aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/compiler')
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions.cpp25
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions_p.h17
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: