diff options
author | Thomas McGuire <thomas.mcguire.qnx@kdab.com> | 2012-08-15 09:50:47 +0200 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-09-14 13:33:45 +0200 |
commit | ecc432a5b7ae269220f86c6f0b3dd364f8643191 (patch) | |
tree | 66c9f0ecc280d9b71e677266f533ce9edafa0f94 /tests/auto/declarative | |
parent | 3414828ccc91da0d94f3b160f29766b9273357ad (diff) |
Delete JS-owned QML objects right away in the engine dtor.
This prevents memory leaks when the engine is destroyed after exec()
has already finished. In most cases this happens during application
shutdown, at which point the event loop is never entered again.
Task-number: QTBUG-20377
Change-Id: I65564ed3e56314d656d92fd66f11ae67d4eb932b
Reviewed-by: Jędrzej Nowacki <jedrzej.nowacki@nokia.com>
Reviewed-by: Lars Knoll <lars.knoll@nokia.com>
Diffstat (limited to 'tests/auto/declarative')
3 files changed, 62 insertions, 1 deletions
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/jsOwnedObjectsDeletedOnEngineDestroy.qml b/tests/auto/declarative/qdeclarativeecmascript/data/jsOwnedObjectsDeletedOnEngineDestroy.qml new file mode 100644 index 0000000000..da1b682d1e --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/jsOwnedObjectsDeletedOnEngineDestroy.qml @@ -0,0 +1,6 @@ +import QtQuick 1.0 + +Item { + property variant jsOwnedObject1: deleteObject.object1() + property variant jsOwnedObject2: deleteObject.object2 +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/testtypes.h b/tests/auto/declarative/qdeclarativeecmascript/testtypes.h index 19505e1458..3d0d37fba9 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/testtypes.h +++ b/tests/auto/declarative/qdeclarativeecmascript/testtypes.h @@ -903,6 +903,27 @@ protected: qreal m_p4; }; +class MyDeleteObject : public QObject +{ + Q_OBJECT + Q_PROPERTY(QObject *object2 READ object2 NOTIFY object2Changed) + +public: + MyDeleteObject() : m_object1(0), m_object2(0) {} + + Q_INVOKABLE QObject *object1() const { return m_object1; } + Q_INVOKABLE QObject *object2() const { return m_object2; } + void setObject1(QObject *object) { m_object1 = object; } + void setObject2(QObject *object) { m_object2 = object; emit object2Changed(); } + +signals: + void object2Changed(); + +private: + QObject *m_object1; + QObject *m_object2; +}; + QML_DECLARE_TYPE(MyRevisionedBaseClassRegistered) QML_DECLARE_TYPE(MyRevisionedBaseClassUnregistered) QML_DECLARE_TYPE(MyRevisionedClass) diff --git a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp index 1c54494325..188cf1b52a 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp +++ b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp @@ -48,6 +48,7 @@ #include <QtDeclarative/private/qdeclarativeguard_p.h> #include <QtCore/qdir.h> #include <QtCore/qnumeric.h> +#include <QtTest/qsignalspy.h> #include <private/qdeclarativeengine_p.h> #include <private/qdeclarativeglobalscriptclass_p.h> #include <private/qscriptdeclarativeclass_p.h> @@ -178,6 +179,7 @@ private slots: void pushCleanContext(); void realToInt(); void qtbug_20648(); + void jsOwnedObjectsDeletedOnEngineDestroy(); void include(); @@ -1388,7 +1390,7 @@ void tst_qdeclarativeecmascript::callQtInvokables() QDeclarativeEngine qmlengine; QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine); - QScriptEngine *engine = &ep->scriptEngine; + QScriptEngine *engine = ep->scriptEngine; QStringList names; QList<QScriptValue> values; names << QLatin1String("object"); values << ep->objectClass->newQObject(&o); @@ -3100,6 +3102,38 @@ void tst_qdeclarativeecmascript::qtbug_20648() delete o; } +void tst_qdeclarativeecmascript::jsOwnedObjectsDeletedOnEngineDestroy() +{ + QDeclarativeEngine *myEngine = new QDeclarativeEngine; + + MyDeleteObject deleteObject; + deleteObject.setObjectName("deleteObject"); + QObject * const object1 = new QObject; + QObject * const object2 = new QObject; + object1->setObjectName("object1"); + object2->setObjectName("object2"); + deleteObject.setObject1(object1); + deleteObject.setObject2(object2); + + // Objects returned by function calls get marked as destructible, but objects returned by + // property getters do not - therefore we explicitly set the object as destructible. + QDeclarativeEngine::setObjectOwnership(object2, QDeclarativeEngine::JavaScriptOwnership); + + myEngine->rootContext()->setContextProperty("deleteObject", &deleteObject); + QDeclarativeComponent component(myEngine, TEST_FILE("jsOwnedObjectsDeletedOnEngineDestroy.qml")); + QObject *object = component.create(); + QVERIFY(object); + + // Destroying the engine should delete all JS owned QObjects + QSignalSpy spy1(object1, SIGNAL(destroyed())); + QSignalSpy spy2(object2, SIGNAL(destroyed())); + delete myEngine; + QCOMPARE(spy1.count(), 1); + QCOMPARE(spy2.count(), 1); + + delete object; +} + QTEST_MAIN(tst_qdeclarativeecmascript) #include "tst_qdeclarativeecmascript.moc" |