diff options
| author | Ulf Hermann <ulf.hermann@qt.io> | 2025-02-19 13:32:06 +0100 |
|---|---|---|
| committer | Ulf Hermann <ulf.hermann@qt.io> | 2025-02-26 20:54:39 +0100 |
| commit | 7d510cfc0bc149c0b4f622f9dd4c1befdfbd85b2 (patch) | |
| tree | c5f844d21a86c5646c169a92cf28f78270e8d1b0 /tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp | |
| parent | 7d96f726337d62f5cd37dd5c31ebcf8accd56bcd (diff) | |
QtQml: Fix AOT compiled context for destroy() and toString() methods
Those are not mapped to regular QMetaMethods but rather come with
special method indices and need to be resolved separately.
Amends commit a741271dd58b21728928684f1ef1efaa91e79ebf
This exposes that the override order between JavaScript extensions and
their base types was wrong. JavaScript extensions do certainly not
override their base types. Fix this, too.
We also need to always specialize the lookups for these calls. It
doesn't actually matter if there is propertyData or not since we branch
off into the special cases anyway when calling them.
Pick-to: 6.9
Fixes: QTBUG-132602
Change-Id: Iea83ce94459b0d0a3bf54731898fd62b9ad46c46
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp')
| -rw-r--r-- | tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp index 0ca624134e..8216bf0125 100644 --- a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp +++ b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp @@ -92,6 +92,7 @@ private slots: void dateConstruction(); void dateConversions(); void deadShoeSize(); + void destroyAndToString(); void detachOnAssignment(); void dialogButtonBox(); void enumConversion(); @@ -1593,6 +1594,73 @@ void tst_QmlCppCodegen::deadShoeSize() QCOMPARE(o->property("shoeSize").toInt(), 0); } +void tst_QmlCppCodegen::destroyAndToString() +{ + QQmlEngine engine; + const QString url = u"qrc:/qt/qml/TestTypes/destroyAndToString.qml"_s; + QQmlComponent c(&engine, QUrl(url)); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QScopedPointer<QObject> o(c.create()); + QVERIFY(o); + + const QString objectName = u"me, myself, and I"_s; + QCOMPARE(o->objectName(), objectName); + + auto verifyName = [&](const char *property, const QString &name) { + const QRegularExpression regexp(u"^QObject[^(]*\\(0x[0-9a-f]+, \"%1\"\\)$"_s.arg(name)); + const QString value = o->property(property).toString(); + const auto match = regexp.match(value); + QVERIFY2(match.hasMatch(), qPrintable(value + u" does not match " + regexp.pattern())); + }; + + verifyName("stringed", objectName); + verifyName("selfStringed", objectName); + verifyName("immediateShadowableStringed", u"immediateShadowable"_s); + verifyName("delayedShadowableStringed", u"delayedShadowable"_s); + + QVERIFY(o->property("delayedShadowable").value<QObject *>()); + QVERIFY(o->property("immediateShadowable").value<QObject *>()); + QVERIFY(o->property("delayedDestroyable").value<QObject *>()); + QVERIFY(o->property("immediateDestroyable").value<QObject *>()); + QVERIFY(o->property("scopedImmediateDestroyable").value<QObject *>()); + QVERIFY(o->property("scopedDelayedDestroyable").value<QObject *>()); + + QMetaObject::invokeMethod(o.data(), "explode"); + + QVERIFY(o->property("delayedShadowable").value<QObject *>()); + QVERIFY(o->property("delayedDestroyable").value<QObject *>()); + QVERIFY(o->property("scopedDelayedDestroyable").value<QObject *>()); + + QTest::ignoreMessage( + QtWarningMsg, + qPrintable(url + u":36: TypeError: Cannot call method 'toString' of null")); + QTest::ignoreMessage( + QtWarningMsg, + qPrintable(url + u":37: TypeError: Cannot call method 'toString' of null")); + + QTRY_VERIFY(!o->property("immediateShadowable").value<QObject *>()); + QTRY_VERIFY(!o->property("immediateDestroyable").value<QObject *>()); + QTRY_VERIFY(!o->property("scopedImmediateDestroyable").value<QObject *>()); + QTRY_VERIFY(!o->property("delayedShadowable").value<QObject *>()); + QTRY_VERIFY(!o->property("delayedDestroyable").value<QObject *>()); + QTRY_VERIFY(!o->property("scopedDelayedDestroyable").value<QObject *>()); + + verifyName("stringed", objectName); + verifyName("selfStringed", objectName); + + // Since the bindings threw errors, the values were not changed + verifyName("immediateShadowableStringed", u"immediateShadowable"_s); + verifyName("delayedShadowableStringed", u"delayedShadowable"_s); + + QVERIFY(o->property("overrides").value<QObject *>() != nullptr); + QString result; + QMetaObject::invokeMethod(o.data(), "callOverridden", Q_RETURN_ARG(QString, result)); + QCOMPARE(result, u"yes"_s); + + QCOMPARE(o->objectName(), objectName); + QTRY_COMPARE(o->property("overrides").value<QObject *>(), nullptr); +} + void tst_QmlCppCodegen::detachOnAssignment() { QQmlEngine engine; |
