diff options
author | Lars Knoll <lars.knoll@qt.io> | 2018-09-04 14:49:49 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2018-09-07 10:31:45 +0000 |
commit | ee3d935a8b45576a237c74fd453fb0810f30f574 (patch) | |
tree | 4de5e0829d6159f9020f8abd549f59fce94a6236 /src/qml/compiler/qv4compilerscanfunctions.cpp | |
parent | d71df8db162ff8b4d6bd1833c088024b8870b02c (diff) |
Fix new.target access from eval()
Change-Id: I1855eb303225d1784b019f8eebab0ad8bf2cdf5e
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/compiler/qv4compilerscanfunctions.cpp')
-rw-r--r-- | src/qml/compiler/qv4compilerscanfunctions.cpp | 45 |
1 files changed, 40 insertions, 5 deletions
diff --git a/src/qml/compiler/qv4compilerscanfunctions.cpp b/src/qml/compiler/qv4compilerscanfunctions.cpp index dafb1c360d..4e18af2227 100644 --- a/src/qml/compiler/qv4compilerscanfunctions.cpp +++ b/src/qml/compiler/qv4compilerscanfunctions.cpp @@ -417,14 +417,42 @@ bool ScanFunctions::visit(TemplateLiteral *ast) bool ScanFunctions::visit(SuperLiteral *) { Context *c = _context; - while (c && (c->contextType != ContextType::Function || c->isArrowFunction)) + bool needContext = false; + while (c && (c->contextType == ContextType::Block || c->isArrowFunction)) { + needContext |= c->isArrowFunction; c = c->parent; + } - if (c) - c->requiresExecutionContext = true; + c->requiresExecutionContext |= needContext; return false; } + +bool ScanFunctions::visit(FieldMemberExpression *ast) +{ + if (AST::IdentifierExpression *id = AST::cast<AST::IdentifierExpression *>(ast->base)) { + if (id->name == QLatin1String("new")) { + // new.target + if (ast->name != QLatin1String("target")) { + _cg->throwSyntaxError(ast->identifierToken, QLatin1String("Expected 'target' after 'new.'.")); + return false; + } + Context *c = _context; + bool needContext = false; + while (c->contextType == ContextType::Block || c->isArrowFunction) { + needContext |= c->isArrowFunction; + c = c->parent; + } + c->requiresExecutionContext |= needContext; + c->innerFunctionAccessesNewTarget |= needContext; + + return false; + } + } + + return true; +} + bool ScanFunctions::enterFunction(FunctionExpression *ast, bool enterName) { if (_context->isStrict && (ast->name == QLatin1String("eval") || ast->name == QLatin1String("arguments"))) @@ -735,6 +763,7 @@ void ScanFunctions::calcEscapingVariables() } if (inner->hasDirectEval) { inner->hasDirectEval = false; + inner->innerFunctionAccessesNewTarget = true; if (!inner->isStrict) { Context *c = inner; while (c->contextType == ContextType::Block) { @@ -742,8 +771,7 @@ void ScanFunctions::calcEscapingVariables() } Q_ASSERT(c); c->hasDirectEval = true; - if (!c->isStrict) - c->innerFunctionAccessesThis = true; + c->innerFunctionAccessesThis = true; } Context *c = inner; while (c) { @@ -773,6 +801,13 @@ void ScanFunctions::calcEscapingVariables() auto m = c->members.find(QStringLiteral("this")); m->canEscape = true; } + if (c->innerFunctionAccessesNewTarget) { + // add an escaping 'new.target' variable + c->addLocalVar(QStringLiteral("new.target"), Context::VariableDefinition, VariableScope::Let); + c->requiresExecutionContext = true; + auto m = c->members.find(QStringLiteral("new.target")); + m->canEscape = true; + } if (c->allVarsEscape && c->contextType == ContextType::Block && c->members.isEmpty()) c->allVarsEscape = false; if (c->contextType == ContextType::Global || (!c->isStrict && c->contextType == ContextType::Eval) || m->debugMode) |