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 2d7fe23b41
.
Pick-to: 6.6 6.5
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>
This commit is contained in:
parent
5774d9b13b
commit
487bd23ee8
|
@ -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;
|
||||
|
|
|
@ -735,6 +735,18 @@ inline QMetaType QQmlPropertyCacheCreator<ObjectContainer>::metaTypeForParameter
|
|||
: compilationUnit->qmlType.typeId();
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -811,8 +811,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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue