aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler/qv4compilerscanfunctions.cpp
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-09-04 14:49:49 +0200
committerLars Knoll <lars.knoll@qt.io>2018-09-07 10:31:45 +0000
commitee3d935a8b45576a237c74fd453fb0810f30f574 (patch)
tree4de5e0829d6159f9020f8abd549f59fce94a6236 /src/qml/compiler/qv4compilerscanfunctions.cpp
parentd71df8db162ff8b4d6bd1833c088024b8870b02c (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.cpp45
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)