141 if (declaration->fromClause) {
142 module = declaration->fromClause->moduleSpecifier.toString();
143 if (!module.isEmpty())
144 _context->moduleRequests << module;
147 QString localNameForDefaultExport = QStringLiteral(
"*default*");
149 if (declaration->exportsAll()) {
150 Q_ASSERT_X(declaration->fromClause,
"ScanFunctions",
151 "ExportDeclaration with exportAll always have a fromClause");
152 Compiler::ExportEntry entry;
153 entry.moduleRequest = declaration->fromClause->moduleSpecifier.toString();
154 entry.importName = QStringLiteral(
"*");
155 entry.location = location(declaration->firstSourceLocation());
156 _context->exportEntries << entry;
157 }
else if (declaration->exportClause) {
158 for (ExportsList *it = declaration->exportClause->exportsList; it; it = it->next) {
159 ExportSpecifier *spec = it->exportSpecifier;
160 Compiler::ExportEntry entry;
161 if (module.isEmpty())
162 entry.localName = spec->identifier.toString();
164 entry.importName = spec->identifier.toString();
166 entry.moduleRequest = module;
167 entry.exportName = spec->exportedIdentifier.toString();
168 entry.location = location(it->firstSourceLocation());
170 _context->exportEntries << entry;
172 }
else if (
auto *vstmt = AST::cast<AST::VariableStatement*>(declaration->variableStatementOrDeclaration)) {
173 BoundNames boundNames;
174 for (VariableDeclarationList *it = vstmt->declarations; it; it = it->next) {
175 if (!it->declaration)
177 it->declaration->boundNames(&boundNames);
179 for (
const auto &name: boundNames) {
180 Compiler::ExportEntry entry;
181 entry.localName = name.id;
182 entry.exportName = name.id;
183 entry.location = location(vstmt->firstSourceLocation());
184 _context->exportEntries << entry;
186 }
else if (
auto *classDecl = AST::cast<AST::ClassDeclaration*>(declaration->variableStatementOrDeclaration)) {
187 QString name = classDecl->name.toString();
188 if (!name.isEmpty()) {
189 Compiler::ExportEntry entry;
190 entry.localName = name;
191 entry.exportName = name;
192 entry.location = location(classDecl->firstSourceLocation());
193 _context->exportEntries << entry;
194 if (declaration->exportDefault)
195 localNameForDefaultExport = entry.localName;
197 }
else if (
auto *fdef = declaration->variableStatementOrDeclaration->asFunctionDefinition()) {
198 QString functionName;
203 auto ast = declaration->variableStatementOrDeclaration;
204 if (AST::cast<AST::ExpressionStatement*>(ast) || AST::cast<AST::FunctionDeclaration*>(ast))
205 functionName = fdef->name.toString();
207 if (!functionName.isEmpty()) {
208 Compiler::ExportEntry entry;
209 entry.localName = functionName;
210 entry.exportName = functionName;
211 entry.location = location(fdef->firstSourceLocation());
212 _context->exportEntries << entry;
213 if (declaration->exportDefault)
214 localNameForDefaultExport = entry.localName;
218 if (declaration->exportDefault) {
219 Compiler::ExportEntry entry;
220 entry.localName = localNameForDefaultExport;
221 _context->localNameForDefaultExport = localNameForDefaultExport;
222 entry.exportName = QStringLiteral(
"default");
223 entry.location = location(declaration->firstSourceLocation());
224 _context->exportEntries << entry;
234 if (declaration->fromClause) {
235 module = declaration->fromClause->moduleSpecifier.toString();
236 if (!module.isEmpty())
237 _context->moduleRequests << module;
240 if (!declaration->moduleSpecifier.isEmpty())
241 _context->moduleRequests << declaration->moduleSpecifier.toString();
243 if (ImportClause *import = declaration->importClause) {
244 if (!import->importedDefaultBinding.isEmpty()) {
245 Compiler::ImportEntry entry;
246 entry.moduleRequest = module;
247 entry.importName = QStringLiteral(
"default");
248 entry.localName = import->importedDefaultBinding.toString();
249 entry.location = location(declaration->firstSourceLocation());
250 _context->importEntries << entry;
253 if (import->nameSpaceImport) {
254 Compiler::ImportEntry entry;
255 entry.moduleRequest = module;
256 entry.importName = QStringLiteral(
"*");
257 entry.localName = import->nameSpaceImport->importedBinding.toString();
258 entry.location = location(declaration->firstSourceLocation());
259 _context->importEntries << entry;
262 if (import->namedImports) {
263 for (ImportsList *it = import->namedImports->importsList; it; it = it->next) {
264 Compiler::ImportEntry entry;
265 entry.moduleRequest = module;
266 entry.localName = it->importSpecifier->importedBinding.toString();
267 if (!it->importSpecifier->identifier.isEmpty())
268 entry.importName = it->importSpecifier->identifier.toString();
270 entry.importName = entry.localName;
271 entry.location = location(declaration->firstSourceLocation());
272 _context->importEntries << entry;
297 if (!ast->isVariableDeclaration())
301 ast->boundNames(&names);
303 QQmlJS::SourceLocation declarationLocation = ast->firstSourceLocation();
304 if (_context->lastBlockInitializerLocation.isValid()) {
305 declarationLocation.length = _context->lastBlockInitializerLocation.end()
306 - declarationLocation.offset;
308 declarationLocation.length = ast->lastSourceLocation().end() - declarationLocation.offset;
311 for (
const auto &name : std::as_const(names)) {
312 if (_context->isStrict && (name.id == QLatin1String(
"eval") || name.id == QLatin1String(
"arguments")))
313 _cg->throwSyntaxError(ast->identifierToken, QStringLiteral(
"Variable name may not be eval or arguments in strict mode"));
314 checkName(QStringView(name.id), ast->identifierToken);
315 if (name.id == QLatin1String(
"arguments"))
316 _context->usesArgumentsObject = Context::UsesArgumentsObject::NotUsed;
317 if (ast->scope == VariableScope::Const && !ast->initializer && !ast->isForDeclaration && !ast->destructuringPattern()) {
318 _cg->throwSyntaxError(ast->identifierToken, QStringLiteral(
"Missing initializer in const declaration"));
321 if (!_context->addLocalVar(name.id, ast->initializer ? Context::VariableDefinition : Context::VariableDeclaration, ast->scope,
322 nullptr, declarationLocation)) {
323 _cg->throwSyntaxError(ast->identifierToken, QStringLiteral(
"Identifier %1 has already been declared").arg(name.id));
342 if (FunctionExpression* expr = AST::cast<AST::FunctionExpression*>(ast->expression)) {
343 if (!_allowFuncDecls)
344 _cg->throwSyntaxError(expr->functionToken, QStringLiteral(
"conditional function or closure declaration"));
346 if (!enterFunction(expr, expr->identifierToken.length > 0
347 ? FunctionNameContext::Inner
348 : FunctionNameContext::None)) {
351 Node::accept(expr->formals,
this);
352 Node::accept(expr->body,
this);
356 SourceLocation firstToken = ast->firstSourceLocation();
357 if (QStringView{_sourceCode}.mid(firstToken.offset, firstToken.length) == QLatin1String(
"function")) {
358 _cg->throwSyntaxError(firstToken, QStringLiteral(
"unexpected token"));
596 TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, _context->isStrict ?
false : _allowFuncDecls);
597 enterEnvironment(ast, ContextType::Block, QStringLiteral(
"%CatchBlock"));
598 _context->isCatchBlock =
true;
599 QString caughtVar = ast->patternElement->bindingIdentifier.toString();
600 if (caughtVar.isEmpty())
601 caughtVar = QStringLiteral(
"@caught");
602 _context->addLocalVar(caughtVar, Context::MemberType::VariableDefinition, VariableScope::Let);
604 _context->caughtVariable = caughtVar;
605 if (_context->isStrict &&
606 (caughtVar == QLatin1String(
"eval") || caughtVar == QLatin1String(
"arguments"))) {
607 _cg->throwSyntaxError(ast->identifierToken, QStringLiteral(
"Catch variable name may not be eval or arguments in strict mode"));
610 Node::accept(ast->patternElement,
this);
612 Node::accept(ast->statement->statements,
this);
724 Module *m =
_cg->_module;
726 for (Context *inner : std::as_const(m->contextMap)) {
727 if (inner->usesArgumentsObject != Context::UsesArgumentsObject::Used)
729 if (inner->contextType != ContextType::Block && !inner->isArrowFunction)
731 Context *c = inner->parent;
732 while (c && (c->contextType == ContextType::Block || c->isArrowFunction))
735 c->usesArgumentsObject = Context::UsesArgumentsObject::Used;
736 inner->usesArgumentsObject = Context::UsesArgumentsObject::NotUsed;
738 for (Context *inner : std::as_const(m->contextMap)) {
739 if (!inner->parent || inner->usesArgumentsObject == Context::UsesArgumentsObject::Unknown)
740 inner->usesArgumentsObject = Context::UsesArgumentsObject::NotUsed;
741 if (inner->usesArgumentsObject == Context::UsesArgumentsObject::Used) {
742 QString arguments = QStringLiteral(
"arguments");
743 inner->addLocalVar(arguments, Context::VariableDeclaration, AST::VariableScope::Var);
744 if (!inner->isStrict) {
745 inner->argumentsCanEscape =
true;
746 inner->requiresExecutionContext =
true;
751 for (Context *c : std::as_const(m->contextMap)) {
752 if (c->contextType != ContextType::ESModule)
754 for (
const auto &entry: std::as_const(c->exportEntries)) {
755 auto mIt = c->members.constFind(entry.localName);
756 if (mIt != c->members.constEnd())
757 mIt->canEscape =
true;
762 for (Context *inner : std::as_const(m->contextMap)) {
763 for (
const QString &var : std::as_const(inner->usedVariables)) {
766 Context *current = c;
768 if (current->isWithBlock || current->contextType != ContextType::Block)
771 Q_ASSERT(c != inner);
773 Context::MemberMap::const_iterator it = c->members.constFind(var);
774 if (it != c->members.constEnd()) {
775 if (c->parent || it->isLexicallyScoped()) {
776 it->canEscape =
true;
777 c->requiresExecutionContext =
true;
778 }
else if (c->contextType == ContextType::ESModule) {
781 it->canEscape =
true;
785 if (c->hasArgument(var)) {
786 c->argumentsCanEscape =
true;
787 c->requiresExecutionContext =
true;
793 if (inner->hasDirectEval) {
794 inner->hasDirectEval =
false;
795 inner->innerFunctionAccessesNewTarget =
true;
796 if (!inner->isStrict) {
798 while (c->contextType == ContextType::Block) {
802 c->hasDirectEval =
true;
803 c->innerFunctionAccessesThis =
true;
807 c->allVarsEscape =
true;
811 if (inner->usesThis) {
812 inner->usesThis =
false;
813 bool innerFunctionAccessesThis =
false;
815 while (c->contextType == ContextType::Block || c->isArrowFunction) {
816 innerFunctionAccessesThis |= c->isArrowFunction;
820 if (!inner->isStrict)
822 c->innerFunctionAccessesThis |= innerFunctionAccessesThis;
825 for (Context *c : std::as_const(m->contextMap)) {
826 if (c->innerFunctionAccessesThis) {
828 c->addLocalVar(QStringLiteral(
"this"), Context::VariableDefinition, VariableScope::Let);
829 c->requiresExecutionContext =
true;
830 auto mIt = c->members.constFind(QStringLiteral(
"this"));
831 Q_ASSERT(mIt != c->members.constEnd());
832 mIt->canEscape =
true;
834 if (c->innerFunctionAccessesNewTarget) {
836 c->addLocalVar(QStringLiteral(
"new.target"), Context::VariableDefinition, VariableScope::Let);
837 c->requiresExecutionContext =
true;
838 auto mIt = c->members.constFind(QStringLiteral(
"new.target"));
839 Q_ASSERT(mIt != c->members.constEnd());
840 mIt->canEscape =
true;
842 if (c->allVarsEscape && c->contextType == ContextType::Block && c->members.isEmpty())
843 c->allVarsEscape =
false;
844 if (c->contextType == ContextType::Global || c->contextType == ContextType::ScriptImportedByQML || (!c->isStrict && c->contextType == ContextType::Eval) || m->debugMode)
845 c->allVarsEscape =
true;
846 if (c->allVarsEscape) {
848 c->requiresExecutionContext =
true;
849 c->argumentsCanEscape =
true;
851 for (
const auto &m : std::as_const(c->members)) {
852 if (m.isLexicallyScoped()) {
853 c->requiresExecutionContext =
true;
859 if (c->contextType == ContextType::Block && c->isCatchBlock) {
860 c->requiresExecutionContext =
true;
861 auto mIt = c->members.constFind(c->caughtVariable);
862 Q_ASSERT(mIt != c->members.constEnd());
863 mIt->canEscape =
true;
865 const QLatin1String exprForOn(
"expression for on");
866 if (c->contextType == ContextType::Binding && c->name.size() > exprForOn.size() &&
867 c->name.startsWith(exprForOn) && c->name.at(exprForOn.size()).isUpper())
870 c->requiresExecutionContext =
true;
871 if (c->allVarsEscape) {
872 for (
const auto &m : std::as_const(c->members))
877 static const bool showEscapingVars = qEnvironmentVariableIsSet(
"QV4_SHOW_ESCAPING_VARS");
878 if (showEscapingVars) {
879 qDebug() <<
"==== escaping variables ====";
880 for (Context *c : std::as_const(m->contextMap)) {
881 qDebug() <<
"Context" << c << c->name <<
"requiresExecutionContext" << c->requiresExecutionContext <<
"isStrict" << c->isStrict;
882 qDebug() <<
" isArrowFunction" << c->isArrowFunction <<
"innerFunctionAccessesThis" << c->innerFunctionAccessesThis;
883 qDebug() <<
" parent:" << c->parent;
884 if (c->argumentsCanEscape)
885 qDebug() <<
" Arguments escape";
886 for (
auto it = c->members.constBegin(); it != c->members.constEnd(); ++it) {
887 qDebug() <<
" " << it.key() << it.value().index << it.value().canEscape <<
"isLexicallyScoped:" << it.value().isLexicallyScoped();