From 81c2da0c7ccc361e3cc2206d30aaeb55065a5352 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 8 Apr 2021 13:50:46 +0200 Subject: Do not auto-clean components with live inline components The inline components do not hold a strong reference to their outer type because that would be a reference cycle. Fixes: QTBUG-92236 Change-Id: I6d76a114352653210f0ece6c198cf761d3b4eda1 Reviewed-by: Fabian Kosmale (cherry picked from commit d0d4cc528ba9e3c39c15a2292066dac1d457abd5) Reviewed-by: Qt Cherry-pick Bot --- src/qml/qml/qqmlmetatype.cpp | 12 +++++++++- tests/auto/qml/qqmllanguage/data/Tab1.qml | 9 ++++++++ tests/auto/qml/qqmllanguage/data/bareInline.qml | 9 ++++++++ tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 28 ++++++++++++++++++++++++ 4 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 tests/auto/qml/qqmllanguage/data/Tab1.qml create mode 100644 tests/auto/qml/qqmllanguage/data/bareInline.qml diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 16aafac6d1..f74bec6003 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -1405,6 +1405,16 @@ void QQmlMetaType::unregisterType(int typeIndex) } } +static bool hasActiveInlineComponents(const QQmlTypePrivate *d) +{ + for (const QQmlType &ic : qAsConst(d->objectIdToICType)) { + const QQmlTypePrivate *icPriv = ic.priv(); + if (icPriv && icPriv->count() > 1) + return true; + } + return false; +} + void QQmlMetaType::freeUnusedTypesAndCaches() { QQmlMetaTypeDataPtr data; @@ -1419,7 +1429,7 @@ void QQmlMetaType::freeUnusedTypesAndCaches() QList::Iterator it = data->types.begin(); while (it != data->types.end()) { const QQmlTypePrivate *d = (*it).priv(); - if (d && d->count() == 1) { + if (d && d->count() == 1 && !hasActiveInlineComponents(d)) { deletedAtLeastOneType = true; removeQQmlTypePrivate(data->idToType, d); diff --git a/tests/auto/qml/qqmllanguage/data/Tab1.qml b/tests/auto/qml/qqmllanguage/data/Tab1.qml new file mode 100644 index 0000000000..e1cd6d8c34 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/Tab1.qml @@ -0,0 +1,9 @@ +import QtQuick 2.15 + +Item { + component LeftTab: Item { + } + + component RightTab: Item { + } +} diff --git a/tests/auto/qml/qqmllanguage/data/bareInline.qml b/tests/auto/qml/qqmllanguage/data/bareInline.qml new file mode 100644 index 0000000000..cb79021250 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/bareInline.qml @@ -0,0 +1,9 @@ +import QtQuick 2.9 + +Item { + width: 800 + height: 600 + visible: true + + Tab1.RightTab {} +} diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 3b527a8f50..41fb80d8ed 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -49,6 +49,7 @@ #include #include #include +#include #include "testtypes.h" #include "testhttpserver.h" @@ -337,6 +338,7 @@ private slots: void arrayToContainer(); void qualifiedScopeInCustomParser(); void accessNullPointerPropertyCache(); + void bareInlineComponent(); void checkUncreatableNoReason(); @@ -6248,6 +6250,32 @@ void tst_qqmllanguage::qtbug_85615() QCOMPARE(o->property("resultNull").metaType(), QMetaType(QMetaType::Nullptr)); } +void tst_qqmllanguage::bareInlineComponent() +{ + QQmlEngine engine; + + QQmlComponent c(&engine, testFileUrl("bareInline.qml")); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QScopedPointer o(c.create()); + QVERIFY(!o.isNull()); + + QQmlMetaType::freeUnusedTypesAndCaches(); + + bool tab1Found = false; + const auto types = QQmlMetaType::qmlTypes(); + for (const QQmlType &type : types) { + if (type.elementName() == QStringLiteral("Tab1")) { + QVERIFY(type.module().isEmpty()); + tab1Found = true; + const auto ics = type.priv()->objectIdToICType; + QVERIFY(ics.size() > 0); + for (const QQmlType &ic : ics) + QVERIFY(ic.containingType() == type); + } + } + QVERIFY(tab1Found); +} + QTEST_MAIN(tst_qqmllanguage) #include "tst_qqmllanguage.moc" -- cgit v1.2.3