diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2013-12-10 15:25:22 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-12-10 15:46:09 +0100 |
commit | 29b6d2e45c7434fccf2e6878630e62d5dcce38db (patch) | |
tree | d2d0ad7639c9863c00cdd8558d9663bea813c3f3 /tests/auto | |
parent | fb72bb3cf27d1f94760709aaab82e3524ae936f4 (diff) |
Fix broken Maroon game / regression in PropertyChanges {} element
Commit 0aadcf8077840068eb182269e9ed9c31ad12f45e that pre-compiles the
expressions in PropertyChanges {} introduced a regression in where the
evaluation context was incorrect and thus bindings would not be able to
access the correct properties. For example
PropertyChanges {
target: someObject
y: height / 2
}
Here height should be looked up in the context of "someObject", not of the
PropertyChanges element.
This patch introduces an auto-test that verifies that the lookup context is
correct and fixes the bug by disabling accelerated compile time property
lookups for binding expressions that are requested from a custom parser.
Change-Id: I5cb607d07211b453ddfc9928ccbf5f9ecec85575
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'tests/auto')
-rw-r--r-- | tests/auto/qml/qqmllanguage/data/customParserBindingScopes.qml | 19 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/testtypes.cpp | 60 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/testtypes.h | 23 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 13 |
4 files changed, 115 insertions, 0 deletions
diff --git a/tests/auto/qml/qqmllanguage/data/customParserBindingScopes.qml b/tests/auto/qml/qqmllanguage/data/customParserBindingScopes.qml new file mode 100644 index 0000000000..2efc199f32 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/customParserBindingScopes.qml @@ -0,0 +1,19 @@ +import Test 1.0 +import QtQml 2.0 +QtObject { + id: root + + property int otherProperty: 10 + + property QtObject child: QtObject { + id: child + + property int testProperty; + property int otherProperty: 41 + + property QtObject customBinder: CustomBinding { + target: child + testProperty: otherProperty + 1 + } + } +} diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp index 3957f9d872..4a4ab3b81a 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.cpp +++ b/tests/auto/qml/qqmllanguage/testtypes.cpp @@ -89,6 +89,8 @@ void registerTypes() qmlRegisterUncreatableType<MyUncreateableBaseClass,1>("Test", 1, 1, "MyUncreateableBaseClass", "Cannot create MyUncreateableBaseClass"); qmlRegisterType<MyCreateableDerivedClass,1>("Test", 1, 1, "MyCreateableDerivedClass"); + + qmlRegisterCustomType<CustomBinding>("Test", 1, 0, "CustomBinding", new CustomBindingParser); } QVariant myCustomVariantTypeConverter(const QString &data) @@ -97,3 +99,61 @@ QVariant myCustomVariantTypeConverter(const QString &data) rv.a = data.toInt(); return QVariant::fromValue(rv); } + + +QByteArray CustomBindingParser::compile(const QList<QQmlCustomParserProperty> &properties) +{ + QByteArray result; + QDataStream ds(&result, QIODevice::WriteOnly); + + ds << properties.count(); + for (int i = 0; i < properties.count(); ++i) { + const QQmlCustomParserProperty &prop = properties.at(i); + ds << prop.name(); + + Q_ASSERT(prop.assignedValues().count() == 1); + QVariant value = prop.assignedValues().first(); + + Q_ASSERT(value.userType() == qMetaTypeId<QQmlScript::Variant>()); + QQmlScript::Variant v = qvariant_cast<QQmlScript::Variant>(value); + Q_ASSERT(v.type() == QQmlScript::Variant::Script); + int bindingId = bindingIdentifier(v, prop.name()); + ds << bindingId; + + ds << prop.location().line; + } + + return result; +} + +void CustomBindingParser::setCustomData(QObject *object, const QByteArray &data) +{ + CustomBinding *customBinding = qobject_cast<CustomBinding*>(object); + Q_ASSERT(customBinding); + customBinding->m_bindingData = data; +} + +void CustomBinding::componentComplete() +{ + Q_ASSERT(m_target); + + QDataStream ds(m_bindingData); + int count; + ds >> count; + for (int i = 0; i < count; ++i) { + QString name; + ds >> name; + + int bindingId; + ds >> bindingId; + + int line; + ds >> line; + + QQmlBinding *binding = QQmlBinding::createBinding(QQmlBinding::Identifier(bindingId), m_target, qmlContext(this), QString(), line); + + QQmlProperty property(m_target, name, qmlContext(this)); + binding->setTarget(property); + QQmlPropertyPrivate::setBinding(property, binding); + } +} diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h index 703b26a73c..a968d9a25a 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.h +++ b/tests/auto/qml/qqmllanguage/testtypes.h @@ -1070,6 +1070,29 @@ QML_DECLARE_TYPE(MyRevisionedSubclass) QML_DECLARE_TYPE(MySubclass) QML_DECLARE_TYPE(MyReceiversTestObject) +class CustomBinding : public QObject, public QQmlParserStatus +{ + Q_OBJECT + Q_INTERFACES(QQmlParserStatus) + Q_PROPERTY(QObject* target READ target WRITE setTarget) +public: + + virtual void classBegin() {} + virtual void componentComplete(); + + QObject *target() const { return m_target; } + void setTarget(QObject *newTarget) { m_target = newTarget; } + + QPointer<QObject> m_target; + QByteArray m_bindingData; +}; + +class CustomBindingParser : public QQmlCustomParser +{ + virtual QByteArray compile(const QList<QQmlCustomParserProperty> &properties); + virtual void setCustomData(QObject *object, const QByteArray &data); +}; + void registerTypes(); #endif // TESTTYPES_H diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 621061ab6a..6a577ec91c 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -214,6 +214,8 @@ private slots: void compositeSingletonSelectors(); void compositeSingletonRegistered(); + void customParserBindingScopes(); + private: QQmlEngine engine; QStringList defaultImportPathList; @@ -3534,6 +3536,17 @@ void tst_qqmllanguage::compositeSingletonRegistered() verifyCompositeSingletonPropertyValues(o, "value1", 925, "value2", 755); } +void tst_qqmllanguage::customParserBindingScopes() +{ + QQmlComponent component(&engine, testFile("customParserBindingScopes.qml")); + VERIFY_ERRORS(0); + QScopedPointer<QObject> o(component.create()); + QVERIFY(!o.isNull()); + QPointer<QObject> child = qvariant_cast<QObject*>(o->property("child")); + QVERIFY(!child.isNull()); + QCOMPARE(child->property("testProperty").toInt(), 42); +} + QTEST_MAIN(tst_qqmllanguage) #include "tst_qqmllanguage.moc" |