diff options
| author | Ulf Hermann <ulf.hermann@qt.io> | 2025-08-15 10:01:59 +0200 |
|---|---|---|
| committer | Ulf Hermann <ulf.hermann@qt.io> | 2025-08-21 20:33:23 +0200 |
| commit | 2547e8be4d507361527d422184d3cae205aa76ff (patch) | |
| tree | ce5c1ec11b862ac0a5fdb67e7158fb5e15342a7c /tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp | |
| parent | e0b9c581b815996ce1b278e3cb5fd94ab5489f8d (diff) | |
QtQml: Store detached VariantAssociation objects on the JS heap
While the VariantAssociation is detached it is subject to the GC or
unrelated C++ code deleting objects from its internals. Since it's then
not the owning object's responsibility to track this anymore, we need to
track it ourselves. The way to do it is to use the existing V4 objects.
Pick-to: 6.10 6.9
Task-number: QTBUG-139025
Change-Id: Ic1d5aa85171b5d91c2b9d546963268b6f09c2802
Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
Diffstat (limited to 'tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp')
| -rw-r--r-- | tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp | 55 |
1 files changed, 55 insertions, 0 deletions
diff --git a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp index a3082d0d75..df26b97488 100644 --- a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp +++ b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp @@ -3,6 +3,7 @@ #include <data/birthdayparty.h> #include <data/cppbaseclass.h> +#include <data/detachedreferences.h> #include <data/druggeljug.h> #include <data/enumProperty.h> #include <data/enumproblems.h> @@ -97,6 +98,7 @@ private slots: void deduplicateConversionOrigins(); void destroyAndToString(); void detachOnAssignment(); + void detachedReferences(); void dialogButtonBox(); void enumConversion(); void enumFromBadSingleton(); @@ -1739,6 +1741,59 @@ void tst_QmlCppCodegen::detachOnAssignment() QCOMPARE(p->things()[0], QStringLiteral("c")); } +void tst_QmlCppCodegen::detachedReferences() +{ + QQmlEngine engine; + QQmlComponent c(&engine, QUrl(u"qrc:/qt/qml/TestTypes/detachedreferences.qml"_s)); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QScopedPointer<QObject> o(c.create()); + QVERIFY(o); + + DetachedReferences *d = qobject_cast<DetachedReferences *>(o.data()); + QVERIFY(d); + + const QVariantHash hash = d->getHash(); + QObject *collectable1 = hash["collectable"_L1].value<QObject *>(); + QVERIFY(collectable1); + QSignalSpy spy1(collectable1, &QObject::destroyed); + + const QVariantMap map = d->getMap(); + QObject *collectable2 = map["collectable"_L1].value<QObject *>(); + QVERIFY(collectable2); + QSignalSpy spy2(collectable2, &QObject::destroyed); + + // The detached containers retain their types. + QCOMPARE(d->property("markedMap").metaType(), QMetaType::fromType<QVariantMap>()); + QCOMPARE(d->property("markedHash").metaType(), QMetaType::fromType<QVariantHash>()); + + engine.collectGarbage(); + QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); + QCoreApplication::processEvents(); + + QCOMPARE(spy1.count(), 0); + QCOMPARE(spy2.count(), 0); + + // Resetting the hash alone does not cause collectible1 to be collected + // because it's also in the map (recursively). + d->setProperty("markedHash", QVariant()); + + engine.collectGarbage(); + QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); + QCoreApplication::processEvents(); + + QCOMPARE(spy1.count(), 0); + QCOMPARE(spy2.count(), 0); + + d->setProperty("markedMap", QVariant()); + + engine.collectGarbage(); + QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); + QCoreApplication::processEvents(); + + QCOMPARE(spy1.count(), 1); + QCOMPARE(spy2.count(), 1); +} + void tst_QmlCppCodegen::dialogButtonBox() { QQmlEngine engine; |
