diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2013-12-10 15:25:22 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-12-10 15:46:09 +0100 |
commit | 29b6d2e45c7434fccf2e6878630e62d5dcce38db (patch) | |
tree | d2d0ad7639c9863c00cdd8558d9663bea813c3f3 /src/qml/compiler | |
parent | fb72bb3cf27d1f94760709aaab82e3524ae936f4 (diff) |
Fix broken Maroon game / regression in PropertyChanges {} element
Commit 0aadcf8077840068eb182269e9ed9c31ad12f45e that pre-compiles the
expressions in PropertyChanges {} introduced a regression in where the
evaluation context was incorrect and thus bindings would not be able to
access the correct properties. For example
PropertyChanges {
target: someObject
y: height / 2
}
Here height should be looked up in the context of "someObject", not of the
PropertyChanges element.
This patch introduces an auto-test that verifies that the lookup context is
correct and fixes the bug by disabling accelerated compile time property
lookups for binding expressions that are requested from a custom parser.
Change-Id: I5cb607d07211b453ddfc9928ccbf5f9ecec85575
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/qml/compiler')
-rw-r--r-- | src/qml/compiler/qqmlcodegenerator.cpp | 28 | ||||
-rw-r--r-- | src/qml/compiler/qqmlcodegenerator_p.h | 21 |
2 files changed, 36 insertions, 13 deletions
diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp index 1b96bad94f..8809221abe 100644 --- a/src/qml/compiler/qqmlcodegenerator.cpp +++ b/src/qml/compiler/qqmlcodegenerator.cpp @@ -281,7 +281,7 @@ bool QQmlCodeGenerator::sanityCheckFunctionNames() { QSet<QString> functionNames; for (Function *f = _object->functions->first; f; f = f->next) { - AST::FunctionDeclaration *function = AST::cast<AST::FunctionDeclaration*>(_functions.at(f->index)); + AST::FunctionDeclaration *function = AST::cast<AST::FunctionDeclaration*>(_functions.at(f->index).node); Q_ASSERT(function); QString name = function->name.toString(); if (functionNames.contains(name)) @@ -1210,6 +1210,7 @@ JSCodeGen::JSCodeGen(const QString &fileName, const QString &sourceCode, V4IR::M , jsEngine(jsEngine) , qmlRoot(qmlRoot) , imports(imports) + , _disableAcceleratedLookups(false) , _contextObject(0) , _scopeObject(0) , _contextObjectTemp(-1) @@ -1234,23 +1235,23 @@ void JSCodeGen::beginObjectScope(QQmlPropertyCache *scopeObject) _scopeObject = scopeObject; } -QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<AST::Node*> &functions, const QHash<int, QString> &functionNames) +QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<CompiledFunctionOrExpression> &functions) { QVector<int> runtimeFunctionIndices(functions.size()); ScanFunctions scan(this, sourceCode, GlobalCode); scan.enterEnvironment(0, QmlBinding); scan.enterQmlScope(qmlRoot, QStringLiteral("context scope")); - foreach (AST::Node *node, functions) { - Q_ASSERT(node != qmlRoot); - AST::FunctionDeclaration *function = AST::cast<AST::FunctionDeclaration*>(node); + foreach (const CompiledFunctionOrExpression &f, functions) { + Q_ASSERT(f.node != qmlRoot); + AST::FunctionDeclaration *function = AST::cast<AST::FunctionDeclaration*>(f.node); if (function) scan.enterQmlFunction(function); else - scan.enterEnvironment(node, QmlBinding); + scan.enterEnvironment(f.node, QmlBinding); - scan(function ? function->body : node); + scan(function ? function->body : f.node); scan.leaveEnvironment(); } scan.leaveEnvironment(); @@ -1260,7 +1261,8 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<AST::N _function = _module->functions.at(defineFunction(QStringLiteral("context scope"), qmlRoot, 0, 0)); for (int i = 0; i < functions.count(); ++i) { - AST::Node *node = functions.at(i); + const CompiledFunctionOrExpression &qmlFunction = functions.at(i); + AST::Node *node = qmlFunction.node; Q_ASSERT(node != qmlRoot); AST::FunctionDeclaration *function = AST::cast<AST::FunctionDeclaration*>(node); @@ -1268,8 +1270,10 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<AST::N QString name; if (function) name = function->name.toString(); + else if (!qmlFunction.name.isEmpty()) + name = qmlFunction.name; else - name = functionNames.value(i, QStringLiteral("%qml-expression-entry")); + name = QStringLiteral("%qml-expression-entry"); AST::SourceElements *body; if (function) @@ -1289,6 +1293,7 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<AST::N body = body->finish(); } + _disableAcceleratedLookups = qmlFunction.disableAcceleratedLookups; int idx = defineFunction(name, node, function ? function->formals : 0, body); @@ -1530,6 +1535,9 @@ void JSCodeGen::beginFunctionBodyHook() V4IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int col) { + if (_disableAcceleratedLookups) + return 0; + Q_UNUSED(line) Q_UNUSED(col) // Implement QML lookup semantics in the current file context. @@ -1746,7 +1754,7 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio if (paramList) paramList = paramList->finish(); - AST::Statement *statement = static_cast<AST::Statement*>(parsedQML->functions[binding->value.compiledScriptIndex]); + AST::Statement *statement = static_cast<AST::Statement*>(parsedQML->functions[binding->value.compiledScriptIndex].node); AST::SourceElement *sourceElement = new (pool) AST::StatementSourceElement(statement); AST::SourceElements *elements = new (pool) AST::SourceElements(sourceElement); elements = elements->finish(); diff --git a/src/qml/compiler/qqmlcodegenerator_p.h b/src/qml/compiler/qqmlcodegenerator_p.h index 348ef0a2cf..0a0e4f2d5b 100644 --- a/src/qml/compiler/qqmlcodegenerator_p.h +++ b/src/qml/compiler/qqmlcodegenerator_p.h @@ -166,6 +166,20 @@ struct Pragma QV4::CompiledData::Location location; }; +struct CompiledFunctionOrExpression +{ + CompiledFunctionOrExpression() + : disableAcceleratedLookups(false) + {} + CompiledFunctionOrExpression(AST::Node *n) + : node(n) + , disableAcceleratedLookups(false) + {} + AST::Node *node; // FunctionDeclaration, Statement or Expression + QString name; + bool disableAcceleratedLookups; +}; + struct ParsedQML { ParsedQML(bool debugMode) @@ -180,7 +194,7 @@ struct ParsedQML AST::UiProgram *program; int indexOfRootObject; QList<QmlObject*> objects; - QList<AST::Node*> functions; // FunctionDeclaration, Statement or Expression + QList<CompiledFunctionOrExpression> functions; QV4::Compiler::JSUnitGenerator jsGenerator; QV4::CompiledData::TypeReferenceMap typeReferences; @@ -269,7 +283,7 @@ public: QList<QV4::CompiledData::Import*> _imports; QList<Pragma*> _pragmas; QList<QmlObject*> _objects; - QList<AST::Node*> _functions; + QList<CompiledFunctionOrExpression> _functions; QV4::CompiledData::TypeReferenceMap _typeReferences; @@ -362,7 +376,7 @@ struct Q_QML_EXPORT JSCodeGen : public QQmlJS::Codegen void beginObjectScope(QQmlPropertyCache *scopeObject); // Returns mapping from input functions to index in V4IR::Module::functions / compiledData->runtimeFunctions - QVector<int> generateJSCodeForFunctionsAndBindings(const QList<AST::Node*> &functions, const QHash<int, QString> &functionNames); + QVector<int> generateJSCodeForFunctionsAndBindings(const QList<CompiledFunctionOrExpression> &functions); protected: virtual void beginFunctionBodyHook(); @@ -376,6 +390,7 @@ private: AST::UiProgram *qmlRoot; QQmlTypeNameCache *imports; + bool _disableAcceleratedLookups; ObjectIdMapping _idObjects; QQmlPropertyCache *_contextObject; QQmlPropertyCache *_scopeObject; |