diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2023-04-28 14:02:20 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2023-05-04 16:44:44 +0200 |
commit | 4634b6bf54e5ba15aa2e8efc12feb156e3d9c309 (patch) | |
tree | be5109708b5729475b58ddb6f1d164caf7928c6a /tests/auto | |
parent | 8fab8cf39c9ce7247b8e5b72d123c9dd806ea870 (diff) | |
download | qtdeclarative-4634b6bf54e5ba15aa2e8efc12feb156e3d9c309.tar.gz |
QmlCompiler: Disallow reading from values affected by side effects
Instead of accepting the inconsistency between interpreter and compiled
code here, we can just detect whether a value can be affected by side
effects and refrain from reading it then. Since you can always
explicitly reload a value that may have been changed, the resulting
compile warnings are easily worked around in user code. Refactoring user
code this way also makes it much clearer what is actually going on.
Pick-to: 6.5
Task-number: QTBUG-109221
Change-Id: Ica832e39838ef732b0d181364630737fd7709b74
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'tests/auto')
-rw-r--r-- | tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tests/auto/qml/qmlcppcodegen/data/valueTypeDefault.qml | 34 | ||||
-rw-r--r-- | tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp | 75 |
3 files changed, 81 insertions, 29 deletions
diff --git a/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt b/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt index 74f56f0bb3..ad8bcf32a9 100644 --- a/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt +++ b/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt @@ -219,6 +219,7 @@ set(qml_files usingCxxTypesFromFileImports.qml valueTypeCast.qml valueTypeCopy.qml + valueTypeDefault.qml valueTypeLists.qml valueTypeProperty.qml valueTypeReference.qml diff --git a/tests/auto/qml/qmlcppcodegen/data/valueTypeDefault.qml b/tests/auto/qml/qmlcppcodegen/data/valueTypeDefault.qml new file mode 100644 index 0000000000..42a55e832d --- /dev/null +++ b/tests/auto/qml/qmlcppcodegen/data/valueTypeDefault.qml @@ -0,0 +1,34 @@ +import QtQml + + +QtObject { + id: root + + property list<double> numbers: { + var result = []; + for (var i = 0; i < 10; ++i) + result[i] = i; + return result; + } + + property rect r: ({x: 1, y: 2, width: 3, height: 4}) + + function evil() : double { + var numbers = root.numbers; + root.numbers = []; + var a = 0; + for (var j = 0; j < 10; ++j) { + a += numbers[j]; + } + return a; + } + + function fvil() : double { + var r = root.r; + root.r = {x: 5, y: 6, width: 7, height: 8}; + return r.x; + } + + property double e: evil() + property double f: fvil() +} diff --git a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp index 9991688943..20a1bac8af 100644 --- a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp +++ b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp @@ -3693,42 +3693,59 @@ void tst_QmlCppCodegen::valueTypeBehavior() { QQmlEngine engine; - const QUrl copy(u"qrc:/qt/qml/TestTypes/valueTypeCopy.qml"_s); + { + const QUrl url(u"qrc:/qt/qml/TestTypes/valueTypeCopy.qml"_s); + QQmlComponent c(&engine, url); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QTest::ignoreMessage(QtWarningMsg, bindingLoopMessage(url, 'e')); + QTest::ignoreMessage(QtWarningMsg, bindingLoopMessage(url, 'f')); + QScopedPointer<QObject> o(c.create()); + QVERIFY(!o.isNull()); + QCOMPARE(o->property("e").toDouble(), 45.0); + QCOMPARE(o->property("f").toDouble(), 1.0); + } - QQmlComponent c1(&engine, copy); - QVERIFY2(c1.isReady(), qPrintable(c1.errorString())); - QTest::ignoreMessage(QtWarningMsg, bindingLoopMessage(copy, 'e')); - QTest::ignoreMessage(QtWarningMsg, bindingLoopMessage(copy, 'f')); - QScopedPointer<QObject> o1(c1.create()); - QVERIFY(!o1.isNull()); - QCOMPARE(o1->property("e").toDouble(), 45.0); - QCOMPARE(o1->property("f").toDouble(), 1.0); + { + const QUrl url(u"qrc:/qt/qml/TestTypes/valueTypeReference.qml"_s); + QQmlComponent c(&engine, url); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QTest::ignoreMessage(QtWarningMsg, bindingLoopMessage(url, 'e')); + QTest::ignoreMessage(QtWarningMsg, bindingLoopMessage(url, 'f')); + QScopedPointer<QObject> o(c.create()); + QVERIFY(!o.isNull()); + QVERIFY(qIsNaN(o->property("e").toDouble())); + QCOMPARE(o->property("f").toDouble(), 5.0); + } - const QUrl reference(u"qrc:/qt/qml/TestTypes/valueTypeReference.qml"_s); - QQmlComponent c2(&engine, reference); - QVERIFY2(c2.isReady(), qPrintable(c2.errorString())); - QTest::ignoreMessage(QtWarningMsg, bindingLoopMessage(reference, 'e')); - QTest::ignoreMessage(QtWarningMsg, bindingLoopMessage(reference, 'f')); - QScopedPointer<QObject> o2(c2.create()); - QVERIFY(!o2.isNull()); - QVERIFY(qIsNaN(o2->property("e").toDouble())); - QCOMPARE(o2->property("f").toDouble(), 5.0); + { + const QUrl url(u"qrc:/qt/qml/TestTypes/valueTypeDefault.qml"_s); + QQmlComponent c(&engine, url); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QTest::ignoreMessage(QtWarningMsg, bindingLoopMessage(url, 'e')); + QTest::ignoreMessage(QtWarningMsg, bindingLoopMessage(url, 'f')); + QScopedPointer<QObject> o(c.create()); + QVERIFY(!o.isNull()); + QVERIFY(qIsNaN(o->property("e").toDouble())); + QCOMPARE(o->property("f").toDouble(), 5.0); + } - const QUrl cast(u"qrc:/qt/qml/TestTypes/valueTypeCast.qml"_s); - QQmlComponent c3(&engine, cast); - QVERIFY2(c3.isReady(), qPrintable(c3.errorString())); - QScopedPointer o3(c3.create()); - QVERIFY(!o3.isNull()); - QCOMPARE(o3->property("x"), 10); + { + const QUrl url(u"qrc:/qt/qml/TestTypes/valueTypeCast.qml"_s); + QQmlComponent c(&engine, url); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QScopedPointer o(c.create()); + QVERIFY(!o.isNull()); + QCOMPARE(o->property("x"), 10); - QTest::ignoreMessage( + QTest::ignoreMessage( QtWarningMsg, - qPrintable(cast.toString() + qPrintable(url.toString() + u":8: TypeError: Cannot read property 'x' of undefined"_s)); - o3->setProperty("v", QLatin1String("not a rect")); + o->setProperty("v", QLatin1String("not a rect")); - // If the binding throws an exception, the value doesn't change. - QCOMPARE(o3->property("x"), 10); + // If the binding throws an exception, the value doesn't change. + QCOMPARE(o->property("x"), 10); + } } void tst_QmlCppCodegen::valueTypeLists() |