diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2024-01-31 15:17:19 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2024-02-01 09:33:09 +0100 |
commit | 452929cea1be97664f886509c3bd1b1a51dcf755 (patch) | |
tree | ec688aa8c9c712d13bfcb8c66948a6a115ec6838 /tests/auto/qml/qmlcppcodegen | |
parent | 1b8b77285948813b6e74554798b06210736e521c (diff) |
QmlCompiler: Reject lookups on shadowable base types
If the base type of a lookup is shadowable we cannot give any guarantees
at all about what is going to happen. Only if the right hand side of the
lookup is shadowable we can use our QVariant trick.
Fixes: QTBUG-121734
Pick-to: 6.7 6.6
Change-Id: I969a842a6bc6d6a4446bfbfb50f1a7021b84049e
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Diffstat (limited to 'tests/auto/qml/qmlcppcodegen')
5 files changed, 116 insertions, 3 deletions
diff --git a/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt b/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt index 4bf9aaab96..b896de4a1f 100644 --- a/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt +++ b/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt @@ -154,6 +154,7 @@ set(qml_files immediateQuit.qml imports/QmlBench/Globals.qml importsFromImportPath.qml + indirectlyShadowable.qml infinities.qml infinitiesToInt.qml intEnumCompare.qml diff --git a/tests/auto/qml/qmlcppcodegen/data/indirectlyShadowable.qml b/tests/auto/qml/qmlcppcodegen/data/indirectlyShadowable.qml new file mode 100644 index 0000000000..de31527e5b --- /dev/null +++ b/tests/auto/qml/qmlcppcodegen/data/indirectlyShadowable.qml @@ -0,0 +1,39 @@ +import QtQml + +QtObject { + id: self + objectName: "self" + + component Inner : QtObject { + property QtObject shadowable: QtObject { + objectName: "shadowable" + } + } + + component Outer : QtObject { + property Inner inner: Inner {} + } + + component Evil : Outer { + property string inner: "evil" + } + + property Outer outer: Outer {} + property Outer evil: Evil {} + + property QtObject notShadowable: QtObject { + objectName: "notShadowable" + } + + function getInnerShadowable() { + notShadowable = outer.inner.shadowable; + } + + function setInnerShadowable() { + outer.inner.shadowable = self; + } + + function turnEvil() { + outer = evil; + } +} diff --git a/tests/auto/qml/qmlcppcodegen/data/variantMap.qml b/tests/auto/qml/qmlcppcodegen/data/variantMap.qml index 410727cfd6..a8ac953f8b 100644 --- a/tests/auto/qml/qmlcppcodegen/data/variantMap.qml +++ b/tests/auto/qml/qmlcppcodegen/data/variantMap.qml @@ -11,8 +11,14 @@ QtObject { QtObject {} } + // We need this extra function in order to coerce the result of the shadowable + // method call back to QtObject + function createShadowable() : QtObject { + return shadowable.createObject(this, {objectName: "a"}) + } + objectName: { - return shadowable.createObject(this, {objectName: "a"}).objectName + return createShadowable().objectName + " " + unshadowable.createObject(this, {objectName: "b"}).objectName } diff --git a/tests/auto/qml/qmlcppcodegen/data/writeback.qml b/tests/auto/qml/qmlcppcodegen/data/writeback.qml index 8c6cb845c7..359f00efb7 100644 --- a/tests/auto/qml/qmlcppcodegen/data/writeback.qml +++ b/tests/auto/qml/qmlcppcodegen/data/writeback.qml @@ -15,6 +15,7 @@ Person { property outer recursive property Person shadowable: Person { + id: notShadowable area.width: self.area.width area2.height: self.area2.height } @@ -26,8 +27,10 @@ Person { self.area.x = 4 self.area2.y = 5 - shadowable.area.x = 40 - shadowable.area2.y = 50 + // You cannot do this on the shadowable Person because + // shadowable.area may not actually be a QRectF anymore. + notShadowable.area.x = 40 + notShadowable.area2.y = 50 self.recursive.inner.i = 99; diff --git a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp index 88c4e2375f..b98da74716 100644 --- a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp +++ b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp @@ -119,6 +119,7 @@ private slots: void importsFromImportPath(); void inPlaceDecrement(); void inaccessibleProperty(); + void indirectlyShadowable(); void infinities(); void infinitiesToInt(); void innerObjectNonShadowable(); @@ -2243,6 +2244,69 @@ void tst_QmlCppCodegen::inaccessibleProperty() QCOMPARE(o->property("c").toInt(), 5); } +void tst_QmlCppCodegen::indirectlyShadowable() +{ + QQmlEngine engine; + + const QString url = u"qrc:/qt/qml/TestTypes/indirectlyShadowable.qml"_s; + QQmlComponent c(&engine, QUrl(url)); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QScopedPointer<QObject> o(c.create()); + QVERIFY(!o.isNull()); + + const auto verifyShadowable = [&](const QString &objectName) { + QObject *outer = o->property("outer").value<QObject *>(); + QVERIFY(outer); + QObject *inner = outer->property("inner").value<QObject *>(); + QVERIFY(inner); + QObject *shadowable = inner->property("shadowable").value<QObject *>(); + QVERIFY(shadowable); + QCOMPARE(shadowable->objectName(), objectName); + }; + + const auto verifyNotShadowable = [&](const QString &objectName) { + QObject *notShadowable = o->property("notShadowable").value<QObject *>(); + QCOMPARE(notShadowable->objectName(), objectName); + }; + + const auto verifyEvil = [&]() { + QObject *outer = o->property("outer").value<QObject *>(); + QVERIFY(outer); + QCOMPARE(outer->property("inner").toString(), u"evil"_s); + }; + + verifyShadowable(u"shadowable"_s); + verifyNotShadowable(u"notShadowable"_s); + + QMetaObject::invokeMethod(o.data(), "setInnerShadowable"); + + verifyShadowable(u"self"_s); + verifyNotShadowable(u"notShadowable"_s); + + QMetaObject::invokeMethod(o.data(), "getInnerShadowable"); + + verifyShadowable(u"self"_s); + verifyNotShadowable(u"self"_s); + + QMetaObject::invokeMethod(o.data(), "turnEvil"); + + verifyEvil(); + verifyNotShadowable(u"self"_s); + + // Does not produce an error message because JavaScript. + QMetaObject::invokeMethod(o.data(), "setInnerShadowable"); + + verifyEvil(); + verifyNotShadowable(u"self"_s); + + QTest::ignoreMessage( + QtWarningMsg, qPrintable(url + u":29: Error: Cannot assign [undefined] to QObject*"_s)); + QMetaObject::invokeMethod(o.data(), "getInnerShadowable"); + + verifyEvil(); + verifyNotShadowable(u"self"_s); +} + void tst_QmlCppCodegen::infinities() { QQmlEngine engine; |