diff options
Diffstat (limited to 'src/qml/compiler')
-rw-r--r-- | src/qml/compiler/qv4compilerscanfunctions.cpp | 25 | ||||
-rw-r--r-- | src/qml/compiler/qv4compilerscanfunctions_p.h | 17 |
2 files changed, 31 insertions, 11 deletions
diff --git a/src/qml/compiler/qv4compilerscanfunctions.cpp b/src/qml/compiler/qv4compilerscanfunctions.cpp index 9dec968a91..ee259b968b 100644 --- a/src/qml/compiler/qv4compilerscanfunctions.cpp +++ b/src/qml/compiler/qv4compilerscanfunctions.cpp @@ -382,8 +382,11 @@ bool ScanFunctions::visit(ExpressionStatement *ast) if (!_allowFuncDecls) _cg->throwSyntaxError(expr->functionToken, QStringLiteral("conditional function or closure declaration")); - if (!enterFunction(expr, /*enterName*/ true)) + if (!enterFunction(expr, expr->identifierToken.length > 0 + ? FunctionNameContext::Inner + : FunctionNameContext::None)) { return false; + } Node::accept(expr->formals, this); Node::accept(expr->body, this); leaveEnvironment(); @@ -399,7 +402,9 @@ bool ScanFunctions::visit(ExpressionStatement *ast) bool ScanFunctions::visit(FunctionExpression *ast) { - return enterFunction(ast, /*enterName*/ false); + return enterFunction(ast, ast->identifierToken.length > 0 + ? FunctionNameContext::Inner + : FunctionNameContext::None); } bool ScanFunctions::visit(ClassExpression *ast) @@ -496,12 +501,12 @@ bool ScanFunctions::visit(ArrayPattern *ast) return false; } -bool ScanFunctions::enterFunction(FunctionExpression *ast, bool enterName) +bool ScanFunctions::enterFunction(FunctionExpression *ast, FunctionNameContext nameContext) { Q_ASSERT(_context); if (_context->isStrict && (ast->name == QLatin1String("eval") || ast->name == QLatin1String("arguments"))) _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Function name may not be eval or arguments in strict mode")); - return enterFunction(ast, ast->name.toString(), ast->formals, ast->body, enterName); + return enterFunction(ast, ast->name.toString(), ast->formals, ast->body, nameContext); } void ScanFunctions::endVisit(FunctionExpression *) @@ -536,7 +541,7 @@ void ScanFunctions::endVisit(PatternProperty *) bool ScanFunctions::visit(FunctionDeclaration *ast) { - return enterFunction(ast, /*enterName*/ true); + return enterFunction(ast, FunctionNameContext::Outer); } void ScanFunctions::endVisit(FunctionDeclaration *) @@ -674,7 +679,9 @@ void ScanFunctions::endVisit(WithStatement *) leaveEnvironment(); } -bool ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParameterList *formals, StatementList *body, bool enterName) +bool ScanFunctions::enterFunction( + Node *ast, const QString &name, FormalParameterList *formals, StatementList *body, + FunctionNameContext nameContext) { Context *outerContext = _context; enterEnvironment(ast, ContextType::Function, name); @@ -685,7 +692,7 @@ bool ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParamete if (outerContext) { outerContext->hasNestedFunctions = true; // The identifier of a function expression cannot be referenced from the enclosing environment. - if (enterName) { + if (nameContext == FunctionNameContext::Outer) { if (!outerContext->addLocalVar(name, Context::FunctionDefinition, VariableScope::Var, expr)) { _cg->throwSyntaxError(ast->firstSourceLocation(), QStringLiteral("Identifier %1 has already been declared").arg(name)); return false; @@ -711,8 +718,10 @@ bool ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParamete } - if (!enterName && (!name.isEmpty() && (!formals || !formals->containsName(name)))) + if (nameContext == FunctionNameContext::Inner + && (!name.isEmpty() && (!formals || !formals->containsName(name)))) { _context->addLocalVar(name, Context::ThisFunctionName, VariableScope::Var); + } _context->formals = formals; if (body && !_context->isStrict) diff --git a/src/qml/compiler/qv4compilerscanfunctions_p.h b/src/qml/compiler/qv4compilerscanfunctions_p.h index 0336398cac..073ee5c2a4 100644 --- a/src/qml/compiler/qv4compilerscanfunctions_p.h +++ b/src/qml/compiler/qv4compilerscanfunctions_p.h @@ -89,9 +89,19 @@ public: void leaveEnvironment(); void enterQmlFunction(QQmlJS::AST::FunctionExpression *ast) - { enterFunction(ast, false); } + { enterFunction(ast, FunctionNameContext::None); } protected: + // Function declarations add their name to the outer scope, but not the + // inner scope. Function expressions add their name to the inner scope, + // unless the name is actually picked from the outer scope rather than + // given after the function token. QML functions don't add their name + // anywhere because the name is already recorded in the QML element. + // This enum is used to control the behavior of enterFunction(). + enum class FunctionNameContext { + None, Inner, Outer + }; + using Visitor::visit; using Visitor::endVisit; @@ -118,7 +128,8 @@ protected: bool visit(QQmlJS::AST::FieldMemberExpression *) override; bool visit(QQmlJS::AST::ArrayPattern *) override; - bool enterFunction(QQmlJS::AST::FunctionExpression *ast, bool enterName); + bool enterFunction(QQmlJS::AST::FunctionExpression *ast, + FunctionNameContext nameContext); void endVisit(QQmlJS::AST::FunctionExpression *) override; @@ -161,7 +172,7 @@ protected: protected: bool enterFunction(QQmlJS::AST::Node *ast, const QString &name, QQmlJS::AST::FormalParameterList *formals, - QQmlJS::AST::StatementList *body, bool enterName); + QQmlJS::AST::StatementList *body, FunctionNameContext nameContext); void calcEscapingVariables(); // fields: |