142 if (declaration->fromClause) {
143 module = declaration->fromClause->moduleSpecifier.toString();
144 if (!module.isEmpty())
145 _context->moduleRequests << module;
148 QString localNameForDefaultExport = QStringLiteral(
"*default*");
150 if (declaration->exportsAll()) {
151 Q_ASSERT_X(declaration->fromClause,
"ScanFunctions",
152 "ExportDeclaration with exportAll always have a fromClause");
153 Compiler::ExportEntry entry;
154 entry.moduleRequest = declaration->fromClause->moduleSpecifier.toString();
155 entry.importName = QStringLiteral(
"*");
156 entry.location = location(declaration->firstSourceLocation());
157 _context->exportEntries << entry;
158 }
else if (declaration->exportClause) {
159 for (ExportsList *it = declaration->exportClause->exportsList; it; it = it->next) {
160 ExportSpecifier *spec = it->exportSpecifier;
161 Compiler::ExportEntry entry;
162 if (module.isEmpty())
163 entry.localName = spec->identifier.toString();
165 entry.importName = spec->identifier.toString();
167 entry.moduleRequest = module;
168 entry.exportName = spec->exportedIdentifier.toString();
169 entry.location = location(it->firstSourceLocation());
171 _context->exportEntries << entry;
173 }
else if (
auto *vstmt = AST::cast<AST::VariableStatement*>(declaration->variableStatementOrDeclaration)) {
174 BoundNames boundNames;
175 for (VariableDeclarationList *it = vstmt->declarations; it; it = it->next) {
176 if (!it->declaration)
178 it->declaration->boundNames(&boundNames);
180 for (
const auto &name: boundNames) {
181 Compiler::ExportEntry entry;
182 entry.localName = name.id;
183 entry.exportName = name.id;
184 entry.location = location(vstmt->firstSourceLocation());
185 _context->exportEntries << entry;
187 }
else if (
auto *classDecl = AST::cast<AST::ClassDeclaration*>(declaration->variableStatementOrDeclaration)) {
188 QString name = classDecl->name.toString();
189 if (!name.isEmpty()) {
190 Compiler::ExportEntry entry;
191 entry.localName = name;
192 entry.exportName = name;
193 entry.location = location(classDecl->firstSourceLocation());
194 _context->exportEntries << entry;
195 if (declaration->exportDefault)
196 localNameForDefaultExport = entry.localName;
198 }
else if (
auto *fdef = declaration->variableStatementOrDeclaration->asFunctionDefinition()) {
199 QString functionName;
204 auto ast = declaration->variableStatementOrDeclaration;
205 if (AST::cast<AST::ExpressionStatement*>(ast) || AST::cast<AST::FunctionDeclaration*>(ast))
206 functionName = fdef->name.toString();
208 if (!functionName.isEmpty()) {
209 Compiler::ExportEntry entry;
210 entry.localName = functionName;
211 entry.exportName = functionName;
212 entry.location = location(fdef->firstSourceLocation());
213 _context->exportEntries << entry;
214 if (declaration->exportDefault)
215 localNameForDefaultExport = entry.localName;
219 if (declaration->exportDefault) {
220 Compiler::ExportEntry entry;
221 entry.localName = localNameForDefaultExport;
222 _context->localNameForDefaultExport = localNameForDefaultExport;
223 entry.exportName = QStringLiteral(
"default");
224 entry.location = location(declaration->firstSourceLocation());
225 _context->exportEntries << entry;
235 if (declaration->fromClause) {
236 module = declaration->fromClause->moduleSpecifier.toString();
237 if (!module.isEmpty())
238 _context->moduleRequests << module;
241 if (!declaration->moduleSpecifier.isEmpty())
242 _context->moduleRequests << declaration->moduleSpecifier.toString();
244 if (ImportClause *import = declaration->importClause) {
245 if (!import->importedDefaultBinding.isEmpty()) {
246 Compiler::ImportEntry entry;
247 entry.moduleRequest = module;
248 entry.importName = QStringLiteral(
"default");
249 entry.localName = import->importedDefaultBinding.toString();
250 entry.location = location(declaration->firstSourceLocation());
251 _context->importEntries << entry;
254 if (import->nameSpaceImport) {
255 Compiler::ImportEntry entry;
256 entry.moduleRequest = module;
257 entry.importName = QStringLiteral(
"*");
258 entry.localName = import->nameSpaceImport->importedBinding.toString();
259 entry.location = location(declaration->firstSourceLocation());
260 _context->importEntries << entry;
263 if (import->namedImports) {
264 for (ImportsList *it = import->namedImports->importsList; it; it = it->next) {
265 Compiler::ImportEntry entry;
266 entry.moduleRequest = module;
267 entry.localName = it->importSpecifier->importedBinding.toString();
268 if (!it->importSpecifier->identifier.isEmpty())
269 entry.importName = it->importSpecifier->identifier.toString();
271 entry.importName = entry.localName;
272 entry.location = location(declaration->firstSourceLocation());
273 _context->importEntries << entry;
298 if (!ast->isVariableDeclaration())
302 ast->boundNames(&names);
304 QQmlJS::SourceLocation declarationLocation = ast->firstSourceLocation();
305 if (_context->lastBlockInitializerLocation.isValid()) {
306 declarationLocation.length = _context->lastBlockInitializerLocation.end()
307 - declarationLocation.offset;
309 declarationLocation.length = ast->lastSourceLocation().end() - declarationLocation.offset;
312 for (
const auto &name : std::as_const(names)) {
313 if (_context->isStrict && (name.id == QLatin1String(
"eval") || name.id == QLatin1String(
"arguments")))
314 _cg->throwSyntaxError(ast->identifierToken, QStringLiteral(
"Variable name may not be eval or arguments in strict mode"));
315 checkName(QStringView(name.id), ast->identifierToken);
316 if (name.id == QLatin1String(
"arguments"))
317 _context->usesArgumentsObject = Context::UsesArgumentsObject::NotUsed;
318 if (ast->scope == VariableScope::Const && !ast->initializer && !ast->isForDeclaration && !ast->destructuringPattern()) {
319 _cg->throwSyntaxError(ast->identifierToken, QStringLiteral(
"Missing initializer in const declaration"));
322 if (!_context->addLocalVar(name.id, ast->initializer ? Context::VariableDefinition : Context::VariableDeclaration, ast->scope,
323 nullptr, declarationLocation)) {
324 _cg->throwSyntaxError(ast->identifierToken, QStringLiteral(
"Identifier %1 has already been declared").arg(name.id));
597 TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, _context->isStrict ?
false : _allowFuncDecls);
598 enterEnvironment(ast, ContextType::Block, QStringLiteral(
"%CatchBlock"));
599 _context->isCatchBlock =
true;
600 QString caughtVar = ast->patternElement->bindingIdentifier.toString();
601 if (caughtVar.isEmpty())
602 caughtVar = QStringLiteral(
"@caught");
603 _context->addLocalVar(caughtVar, Context::MemberType::VariableDefinition, VariableScope::Let);
605 _context->caughtVariable = caughtVar;
606 if (_context->isStrict &&
607 (caughtVar == QLatin1String(
"eval") || caughtVar == QLatin1String(
"arguments"))) {
608 _cg->throwSyntaxError(ast->identifierToken, QStringLiteral(
"Catch variable name may not be eval or arguments in strict mode"));
611 Node::accept(ast->patternElement,
this);
613 Node::accept(ast->statement->statements,
this);
808 Module *m =
_cg->_module;
810 forEachContext(m, [](Context *inner) {
811 if (inner->usesArgumentsObject != Context::UsesArgumentsObject::Used)
813 if (inner->contextType != ContextType::Block && !inner->isArrowFunction)
815 Context *c = inner->parent;
816 while (c && (c->contextType == ContextType::Block || c->isArrowFunction))
819 c->usesArgumentsObject = Context::UsesArgumentsObject::Used;
820 inner->usesArgumentsObject = Context::UsesArgumentsObject::NotUsed;
824 forEachContext(m, [](Context *inner) {
825 if (!inner->parent || inner->usesArgumentsObject == Context::UsesArgumentsObject::Unknown)
826 inner->usesArgumentsObject = Context::UsesArgumentsObject::NotUsed;
827 if (inner->usesArgumentsObject == Context::UsesArgumentsObject::Used) {
828 QString arguments = QStringLiteral(
"arguments");
829 inner->addLocalVar(arguments, Context::VariableDeclaration, AST::VariableScope::Var);
830 if (!inner->isStrict) {
831 inner->argumentsCanEscape =
true;
832 inner->requiresExecutionContext =
true;
838 forEachContext(m, [](Context *c) {
839 if (c->contextType != ContextType::ESModule)
841 for (
const auto &entry: std::as_const(c->exportEntries)) {
842 auto mIt = c->members.constFind(entry.localName);
843 if (mIt != c->members.constEnd())
844 mIt->canEscape =
true;
849 forEachContext(m, [](Context *inner) {
850 for (
const QString &var : std::as_const(inner->usedVariables)) {
853 Context *current = c;
855 if (current->isWithBlock || current->contextType != ContextType::Block)
858 Q_ASSERT(c != inner);
860 Context::MemberMap::const_iterator it = c->members.constFind(var);
861 if (it != c->members.constEnd()) {
862 if (c->parent || it->isLexicallyScoped()) {
863 it->canEscape =
true;
864 c->requiresExecutionContext =
true;
865 }
else if (c->contextType == ContextType::ESModule) {
868 it->canEscape =
true;
872 if (c->hasArgument(var)) {
873 c->argumentsCanEscape =
true;
874 c->requiresExecutionContext =
true;
880 if (inner->hasDirectEval) {
881 inner->hasDirectEval =
false;
882 inner->innerFunctionAccessesNewTarget =
true;
883 if (!inner->isStrict) {
885 while (c->contextType == ContextType::Block) {
889 c->hasDirectEval =
true;
890 c->innerFunctionAccessesThis =
true;
894 c->allVarsEscape =
true;
898 if (inner->usesThis) {
899 inner->usesThis =
false;
900 bool innerFunctionAccessesThis =
false;
902 while (c->contextType == ContextType::Block || c->isArrowFunction) {
903 innerFunctionAccessesThis |= c->isArrowFunction;
907 if (!inner->isStrict)
909 c->innerFunctionAccessesThis |= innerFunctionAccessesThis;
915 forEachContext(m, [m](Context *c) {
916 if (c->innerFunctionAccessesThis) {
918 c->addLocalVar(QStringLiteral(
"this"), Context::VariableDefinition, VariableScope::Let);
919 c->requiresExecutionContext =
true;
920 auto mIt = c->members.constFind(QStringLiteral(
"this"));
921 Q_ASSERT(mIt != c->members.constEnd());
922 mIt->canEscape =
true;
924 if (c->innerFunctionAccessesNewTarget) {
926 c->addLocalVar(QStringLiteral(
"new.target"), Context::VariableDefinition, VariableScope::Let);
927 c->requiresExecutionContext =
true;
928 auto mIt = c->members.constFind(QStringLiteral(
"new.target"));
929 Q_ASSERT(mIt != c->members.constEnd());
930 mIt->canEscape =
true;
932 if (c->allVarsEscape && c->contextType == ContextType::Block && c->members.isEmpty())
933 c->allVarsEscape =
false;
934 if (c->contextType == ContextType::Global || c->contextType == ContextType::ScriptImportedByQML || (!c->isStrict && c->contextType == ContextType::Eval) || m->debugMode)
935 c->allVarsEscape =
true;
936 if (c->allVarsEscape) {
938 c->requiresExecutionContext =
true;
939 c->argumentsCanEscape =
true;
941 for (
const auto &m : std::as_const(c->members)) {
942 if (m.isLexicallyScoped()) {
943 c->requiresExecutionContext =
true;
949 if (c->contextType == ContextType::Block && c->isCatchBlock) {
950 c->requiresExecutionContext =
true;
951 auto mIt = c->members.constFind(c->caughtVariable);
952 Q_ASSERT(mIt != c->members.constEnd());
953 mIt->canEscape =
true;
955 const QLatin1String exprForOn(
"expression for on");
956 if (c->contextType == ContextType::Binding && c->name.size() > exprForOn.size() &&
957 c->name.startsWith(exprForOn) && c->name.at(exprForOn.size()).isUpper())
960 c->requiresExecutionContext =
true;
961 if (c->allVarsEscape) {
962 for (
const auto &m : std::as_const(c->members))
969 static const bool showEscapingVars = qEnvironmentVariableIsSet(
"QV4_SHOW_ESCAPING_VARS");
970 if (showEscapingVars) {
971 qDebug() <<
"==== escaping variables ====";
972 for (Context *c : std::as_const(m->contextMap)) {
973 qDebug() <<
"Context" << c << c->name <<
"requiresExecutionContext" << c->requiresExecutionContext <<
"isStrict" << c->isStrict;
974 qDebug() <<
" isArrowFunction" << c->isArrowFunction <<
"innerFunctionAccessesThis" << c->innerFunctionAccessesThis;
975 qDebug() <<
" parent:" << c->parent;
976 if (c->argumentsCanEscape)
977 qDebug() <<
" Arguments escape";
978 for (
auto it = c->members.constBegin(); it != c->members.constEnd(); ++it) {
979 qDebug() <<
" " << it.key() << it.value().index << it.value().canEscape <<
"isLexicallyScoped:" << it.value().isLexicallyScoped();