From 7d510cfc0bc149c0b4f622f9dd4c1befdfbd85b2 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 19 Feb 2025 13:32:06 +0100 Subject: 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 --- tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp | 68 ++++++++++++++++++++++ 1 file changed, 68 insertions(+) (limited to 'tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp') 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 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()); + QVERIFY(o->property("immediateShadowable").value()); + QVERIFY(o->property("delayedDestroyable").value()); + QVERIFY(o->property("immediateDestroyable").value()); + QVERIFY(o->property("scopedImmediateDestroyable").value()); + QVERIFY(o->property("scopedDelayedDestroyable").value()); + + QMetaObject::invokeMethod(o.data(), "explode"); + + QVERIFY(o->property("delayedShadowable").value()); + QVERIFY(o->property("delayedDestroyable").value()); + QVERIFY(o->property("scopedDelayedDestroyable").value()); + + 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()); + QTRY_VERIFY(!o->property("immediateDestroyable").value()); + QTRY_VERIFY(!o->property("scopedImmediateDestroyable").value()); + QTRY_VERIFY(!o->property("delayedShadowable").value()); + QTRY_VERIFY(!o->property("delayedDestroyable").value()); + QTRY_VERIFY(!o->property("scopedDelayedDestroyable").value()); + + 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() != 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(), nullptr); +} + void tst_QmlCppCodegen::detachOnAssignment() { QQmlEngine engine; -- cgit v1.2.3