diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2014-03-17 14:42:05 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-03-17 15:45:45 +0100 |
commit | acf1298e21abd2fb12d8364c593fbbff345374bc (patch) | |
tree | 30533bedc74cbf5f55ba767c34daa694e746c865 | |
parent | 3f362cdf9304afeed06081cd5abfcaf6aaabe19e (diff) |
Fix crash with lazy binding initialization and compile time calculated dependencies
During lazy binding initialization we may execute bindings where we calculated
dependencies to the context object at compile time. In order to register those
dependencies, the contet object needs to be set in the QQmlContextData.
This patch makes sure to set it before setting up the bindings.
Change-Id: Iacd360140cd9c389487bda82f6a7e6cc3a44c154
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
-rw-r--r-- | src/qml/qml/qqmlcontextwrapper.cpp | 1 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator.cpp | 11 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator_p.h | 2 | ||||
-rw-r--r-- | tests/auto/qml/qqmlecmascript/data/SubObject.qml | 8 | ||||
-rw-r--r-- | tests/auto/qml/qqmlecmascript/data/contextObjectOnLazyBindings.qml | 10 | ||||
-rw-r--r-- | tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 13 |
6 files changed, 40 insertions, 5 deletions
diff --git a/src/qml/qml/qqmlcontextwrapper.cpp b/src/qml/qml/qqmlcontextwrapper.cpp index 07ef86e16f..54bf986b8e 100644 --- a/src/qml/qml/qqmlcontextwrapper.cpp +++ b/src/qml/qml/qqmlcontextwrapper.cpp @@ -387,6 +387,7 @@ void QmlContextWrapper::registerQmlDependencies(ExecutionEngine *engine, const C capture->captureProperty(&qmlContext->idValues[*idObjectDependency].bindings); } + Q_ASSERT(qmlContext->contextObject); const quint32 *contextPropertyDependency = compiledFunction->qmlContextPropertiesDependencyTable(); const int contextPropertyDependencyCount = compiledFunction->nDependingContextProperties; for (int i = 0; i < contextPropertyDependencyCount; ++i) { diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index d0852bbef2..0825b8ec53 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -213,7 +213,7 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI context->importedScripts = sharedState->creationContext->importedScripts; } - QObject *instance = createInstance(objectToCreate, parent); + QObject *instance = createInstance(objectToCreate, parent, /*isContextObject*/true); if (instance) { QQmlData *ddata = QQmlData::get(instance); Q_ASSERT(ddata); @@ -221,8 +221,6 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI ddata->compiledData->release(); ddata->compiledData = compiledData; ddata->compiledData->addref(); - - context->contextObject = instance; } Q_QML_VME_PROFILE(sharedState->profiler, stop()); @@ -1014,7 +1012,7 @@ void QQmlObjectCreator::recordError(const QV4::CompiledData::Location &location, errors << error; } -QObject *QQmlObjectCreator::createInstance(int index, QObject *parent) +QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isContextObject) { ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine)); @@ -1111,6 +1109,11 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent) if (idEntry != objectIndexToId.constEnd()) context->setIdProperty(idEntry.value(), instance); + // Register the context object in the context early on in order for pending binding + // initialization to find it available. + if (isContextObject) + context->contextObject = instance; + QBitArray bindingsToSkip; if (customParser) { QHash<int, QQmlCompiledData::CustomParserData>::ConstIterator entry = compiledData->customParserData.find(index); diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index 9fd52a9f48..379a3b2970 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -96,7 +96,7 @@ private: void init(QQmlContextData *parentContext); - QObject *createInstance(int index, QObject *parent = 0); + QObject *createInstance(int index, QObject *parent = 0, bool isContextObject = false); bool populateInstance(int index, QObject *instance, QObject *bindingTarget, QQmlPropertyData *valueTypeProperty, diff --git a/tests/auto/qml/qqmlecmascript/data/SubObject.qml b/tests/auto/qml/qqmlecmascript/data/SubObject.qml new file mode 100644 index 0000000000..4658edd1db --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/SubObject.qml @@ -0,0 +1,8 @@ +import QtQml 2.0 +QtObject { + property int testValue: -1 + property int subValue; + onSubValueChanged: { + testValue = this.someExpression + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/contextObjectOnLazyBindings.qml b/tests/auto/qml/qqmlecmascript/data/contextObjectOnLazyBindings.qml new file mode 100644 index 0000000000..33b21c74a8 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/contextObjectOnLazyBindings.qml @@ -0,0 +1,10 @@ +import QtQml 2.0 +QtObject { + property SubObject subObject: SubObject { + subValue: 20; + property int someExpression: { + return someValue; + } + } + property int someValue: 42 +} diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index b6c564a6ce..085bf24430 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -320,6 +320,7 @@ private slots: void singletonWithEnum(); void lazyBindingEvaluation(); void varPropertyAccessOnObjectWithInvalidContext(); + void contextObjectOnLazyBindings(); private: // static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter); @@ -7579,6 +7580,18 @@ void tst_qqmlecmascript::varPropertyAccessOnObjectWithInvalidContext() QVERIFY(obj->property("success") == true); } +void tst_qqmlecmascript::contextObjectOnLazyBindings() +{ + QQmlComponent component(&engine, testFileUrl("contextObjectOnLazyBindings.qml")); + QScopedPointer<QObject> obj(component.create()); + if (obj.isNull()) + qDebug() << component.errors().first().toString(); + QVERIFY(!obj.isNull()); + QObject *subObject = qvariant_cast<QObject*>(obj->property("subObject")); + QVERIFY(subObject); + QCOMPARE(subObject->property("testValue").toInt(), int(42)); +} + QTEST_MAIN(tst_qqmlecmascript) #include "tst_qqmlecmascript.moc" |