diff options
author | Lars Knoll <lars.knoll@qt.io> | 2018-04-09 13:39:23 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2018-05-02 14:17:41 +0000 |
commit | d499a995292629d3522f5e77b7c958bacdf5d0ae (patch) | |
tree | 73456336ec5038c6b27477eec017d43dfffc8467 /src | |
parent | 748558b3065881f91765d276ee5637cf7634a298 (diff) |
Make sure we call Codegen::defineFunction with proper arguments
So far, when instantiating QML bindings, the node parameter
could be the same or a child of the body. This will break
badly when we introduce lexical scopeing as that node
could be an AST::Block that opens it's own context.
Changing this requires some smaller adjustments to our autotests,
as error locations will now be slightly different (pointing to
the beginning of the binding, not the beginning of the RHS of
the binding).
Change-Id: I2c536a4fe6d8b549a138cc7967ef034eb2523f3b
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/qml/compiler/qqmlirbuilder.cpp | 28 | ||||
-rw-r--r-- | src/qml/compiler/qqmlirbuilder_p.h | 11 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 2 |
3 files changed, 22 insertions, 19 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index ffad1927df..badf89fe44 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -498,7 +498,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiObjectBinding *node) bool IRBuilder::visit(QQmlJS::AST::UiScriptBinding *node) { - appendBinding(node->qualifiedId, node->statement); + appendBinding(node->qualifiedId, node->statement, node); return false; } @@ -958,7 +958,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node) QQmlJS::AST::Node::accept(node->binding, this); } else if (node->statement) { if (!isRedundantNullInitializerForPropertyDeclaration(_propertyDeclaration, node->statement)) - appendBinding(node->identifierToken, node->identifierToken, _propertyDeclaration->nameIndex, node->statement); + appendBinding(node->identifierToken, node->identifierToken, _propertyDeclaration->nameIndex, node->statement, node); } qSwap(_propertyDeclaration, property); } @@ -972,6 +972,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiSourceElement *node) if (QQmlJS::AST::FunctionDeclaration *funDecl = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration *>(node->sourceElement)) { CompiledFunctionOrExpression *foe = New<CompiledFunctionOrExpression>(); foe->node = funDecl; + foe->parentNode = funDecl; foe->nameIndex = registerString(funDecl->name.toString()); foe->disableAcceleratedLookups = false; const int index = _object->functionsAndExpressions->append(foe); @@ -1045,7 +1046,7 @@ QStringRef IRBuilder::textRefAt(const QQmlJS::AST::SourceLocation &first, const return QStringRef(&sourceCode, first.offset, last.offset + last.length - first.offset); } -void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST::Statement *statement) +void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST::Statement *statement, QQmlJS::AST::Node *parentNode) { QQmlJS::AST::SourceLocation loc = statement->firstSourceLocation(); binding->valueLocation.line = loc.startLine; @@ -1091,6 +1092,7 @@ void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST CompiledFunctionOrExpression *expr = New<CompiledFunctionOrExpression>(); expr->node = statement; + expr->parentNode = parentNode; expr->nameIndex = registerString(QLatin1String("expression for ") + stringAt(binding->propertyNameIndex)); expr->disableAcceleratedLookups = false; @@ -1217,7 +1219,7 @@ void IRBuilder::tryGeneratingTranslationBinding(const QStringRef &base, AST::Arg } } -void IRBuilder::appendBinding(QQmlJS::AST::UiQualifiedId *name, QQmlJS::AST::Statement *value) +void IRBuilder::appendBinding(QQmlJS::AST::UiQualifiedId *name, QQmlJS::AST::Statement *value, QQmlJS::AST::Node *parentNode) { const QQmlJS::AST::SourceLocation qualifiedNameLocation = name->identifierToken; Object *object = nullptr; @@ -1228,7 +1230,7 @@ void IRBuilder::appendBinding(QQmlJS::AST::UiQualifiedId *name, QQmlJS::AST::Sta return; } qSwap(_object, object); - appendBinding(qualifiedNameLocation, name->identifierToken, registerString(name->name.toString()), value); + appendBinding(qualifiedNameLocation, name->identifierToken, registerString(name->name.toString()), value, parentNode); qSwap(_object, object); } @@ -1243,7 +1245,8 @@ void IRBuilder::appendBinding(QQmlJS::AST::UiQualifiedId *name, int objectIndex, qSwap(_object, object); } -void IRBuilder::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, QQmlJS::AST::Statement *value) +void IRBuilder::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, + QQmlJS::AST::Statement *value, QQmlJS::AST::Node *parentNode) { Binding *binding = New<Binding>(); binding->propertyNameIndex = propertyNameIndex; @@ -1251,7 +1254,7 @@ void IRBuilder::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLo binding->location.line = nameLocation.startLine; binding->location.column = nameLocation.startColumn; binding->flags = 0; - setBindingValue(binding, value); + setBindingValue(binding, value, parentNode); QString error = bindingsTarget()->appendBinding(binding, /*isListBinding*/false); if (!error.isEmpty()) { recordError(qualifiedNameLocation, error); @@ -1813,12 +1816,15 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil scan.enterGlobalEnvironment(QV4::Compiler::ContextType::Binding); for (const CompiledFunctionOrExpression &f : functions) { Q_ASSERT(f.node != qmlRoot); + Q_ASSERT(f.parentNode && f.parentNode != qmlRoot); QQmlJS::AST::FunctionDeclaration *function = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration*>(f.node); - if (function) + if (function) { scan.enterQmlFunction(function); - else - scan.enterEnvironment(f.node, QV4::Compiler::ContextType::Binding); + } else { + Q_ASSERT(f.node != f.parentNode); + scan.enterEnvironment(f.parentNode, QV4::Compiler::ContextType::Binding); + } scan(function ? function->body : f.node); scan.leaveEnvironment(); @@ -1863,7 +1869,7 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil } _disableAcceleratedLookups = qmlFunction.disableAcceleratedLookups; - int idx = defineFunction(name, node, + int idx = defineFunction(name, function ? function : qmlFunction.parentNode, function ? function->formals : nullptr, body); runtimeFunctionIndices[i] = idx; diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h index 1c1ffeb8c9..fa93130252 100644 --- a/src/qml/compiler/qqmlirbuilder_p.h +++ b/src/qml/compiler/qqmlirbuilder_p.h @@ -340,12 +340,9 @@ struct Function struct Q_QML_PRIVATE_EXPORT CompiledFunctionOrExpression { CompiledFunctionOrExpression() - {} - CompiledFunctionOrExpression(QQmlJS::AST::Node *n) - : node(n) - {} + QQmlJS::AST::Node *parentNode = nullptr; // FunctionDeclaration, Statement or Expression QQmlJS::AST::Node *node = nullptr; // FunctionDeclaration, Statement or Expression quint32 nameIndex = 0; bool disableAcceleratedLookups = false; @@ -516,12 +513,12 @@ public: QStringRef textRefAt(const QQmlJS::AST::SourceLocation &first, const QQmlJS::AST::SourceLocation &last) const; - void setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST::Statement *statement); + void setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST::Statement *statement, AST::Node *parentNode); void tryGeneratingTranslationBinding(const QStringRef &base, QQmlJS::AST::ArgumentList *args, QV4::CompiledData::Binding *binding); - void appendBinding(QQmlJS::AST::UiQualifiedId *name, QQmlJS::AST::Statement *value); + void appendBinding(QQmlJS::AST::UiQualifiedId *name, QQmlJS::AST::Statement *value, AST::Node *parentNode); void appendBinding(QQmlJS::AST::UiQualifiedId *name, int objectIndex, bool isOnAssignment = false); - void appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, QQmlJS::AST::Statement *value); + void appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, QQmlJS::AST::Statement *value, AST::Node *parentNode); void appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, int objectIndex, bool isListItem = false, bool isOnAssignment = false); bool appendAlias(QQmlJS::AST::UiPublicMember *node); diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index d0b84c7463..d71cd0cdb3 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -2300,7 +2300,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast, // at all, because if the onSignal is a signal handler, the user is actually making it explicit // that the binding is a function, so we should execute that. However, we don't know that during // AOT compilation, so mark the surrounding function as only-returning-a-closure. - _context->returnsClosure = cast<ExpressionStatement *>(ast) && cast<FunctionExpression *>(cast<ExpressionStatement *>(ast)->expression); + _context->returnsClosure = body && body->statement && cast<ExpressionStatement *>(body->statement) && cast<FunctionExpression *>(cast<ExpressionStatement *>(body->statement)->expression); BytecodeGenerator bytecode(_context->line, _module->debugMode); BytecodeGenerator *savedBytecodeGenerator; |