Do not execute overwritten bindings
authorAaron Kennedy <aaron.kennedy@nokia.com>
Wed, 4 Apr 2012 11:17:59 +0000 (12:17 +0100)
committerQt by Nokia <qt-info@nokia.com>
Wed, 4 Apr 2012 11:29:19 +0000 (13:29 +0200)
During the construction of an object, internal bindings can be
overwritten by the initialization of objects with outer scope.

Task-number: QTBUG-23138
Change-Id: I46a187d9cdc41f4dd96d068f39788a2255b8888d
Reviewed-by: Roberto Raggi <roberto.raggi@nokia.com>
src/qml/qml/qqmlvme.cpp
tests/auto/qml/qqmlecmascript/data/InnerObject.qml [new file with mode: 0644]
tests/auto/qml/qqmlecmascript/data/OuterObject.qml [new file with mode: 0644]
tests/auto/qml/qqmlecmascript/data/replaceBinding.qml [new file with mode: 0644]
tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp

index f5a6954..9115e47 100644 (file)
@@ -205,13 +205,19 @@ inline bool fastHasBinding(QObject *o, int index)
 {
     QQmlData *ddata = static_cast<QQmlData *>(QObjectPrivate::get(o)->declarativeData);
 
+    index &= 0xFFFFFF; // To handle value types
+
     return ddata && (ddata->bindingBitsSize > index) && 
            (ddata->bindingBits[index / 32] & (1 << (index % 32)));
 }
 
 static void removeBindingOnProperty(QObject *o, int index)
 {
-    QQmlAbstractBinding *binding = QQmlPropertyPrivate::setBinding(o, index, -1, 0);
+    int coreIndex = index & 0xFFFFFF;
+    int valueTypeIndex = index & 0xFF000000;
+    if (!valueTypeIndex) valueTypeIndex = -1;
+
+    QQmlAbstractBinding *binding = QQmlPropertyPrivate::setBinding(o, coreIndex, valueTypeIndex, 0);
     if (binding) binding->destroy();
 }
 
@@ -782,6 +788,8 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
                 Q_ASSERT(bind->propertyIndex() == QDPP::bindingIndex(instr.property));
                 Q_ASSERT(bind->object() == target);
 
+                CLEAN_PROPERTY(target, QDPP::bindingIndex(instr.property));
+
                 bind->addToObject();
             }
         QML_END_INSTR(StoreBinding)
@@ -805,6 +813,8 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
             Q_ASSERT(binding->propertyIndex() == (property & 0xFF00FFFF));
             Q_ASSERT(binding->object() == target);
 
+            CLEAN_PROPERTY(target, property & 0xFF00FFFF);
+
             binding->addToObject();
         QML_END_INSTR(StoreV4Binding)
 
@@ -835,6 +845,8 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
                     Q_ASSERT(binding->propertyIndex() == QDPP::bindingIndex(instr.property));
                     Q_ASSERT(binding->object() == target);
 
+                    CLEAN_PROPERTY(target, QDPP::bindingIndex(instr.property));
+
                     binding->addToObject();
                 }
             }
diff --git a/tests/auto/qml/qqmlecmascript/data/InnerObject.qml b/tests/auto/qml/qqmlecmascript/data/InnerObject.qml
new file mode 100644 (file)
index 0000000..a8ed959
--- /dev/null
@@ -0,0 +1,13 @@
+import QtQuick 2.0
+
+QtObject {
+    property int foo1: 100
+    property int foo2: 100
+    property int foo3: { return 100; }
+    property int foo4: { return 100; }
+
+    property string bar1: 'Hello'
+    property string bar2: 'Hello'
+    property string bar3: { return 'Hello'; }
+    property string bar4: { return 'Hello'; }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/OuterObject.qml b/tests/auto/qml/qqmlecmascript/data/OuterObject.qml
new file mode 100644 (file)
index 0000000..da571a9
--- /dev/null
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+Item {
+    property InnerObject inner: InnerObject {}
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/replaceBinding.qml b/tests/auto/qml/qqmlecmascript/data/replaceBinding.qml
new file mode 100644 (file)
index 0000000..670231a
--- /dev/null
@@ -0,0 +1,26 @@
+import QtQuick 2.0
+
+OuterObject {
+    property bool success: false
+
+    inner.foo1: 200
+    inner.foo2: { return 200; }
+    inner.foo3: 200
+    inner.foo4: { return 200; }
+
+    inner.bar1: 'Goodbye'
+    inner.bar2: { return 'Goodbye' }
+    inner.bar3: 'Goodbye'
+    inner.bar4: { return 'Goodbye' }
+
+    Component.onCompleted: {
+        success = (inner.foo1 == 200 &&
+                   inner.foo2 == 200 &&
+                   inner.foo3 == 200 &&
+                   inner.foo4 == 200 &&
+                   inner.bar1 == 'Goodbye' &&
+                   inner.bar2 == 'Goodbye' &&
+                   inner.bar3 == 'Goodbye' &&
+                   inner.bar4 == 'Goodbye');
+    }
+}
index ee9c7ee..273cd07 100644 (file)
@@ -252,6 +252,7 @@ private slots:
     void switchStatement();
     void withStatement();
     void tryStatement();
+    void replaceBinding();
 
 private:
     static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
@@ -6416,6 +6417,18 @@ void tst_qqmlecmascript::registeredFlagMethod()
     delete object;
 }
 
+// QTBUG-23138
+void tst_qqmlecmascript::replaceBinding()
+{
+    QQmlEngine engine;
+    QQmlComponent c(&engine, testFileUrl("replaceBinding.qml"));
+    QObject *obj = c.create();
+    QVERIFY(obj != 0);
+
+    QVERIFY(obj->property("success").toBool());
+    delete obj;
+}
+
 QTEST_MAIN(tst_qqmlecmascript)
 
 #include "tst_qqmlecmascript.moc"