aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2025-08-19 15:25:48 +0200
committerUlf Hermann <ulf.hermann@qt.io>2025-09-02 09:14:58 +0200
commit9148ab4d8dd2fe4221aca1f1e2af1ad17835b6bd (patch)
tree6df960d0ae87f7ea9ae3841fe44643bfae6e4940 /tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
parent28377160bec02d735f2391fbba34f3a1c50b21b2 (diff)
QtQml: Store detached Sequence objects on the JS heap
While the Sequence 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. We don't have to store the sequence on the JS heap if it cannot store a QObject. Only lists of variants or pointers are affected. This independently fixes QTBUG-129972 for 6.8 where VariantAssociationObject does not exist, yet. This is because the detached sequence shown in that bug won't need to be written back to anymore in order to stay up to date. Pick-to: 6.10 6.9 6.8 Fixes: QTBUG-129972 Task-number: QTBUG-139025 Change-Id: Ib469c6c65f2f96041e2ad2fd106f8cd60a182e13 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.cpp32
1 files changed, 28 insertions, 4 deletions
diff --git a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
index 8bddd2cca0..7e116e9d6f 100644
--- a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
+++ b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
@@ -1762,9 +1762,15 @@ void tst_QmlCppCodegen::detachedReferences()
QVERIFY(collectable2);
QSignalSpy spy2(collectable2, &QObject::destroyed);
+ const QVariantList list = d->getList();
+ QObject *collectable3 = list[2].value<QObject *>();
+ QVERIFY(collectable3);
+ QSignalSpy spy3(collectable3, &QObject::destroyed);
+
// The detached containers retain their types.
QCOMPARE(d->property("markedMap").metaType(), QMetaType::fromType<QVariantMap>());
QCOMPARE(d->property("markedHash").metaType(), QMetaType::fromType<QVariantHash>());
+ QCOMPARE(d->property("markedList").metaType(), QMetaType::fromType<QVariantList>());
engine.collectGarbage();
QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
@@ -1772,9 +1778,10 @@ void tst_QmlCppCodegen::detachedReferences()
QCOMPARE(spy1.count(), 0);
QCOMPARE(spy2.count(), 0);
+ QCOMPARE(spy3.count(), 0);
- // Resetting the hash alone does not cause collectible1 to be collected
- // because it's also in the map (recursively).
+ // Resetting the hash alone does not cause the collectibles to be collected
+ // because they're also in the map and the list (recursively).
d->setProperty("markedHash", QVariant());
engine.collectGarbage();
@@ -1783,15 +1790,30 @@ void tst_QmlCppCodegen::detachedReferences()
QCOMPARE(spy1.count(), 0);
QCOMPARE(spy2.count(), 0);
+ QCOMPARE(spy3.count(), 0);
+ // Resetting the map still does not cause the collectibles to be collected
+ // because they're also in the list (recursively).
d->setProperty("markedMap", QVariant());
engine.collectGarbage();
QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
+ QCOMPARE(spy1.count(), 0);
+ QCOMPARE(spy2.count(), 0);
+ QCOMPARE(spy3.count(), 0);
+
+ // Resetting the list finally causes everything to be collected.
+ d->setProperty("markedList", QVariant());
+
+ engine.collectGarbage();
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
+
QCOMPARE(spy1.count(), 1);
QCOMPARE(spy2.count(), 1);
+ QCOMPARE(spy3.count(), 1);
}
void tst_QmlCppCodegen::dialogButtonBox()
@@ -3421,11 +3443,13 @@ void tst_QmlCppCodegen::listConversion()
QStringList strings = o->property("s").value<QStringList>();
QCOMPARE(strings, QStringList({u"Horst 1"_s, u"Horst 2"_s, u"Horst 3"_s}));
+ // Since this is stored as list<var>, the exact types can't be retained.
+ // For JavaScript any number is double, and any nullptr is just null.
QVariantList vars = o->property("v").toList();
QCOMPARE(vars, QVariantList({
QString(),
- QVariant::fromValue<qsizetype>(3),
- QVariant::fromValue<Person *>(nullptr)
+ QVariant::fromValue<double>(3),
+ QVariant::fromValue(nullptr)
}));
QCOMPARE(o->property("numbers").value<QList<int>>(), (QList<int>{1, 2}));