diff options
-rw-r--r-- | src/qml/qml/qqmlengine.cpp | 3 | ||||
-rw-r--r-- | tests/auto/qml/qqmlcontext/data/MyItem.qml | 5 | ||||
-rw-r--r-- | tests/auto/qml/qqmlcontext/data/outerContextObject.qml | 18 | ||||
-rw-r--r-- | tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp | 58 |
4 files changed, 84 insertions, 0 deletions
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index f288646ec7..c400e9239b 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -755,6 +755,9 @@ void QQmlPrivate::qdeclarativeelement_destructor(QObject *o) d->context = nullptr; } + if (d->outerContext && d->outerContext->contextObject == o) + d->outerContext->contextObject = nullptr; + // Mark this object as in the process of deletion to // prevent it resolving in bindings QQmlData::markAsDeleted(o); diff --git a/tests/auto/qml/qqmlcontext/data/MyItem.qml b/tests/auto/qml/qqmlcontext/data/MyItem.qml new file mode 100644 index 0000000000..2ffd984dfa --- /dev/null +++ b/tests/auto/qml/qqmlcontext/data/MyItem.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +QtObject { + Component.onCompleted: 5 + 5 +} diff --git a/tests/auto/qml/qqmlcontext/data/outerContextObject.qml b/tests/auto/qml/qqmlcontext/data/outerContextObject.qml new file mode 100644 index 0000000000..992b760915 --- /dev/null +++ b/tests/auto/qml/qqmlcontext/data/outerContextObject.qml @@ -0,0 +1,18 @@ +import QtQml 2.2 + +QtObject { + id: window + + property Component itemComponent: Qt.createComponent("MyItem.qml") + property MyItem item + + property Timer timer: Timer { + running: true + interval: 10 + repeat: true + onTriggered: { + item = itemComponent.createObject(null, {}); + gc(); + } + } +} diff --git a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp index 990e364c76..5838193a6b 100644 --- a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp +++ b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp @@ -28,6 +28,7 @@ #include <qtest.h> #include <QDebug> +#include <QTimer> #include <QQmlEngine> #include <QQmlContext> #include <QQmlComponent> @@ -68,6 +69,8 @@ private slots: void contextViaClosureAfterDestruction(); void contextLeak(); + void outerContextObject(); + private: QQmlEngine engine; }; @@ -815,6 +818,61 @@ void tst_qqmlcontext::contextLeak() QVERIFY(scriptContext.isNull()); } + +static bool buildObjectList(QQmlContext *ctxt) +{ + static QHash<QObject *, QString> deletedObjects; + QQmlContextData *p = QQmlContextData::get(ctxt); + QObject *object = p->contextObject; + if (object) { + // If the object was actually deleted this is likely to crash in one way or another. + // Either the memory is still intact, then we will probably find the objectName, or it is + // not, then the connect() below is likely to fail. + if (deletedObjects.contains(object) && deletedObjects[object] == object->objectName()) + return false; + QObject::connect(object, &QObject::destroyed, [object]() { + object->setObjectName(QString::number(deletedObjects.size())); + deletedObjects.insert(object, object->objectName()); + }); + } + + QQmlContextData *child = p->childContexts; + while (child) { + if (!buildObjectList(child->asQQmlContext())) + return false; + child = child->nextChild; + } + + return true; +} + +void tst_qqmlcontext::outerContextObject() +{ + QQmlEngine engine; + + QQmlComponent component(&engine, testFileUrl("outerContextObject.qml")); + QVERIFY(component.isReady()); + + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + + int iterations = 0; + QTimer timer; + timer.setInterval(1); + QObject::connect(&timer, &QTimer::timeout, &engine, [&]() { + if (!buildObjectList(engine.rootContext())) { + iterations = 100; + timer.stop(); + QFAIL("Deleted object found as context object"); + } else { + ++iterations; + } + }); + timer.start(); + + QTRY_VERIFY(iterations >= 100); +} + QTEST_MAIN(tst_qqmlcontext) #include "tst_qqmlcontext.moc" |