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);
773 Module *m =
_cg->_module;
775 forEachContext(m, [](Context *inner) {
776 if (inner->usesArgumentsObject != Context::UsesArgumentsObject::Used)
778 if (inner->contextType != ContextType::Block && !inner->isArrowFunction)
780 Context *c = inner->parent;
781 while (c && (c->contextType == ContextType::Block || c->isArrowFunction))
784 c->usesArgumentsObject = Context::UsesArgumentsObject::Used;
785 inner->usesArgumentsObject = Context::UsesArgumentsObject::NotUsed;
789 forEachContext(m, [](Context *inner) {
790 if (!inner->parent || inner->usesArgumentsObject == Context::UsesArgumentsObject::Unknown)
791 inner->usesArgumentsObject = Context::UsesArgumentsObject::NotUsed;
792 if (inner->usesArgumentsObject == Context::UsesArgumentsObject::Used) {
793 QString arguments = QStringLiteral(
"arguments");
794 inner->addLocalVar(arguments, Context::VariableDeclaration, AST::VariableScope::Var);
795 if (!inner->isStrict) {
796 inner->argumentsCanEscape =
true;
797 inner->requiresExecutionContext =
true;
803 forEachContext(m, [](Context *c) {
804 if (c->contextType != ContextType::ESModule)
806 for (
const auto &entry: std::as_const(c->exportEntries)) {
807 auto mIt = c->members.constFind(entry.localName);
808 if (mIt != c->members.constEnd())
809 mIt->canEscape =
true;
814 forEachContext(m, [](Context *inner) {
815 for (
const QString &var : std::as_const(inner->usedVariables)) {
818 Context *current = c;
820 if (current->isWithBlock || current->contextType != ContextType::Block)
823 Q_ASSERT(c != inner);
825 Context::MemberMap::const_iterator it = c->members.constFind(var);
826 if (it != c->members.constEnd()) {
827 if (c->parent || it->isLexicallyScoped()) {
828 it->canEscape =
true;
829 c->requiresExecutionContext =
true;
830 }
else if (c->contextType == ContextType::ESModule) {
833 it->canEscape =
true;
837 if (c->hasArgument(var)) {
838 c->argumentsCanEscape =
true;
839 c->requiresExecutionContext =
true;
845 if (inner->hasDirectEval) {
846 inner->hasDirectEval =
false;
847 inner->innerFunctionAccessesNewTarget =
true;
848 if (!inner->isStrict) {
850 while (c->contextType == ContextType::Block) {
854 c->hasDirectEval =
true;
855 c->innerFunctionAccessesThis =
true;
859 c->allVarsEscape =
true;
863 if (inner->usesThis) {
864 inner->usesThis =
false;
865 bool innerFunctionAccessesThis =
false;
867 while (c->contextType == ContextType::Block || c->isArrowFunction) {
868 innerFunctionAccessesThis |= c->isArrowFunction;
872 if (!inner->isStrict)
874 c->innerFunctionAccessesThis |= innerFunctionAccessesThis;
880 forEachContext(m, [m](Context *c) {
881 if (c->innerFunctionAccessesThis) {
883 c->addLocalVar(QStringLiteral(
"this"), Context::VariableDefinition, VariableScope::Let);
884 c->requiresExecutionContext =
true;
885 auto mIt = c->members.constFind(QStringLiteral(
"this"));
886 Q_ASSERT(mIt != c->members.constEnd());
887 mIt->canEscape =
true;
889 if (c->innerFunctionAccessesNewTarget) {
891 c->addLocalVar(QStringLiteral(
"new.target"), Context::VariableDefinition, VariableScope::Let);
892 c->requiresExecutionContext =
true;
893 auto mIt = c->members.constFind(QStringLiteral(
"new.target"));
894 Q_ASSERT(mIt != c->members.constEnd());
895 mIt->canEscape =
true;
897 if (c->allVarsEscape && c->contextType == ContextType::Block && c->members.isEmpty())
898 c->allVarsEscape =
false;
899 if (c->contextType == ContextType::Global || c->contextType == ContextType::ScriptImportedByQML || (!c->isStrict && c->contextType == ContextType::Eval) || m->debugMode)
900 c->allVarsEscape =
true;
901 if (c->allVarsEscape) {
903 c->requiresExecutionContext =
true;
904 c->argumentsCanEscape =
true;
906 for (
const auto &m : std::as_const(c->members)) {
907 if (m.isLexicallyScoped()) {
908 c->requiresExecutionContext =
true;
914 if (c->contextType == ContextType::Block && c->isCatchBlock) {
915 c->requiresExecutionContext =
true;
916 auto mIt = c->members.constFind(c->caughtVariable);
917 Q_ASSERT(mIt != c->members.constEnd());
918 mIt->canEscape =
true;
920 const QLatin1String exprForOn(
"expression for on");
921 if (c->contextType == ContextType::Binding && c->name.size() > exprForOn.size() &&
922 c->name.startsWith(exprForOn) && c->name.at(exprForOn.size()).isUpper())
925 c->requiresExecutionContext =
true;
926 if (c->allVarsEscape) {
927 for (
const auto &m : std::as_const(c->members))
934 static const bool showEscapingVars = qEnvironmentVariableIsSet(
"QV4_SHOW_ESCAPING_VARS");
935 if (showEscapingVars) {
936 qDebug() <<
"==== escaping variables ====";
937 for (Context *c : std::as_const(m->contextMap)) {
938 qDebug() <<
"Context" << c << c->name <<
"requiresExecutionContext" << c->requiresExecutionContext <<
"isStrict" << c->isStrict;
939 qDebug() <<
" isArrowFunction" << c->isArrowFunction <<
"innerFunctionAccessesThis" << c->innerFunctionAccessesThis;
940 qDebug() <<
" parent:" << c->parent;
941 if (c->argumentsCanEscape)
942 qDebug() <<
" Arguments escape";
943 for (
auto it = c->members.constBegin(); it != c->members.constEnd(); ++it) {
944 qDebug() <<
" " << it.key() << it.value().index << it.value().canEscape <<
"isLexicallyScoped:" << it.value().isLexicallyScoped();