diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2021-08-11 15:47:13 +0200 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2021-08-17 19:04:40 +0000 |
commit | 4d391ad2968efccf0ec5f2840126f051b40a89f9 (patch) | |
tree | 22ce9ea4c60e23f3de94432a97a11c2a66b219ff /tests | |
parent | fcdd613dbeb9945604f15c164b4c97aba4f195a0 (diff) |
When binding signals, run the outer function to get the nested one
The outer function may perform important tasks like setting up a call
context with a "this" member for the nested function. In particular,
arrow functions retain their original "this" member, no matter where
they are executed later. We can detect this condition while generating
the compilation unit. If the outer function is not a simple wrapper that
only returns the inner function, execute it when binding a signal.
Fixes: QTBUG-95659
Change-Id: I7dfef2c78378588e6bfc4bedde7889c7f2ce03ef
Reviewed-by: Yuya Nishihara <yuya.nishihara@qt.io>
Reviewed-by: Maximilian Goldstein <max.goldstein@qt.io>
(cherry picked from commit 8cd7aabfb24b391143b3c358f49fb6a28765d5f3)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/auto/qml/qqmllanguage/data/thisInArrow.qml | 39 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 25 |
2 files changed, 64 insertions, 0 deletions
diff --git a/tests/auto/qml/qqmllanguage/data/thisInArrow.qml b/tests/auto/qml/qqmllanguage/data/thisInArrow.qml new file mode 100644 index 0000000000..7dd19782e6 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/thisInArrow.qml @@ -0,0 +1,39 @@ +import QtQml + +QtObject { + id: root + + property int width: 43 + Component.onCompleted: () => { console.log(this.width); } + + property var arrow: () => { return this; } + property var func: function() { return this; } + + property QtObject child: QtObject { + property var aa; + property var ff; + + Component.onCompleted: { + root.arrowResult = root.arrow(); + root.funcResult = root.func(); + + var a = root.arrow; + root.aResult = a(); + var f = root.func; + root.fResult = f(); + + aa = a; + root.aaResult = aa(); + + ff = f; + root.ffResult = ff(); + } + } + + property var arrowResult + property var funcResult + property var aResult + property var fResult + property var aaResult + property var ffResult +} diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index d09f903ccb..bf7953c51c 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -364,6 +364,7 @@ private slots: void propertyObserverOnReadonly(); void variantListConversion(); + void thisInArrowFunction(); private: QQmlEngine engine; @@ -6372,6 +6373,30 @@ void tst_qqmllanguage::variantListConversion() QCOMPARE(l1.a, 13ull); } +void tst_qqmllanguage::thisInArrowFunction() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("thisInArrow.qml")); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + + QTest::ignoreMessage(QtDebugMsg, "43"); + QScopedPointer<QObject> o(c.create()); + QVERIFY(!o.isNull()); + + QCOMPARE(qvariant_cast<QObject *>(o->property("arrowResult")), o.data()); + QCOMPARE(qvariant_cast<QObject *>(o->property("funcResult")), o.data()); + QCOMPARE(qvariant_cast<QObject *>(o->property("aResult")), o.data()); + QCOMPARE(qvariant_cast<QObject *>(o->property("aaResult")), o.data()); + + QCOMPARE(qvariant_cast<QObject *>(o->property("fResult")), nullptr); + QCOMPARE(o->property("fResult").metaType(), QMetaType::fromType<QJSValue>()); + QVERIFY(qvariant_cast<QJSValue>(o->property("fResult")).isObject()); + + QObject *child = qvariant_cast<QObject *>(o->property("child")); + QVERIFY(child != nullptr); + QCOMPARE(qvariant_cast<QObject *>(o->property("ffResult")), child); +} + QTEST_MAIN(tst_qqmllanguage) #include "tst_qqmllanguage.moc" |