aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2025-02-19 13:32:06 +0100
committerUlf Hermann <ulf.hermann@qt.io>2025-02-26 20:54:39 +0100
commit7d510cfc0bc149c0b4f622f9dd4c1befdfbd85b2 (patch)
treec5f844d21a86c5646c169a92cf28f78270e8d1b0 /tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
parent7d96f726337d62f5cd37dd5c31ebcf8accd56bcd (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.cpp68
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;