diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2023-08-17 12:18:29 +0200 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2023-08-21 18:52:07 +0000 |
commit | 71f7338f0c6fe5db72bc0fb59527b3ad52fc1bd2 (patch) | |
tree | 2cfa0ab18c0ea2a6bf162cb5cf99843232bb8de1 | |
parent | b8db58e7b367a79f508dc20eaa54ebfe9de68f9f (diff) |
QtQml: Correctly resolve aliases to aliases when loading .qmlc files
We need to loop the objects until all property caches are resolved. We
cannot assume the property caches to be complete right away.
Amends commit 2d7fe23b41aa3fd719b7bc8aa585ab799e4a0c39.
Fixes: QTBUG-116148
Change-Id: I407675cd1ebf8067d1b387542b4ecca8100d9b34
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
(cherry picked from commit 487bd23ee8aa7e06f411da796294ef497fc5bd9c)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r-- | src/qml/qml/qqmlcomponentandaliasresolver_p.h | 8 | ||||
-rw-r--r-- | src/qml/qml/qqmlpropertycachecreator_p.h | 30 | ||||
-rw-r--r-- | src/qml/qml/qqmltypecompiler.cpp | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmltypedata.cpp | 16 | ||||
-rw-r--r-- | tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp | 50 |
5 files changed, 88 insertions, 20 deletions
diff --git a/src/qml/qml/qqmlcomponentandaliasresolver_p.h b/src/qml/qml/qqmlcomponentandaliasresolver_p.h index 74e395f966..5ac4ab210f 100644 --- a/src/qml/qml/qqmlcomponentandaliasresolver_p.h +++ b/src/qml/qml/qqmlcomponentandaliasresolver_p.h @@ -53,7 +53,8 @@ private: void allocateNamedObjects(CompiledObject *object) const; void setObjectId(int index) const; [[nodiscard]] bool markAsComponent(int index) const; - [[nodiscard]] AliasResolutionResult resolveAliasesInObject(int objectIndex, QQmlError *error); + [[nodiscard]] AliasResolutionResult resolveAliasesInObject( + const CompiledObject &component, int objectIndex, QQmlError *error); [[nodiscard]] bool wrapImplicitComponent(CompiledBinding *binding); [[nodiscard]] QQmlError findAndRegisterImplicitComponents( @@ -381,13 +382,14 @@ QQmlError QQmlComponentAndAliasResolver<ObjectContainer>::resolveAliases(int com for (int objectIndex: std::as_const(m_objectsWithAliases)) { QQmlError error; - const auto result = resolveAliasesInObject(objectIndex, &error); + const auto &component = *m_compiler->objectAt(componentIndex); + const auto result = resolveAliasesInObject(component, objectIndex, &error); if (error.isValid()) return error; if (result == AllAliasesResolved) { QQmlError error = aliasCacheCreator.appendAliasesToPropertyCache( - *m_compiler->objectAt(componentIndex), objectIndex, m_enginePrivate); + component, objectIndex, m_enginePrivate); if (error.isValid()) return error; atLeastOneAliasResolved = true; diff --git a/src/qml/qml/qqmlpropertycachecreator_p.h b/src/qml/qml/qqmlpropertycachecreator_p.h index 568e5cac0f..df49fe714f 100644 --- a/src/qml/qml/qqmlpropertycachecreator_p.h +++ b/src/qml/qml/qqmlpropertycachecreator_p.h @@ -735,6 +735,18 @@ inline QMetaType QQmlPropertyCacheCreator<ObjectContainer>::metaTypeForParameter return param.isList() ? compilationUnit->typeIds.listId : compilationUnit->typeIds.id; } +template <typename ObjectContainer, typename CompiledObject> +int objectForId(const ObjectContainer *objectContainer, const CompiledObject &component, int id) +{ + for (quint32 i = 0, count = component.namedObjectsInComponentCount(); i < count; ++i) { + const int candidateIndex = component.namedObjectsInComponentTable()[i]; + const CompiledObject &candidate = *objectContainer->objectAt(candidateIndex); + if (candidate.objectId() == id) + return candidateIndex; + } + return -1; +} + template <typename ObjectContainer> class QQmlPropertyCacheAliasCreator { @@ -751,7 +763,6 @@ private: const CompiledObject &component, const QV4::CompiledData::Alias &alias, QMetaType *type, QTypeRevision *version, QQmlPropertyData::Flags *propertyFlags, QQmlEnginePrivate *enginePriv); - int objectForId(const CompiledObject &component, int id) const; QQmlPropertyCacheVector *propertyCaches; const ObjectContainer *objectContainer; @@ -783,7 +794,8 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor QVarLengthArray<const QV4::CompiledData::Alias *, 4> seenAliases({lastAlias}); do { - const int targetObjectIndex = objectForId(component, lastAlias->targetObjectId()); + const int targetObjectIndex = objectForId( + objectContainer, component, lastAlias->targetObjectId()); Q_ASSERT(targetObjectIndex >= 0); const CompiledObject *targetObject = objectContainer->objectAt(targetObjectIndex); Q_ASSERT(targetObject); @@ -806,7 +818,7 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor component, *lastAlias, type, version, propertyFlags, enginePriv); } - const int targetObjectIndex = objectForId(component, alias.targetObjectId()); + const int targetObjectIndex = objectForId(objectContainer, component, alias.targetObjectId()); Q_ASSERT(targetObjectIndex >= 0); const CompiledObject &targetObject = *objectContainer->objectAt(targetObjectIndex); @@ -938,18 +950,6 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesTo return QQmlError(); } -template <typename ObjectContainer> -inline int QQmlPropertyCacheAliasCreator<ObjectContainer>::objectForId(const CompiledObject &component, int id) const -{ - for (quint32 i = 0, count = component.namedObjectsInComponentCount(); i < count; ++i) { - const int candidateIndex = component.namedObjectsInComponentTable()[i]; - const CompiledObject &candidate = *objectContainer->objectAt(candidateIndex); - if (candidate.objectId() == id) - return candidateIndex; - } - return -1; -} - QT_END_NAMESPACE #endif // QQMLPROPERTYCACHECREATOR_P_H diff --git a/src/qml/qml/qqmltypecompiler.cpp b/src/qml/qml/qqmltypecompiler.cpp index 7b9ee544ea..afd6d5ccd9 100644 --- a/src/qml/qml/qqmltypecompiler.cpp +++ b/src/qml/qml/qqmltypecompiler.cpp @@ -807,8 +807,10 @@ bool QQmlComponentAndAliasResolver<QQmlTypeCompiler>::wrapImplicitComponent(QmlI template<> typename QQmlComponentAndAliasResolver<QQmlTypeCompiler>::AliasResolutionResult QQmlComponentAndAliasResolver<QQmlTypeCompiler>::resolveAliasesInObject( - int objectIndex, QQmlError *error) + const CompiledObject &component, int objectIndex, QQmlError *error) { + Q_UNUSED(component); + const QmlIR::Object * const obj = m_compiler->objectAt(objectIndex); if (!obj->aliasCount()) return AllAliasesResolved; diff --git a/src/qml/qml/qqmltypedata.cpp b/src/qml/qml/qqmltypedata.cpp index 0c95f135df..885831a546 100644 --- a/src/qml/qml/qqmltypedata.cpp +++ b/src/qml/qml/qqmltypedata.cpp @@ -198,7 +198,7 @@ void QQmlComponentAndAliasResolver<QV4::ExecutableCompilationUnit>::setObjectId( template<> typename QQmlComponentAndAliasResolver<QV4::ExecutableCompilationUnit>::AliasResolutionResult QQmlComponentAndAliasResolver<QV4::ExecutableCompilationUnit>::resolveAliasesInObject( - int objectIndex, QQmlError *error) + const CompiledObject &component, int objectIndex, QQmlError *error) { const CompiledObject *obj = m_compiler->objectAt(objectIndex); for (auto alias = obj->aliasesBegin(), end = obj->aliasesEnd(); alias != end; ++alias) { @@ -206,6 +206,20 @@ QQmlComponentAndAliasResolver<QV4::ExecutableCompilationUnit>::resolveAliasesInO *error = qQmlCompileError( alias->referenceLocation, tr("Unresolved alias found")); return NoAliasResolved; } + + if (alias->isAliasToLocalAlias() || alias->encodedMetaPropertyIndex == -1) + continue; + + const int targetObjectIndex + = objectForId(m_compiler, component, alias->targetObjectId()); + const int coreIndex + = QQmlPropertyIndex::fromEncoded(alias->encodedMetaPropertyIndex).coreIndex(); + + QQmlPropertyCache::ConstPtr targetCache = m_propertyCaches->at(targetObjectIndex); + Q_ASSERT(targetCache); + + if (!targetCache->property(coreIndex)) + return SomeAliasesResolved; } return AllAliasesResolved; diff --git a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp index b7737c5a75..6f899f21c7 100644 --- a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp +++ b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp @@ -34,6 +34,7 @@ private slots: void recompileAfterDirectoryChange(); void fileSelectors(); void localAliases(); + void aliasToAlias(); void cacheResources(); void stableOrderOfDependentCompositeTypes(); void singletonDependency(); @@ -675,6 +676,55 @@ void tst_qmldiskcache::localAliases() } } +void tst_qmldiskcache::aliasToAlias() +{ + QQmlEngine engine; + + TestCompiler testCompiler(&engine); + QVERIFY(testCompiler.tempDir.isValid()); + + const QByteArray contents = QByteArrayLiteral(R"( + import QML + QtObject { + id: foo + readonly property alias myAlias: bar.prop + + property QtObject o: QtObject { + id: bar + + property QtObject o: QtObject { + id: baz + readonly property int value: 100 + } + + readonly property alias prop: baz.value + } + } + )"); + + { + testCompiler.clearCache(); + QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString)); + QVERIFY2(testCompiler.verify(), qPrintable(testCompiler.lastErrorString)); + } + + { + CleanlyLoadingComponent component(&engine, testCompiler.testFilePath); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + QCOMPARE(obj->property("myAlias").toInt(), 100); + } + + engine.clearComponentCache(); + + { + CleanlyLoadingComponent component(&engine, testCompiler.testFilePath); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + QCOMPARE(obj->property("myAlias").toInt(), 100); + } +} + static QSet<QString> entrySet(const QDir &dir) { const auto &list = dir.entryList(QDir::Files | QDir::NoDotAndDotDot); |