aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2023-08-17 12:18:29 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2023-08-21 18:52:07 +0000
commit71f7338f0c6fe5db72bc0fb59527b3ad52fc1bd2 (patch)
tree2cfa0ab18c0ea2a6bf162cb5cf99843232bb8de1
parentb8db58e7b367a79f508dc20eaa54ebfe9de68f9f (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.h8
-rw-r--r--src/qml/qml/qqmlpropertycachecreator_p.h30
-rw-r--r--src/qml/qml/qqmltypecompiler.cpp4
-rw-r--r--src/qml/qml/qqmltypedata.cpp16
-rw-r--r--tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp50
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);