aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2025-08-15 10:01:59 +0200
committerUlf Hermann <ulf.hermann@qt.io>2025-08-21 20:33:23 +0200
commit2547e8be4d507361527d422184d3cae205aa76ff (patch)
treece5c1ec11b862ac0a5fdb67e7158fb5e15342a7c /tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
parente0b9c581b815996ce1b278e3cb5fd94ab5489f8d (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.cpp55
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;