Allow QDeclarativeIncubator to be deleted within statusChanged() callback
authorAaron Kennedy <aaron.kennedy@nokia.com>
Tue, 18 Oct 2011 04:56:25 +0000 (14:56 +1000)
committerQt by Nokia <qt-info@nokia.com>
Thu, 20 Oct 2011 11:26:17 +0000 (13:26 +0200)
Change-Id: I17621870b67d8a975545adc27ddaf9695e6a9428
Reviewed-by: Martin Jones <martin.jones@nokia.com>
src/declarative/qml/qdeclarativeincubator.cpp
tests/auto/declarative/qdeclarativeincubator/data/selfDelete.qml [new file with mode: 0644]
tests/auto/declarative/qdeclarativeincubator/tst_qdeclarativeincubator.cpp

index d1afac2..05c73da 100644 (file)
@@ -83,15 +83,22 @@ void QDeclarativeEnginePrivate::incubate(QDeclarativeIncubator &i, QDeclarativeC
 
     inProgressCreations++;
 
-    p->changeStatus(QDeclarativeIncubator::Loading);
-
     if (mode == QDeclarativeIncubator::Synchronous) {
-        QDeclarativeVME::Interrupt i;
-        p->incubate(i);
+        typedef QDeclarativeIncubatorPrivate IP;
+        QRecursionWatcher<IP, &IP::recursion> watcher(p);
+
+        p->changeStatus(QDeclarativeIncubator::Loading);
+
+        if (!watcher.hasRecursed()) {
+            QDeclarativeVME::Interrupt i;
+            p->incubate(i);
+        }
     } else {
         incubatorList.insert(p);
         incubatorCount++;
 
+        p->changeStatus(QDeclarativeIncubator::Loading);
+
         if (incubationController)
             incubationController->incubatingObjectCountChanged(incubatorCount);
     }
diff --git a/tests/auto/declarative/qdeclarativeincubator/data/selfDelete.qml b/tests/auto/declarative/qdeclarativeincubator/data/selfDelete.qml
new file mode 100644 (file)
index 0000000..c395207
--- /dev/null
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+QtObject {
+    property int dummy: 12
+}
index e3648f7..00c226e 100644 (file)
@@ -51,6 +51,7 @@
 #include <QDeclarativeComponent>
 #include <QDeclarativeIncubator>
 #include "../shared/util.h"
+#include "../../../shared/util.h"
 
 inline QUrl TEST_FILE(const QString &filename)
 {
@@ -83,6 +84,7 @@ private slots:
     void asynchronousIfNested();
     void nestedComponent();
     void chainedAsynchronousIfNested();
+    void selfDelete();
 
 private:
     QDeclarativeIncubationController controller;
@@ -772,6 +774,79 @@ void tst_qdeclarativeincubator::chainedAsynchronousIfNested()
     QVERIFY(incubator2.isReady());
 }
 
+void tst_qdeclarativeincubator::selfDelete()
+{
+    struct MyIncubator : public QDeclarativeIncubator {
+        MyIncubator(bool *done, Status status, IncubationMode mode)
+        : QDeclarativeIncubator(mode), done(done), status(status) {}
+
+    protected:
+        virtual void statusChanged(Status s) {
+            if (s == status) {
+                *done = true;
+                if (s == Ready) delete object();
+                delete this;
+            }
+        }
+
+    private:
+        bool *done;
+        Status status;
+    };
+
+    {
+    QDeclarativeComponent component(&engine, TEST_FILE("selfDelete.qml"));
+
+#define DELETE_TEST(status, mode) { \
+    bool done = false; \
+    component.create(*(new MyIncubator(&done, status, mode))); \
+    bool True = true; \
+    controller.incubateWhile(&True); \
+    QVERIFY(done == true); \
+    }
+
+    DELETE_TEST(QDeclarativeIncubator::Loading, QDeclarativeIncubator::Synchronous);
+    DELETE_TEST(QDeclarativeIncubator::Ready, QDeclarativeIncubator::Synchronous);
+    DELETE_TEST(QDeclarativeIncubator::Loading, QDeclarativeIncubator::Asynchronous);
+    DELETE_TEST(QDeclarativeIncubator::Ready, QDeclarativeIncubator::Asynchronous);
+
+#undef DELETE_TEST
+    }
+
+    // Delete within error status
+    {
+    SelfRegisteringType::clearMe();
+
+    QDeclarativeComponent component(&engine, TEST_FILE("objectDeleted.qml"));
+    QVERIFY(component.isReady());
+
+    bool done = false;
+    MyIncubator *incubator = new MyIncubator(&done, QDeclarativeIncubator::Error,
+                                             QDeclarativeIncubator::Asynchronous);
+    component.create(*incubator);
+
+    QCOMPARE(incubator->QDeclarativeIncubator::status(), QDeclarativeIncubator::Loading);
+    QVERIFY(SelfRegisteringType::me() == 0);
+
+    while (SelfRegisteringType::me() == 0 && incubator->isLoading()) {
+        bool b = false;
+        controller.incubateWhile(&b);
+    }
+
+    QVERIFY(SelfRegisteringType::me() != 0);
+    QVERIFY(incubator->isLoading());
+
+    delete SelfRegisteringType::me();
+
+    {
+    bool b = true;
+    controller.incubateWhile(&b);
+    }
+
+    QVERIFY(done);
+    }
+}
+
 QTEST_MAIN(tst_qdeclarativeincubator)
 
 #include "tst_qdeclarativeincubator.moc"