diff options
| author | Ulf Hermann <ulf.hermann@qt.io> | 2023-11-07 15:16:32 +0100 |
|---|---|---|
| committer | Ulf Hermann <ulf.hermann@qt.io> | 2023-11-09 19:12:37 +0100 |
| commit | 3ea55bf398412d373daab9c92b1498f45de70e96 (patch) | |
| tree | f78259ffe54637f5d790d4511235981ceb3d14fb /src | |
| parent | 6c1391911275ba84848647e05b8daa5a10638f1c (diff) | |
QtQml: Fix some problems with deep aliases
We cannot get the property cache for an inline component the usual way
during type compilation. We have to ask the compilation unit for it.
Guard against still not being able to retrieve the property cache for
any reason. Abort the compilation rather than crashing.
Also, unify the setting of property attributes. Those should really work
the same way everywhere.
Finally, disallow writing aliases to value type properties where the
property holding the value type itself is not writable.
Pick-to: 6.6 6.5 6.2
Task-number: QTBUG-115579
Change-Id: I029eb56a9a390085d0c696a787a64c48acf0d620
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src')
| -rw-r--r-- | src/qml/jsruntime/qv4executablecompilationunit.cpp | 9 | ||||
| -rw-r--r-- | src/qml/jsruntime/qv4executablecompilationunit_p.h | 1 | ||||
| -rw-r--r-- | src/qml/qml/qqmlpropertycachecreator_p.h | 89 | ||||
| -rw-r--r-- | src/qml/qml/qqmltypecompiler_p.h | 9 |
4 files changed, 74 insertions, 34 deletions
diff --git a/src/qml/jsruntime/qv4executablecompilationunit.cpp b/src/qml/jsruntime/qv4executablecompilationunit.cpp index e71568b2d8..c0c5f341e5 100644 --- a/src/qml/jsruntime/qv4executablecompilationunit.cpp +++ b/src/qml/jsruntime/qv4executablecompilationunit.cpp @@ -501,6 +501,15 @@ int ExecutableCompilationUnit::totalObjectCount() const { return inlineComponentData[*icRootName].totalObjectCount; } +ResolvedTypeReference *ExecutableCompilationUnit::resolvedType(QMetaType type) const +{ + for (ResolvedTypeReference *ref : std::as_const(resolvedTypes)) { + if (ref->type().typeId() == type) + return ref; + } + return nullptr; +} + int ExecutableCompilationUnit::totalParserStatusCount() const { if (!icRootName) return m_totalParserStatusCount; diff --git a/src/qml/jsruntime/qv4executablecompilationunit_p.h b/src/qml/jsruntime/qv4executablecompilationunit_p.h index f7a491c740..5ad3838658 100644 --- a/src/qml/jsruntime/qv4executablecompilationunit_p.h +++ b/src/qml/jsruntime/qv4executablecompilationunit_p.h @@ -144,6 +144,7 @@ public: QVector<QQmlRefPointer<QQmlScriptData>> dependentScripts; ResolvedTypeReferenceMap resolvedTypes; ResolvedTypeReference *resolvedType(int id) const { return resolvedTypes.value(id); } + ResolvedTypeReference *resolvedType(QMetaType type) const; bool verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) const; diff --git a/src/qml/qml/qqmlpropertycachecreator_p.h b/src/qml/qml/qqmlpropertycachecreator_p.h index 05e669a856..efd897ad4e 100644 --- a/src/qml/qml/qqmlpropertycachecreator_p.h +++ b/src/qml/qml/qqmlpropertycachecreator_p.h @@ -887,53 +887,74 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor const QQmlPropertyData *targetProperty = targetCache->property(coreIndex); Q_ASSERT(targetProperty); + const QMetaType targetPropType = targetProperty->propType(); + + const auto resolveType = [](QMetaType targetPropType) { + if (targetPropType.flags() & QMetaType::IsEnumeration) + return targetPropType.underlyingType(); + else + return targetPropType; + }; + + const auto populateWithPropertyData = [&](const QQmlPropertyData *property) { + *type = resolveType(property->propType()); + writable = property->isWritable(); + resettable = property->isResettable(); + bindable = property->isBindable(); + + // Copy type flags + propertyFlags->copyPropertyTypeFlags(property->flags()); + if (property->isVarProperty()) + propertyFlags->setType(QQmlPropertyData::Flags::QVariantType); + }; + // for deep aliases, valueTypeIndex is always set - if (!QQmlMetaType::isValueType(targetProperty->propType()) && valueTypeIndex != -1) { + if (!QQmlMetaType::isValueType(targetPropType) && valueTypeIndex != -1) { // deep alias property - *type = targetProperty->propType(); - QQmlPropertyCache::ConstPtr typeCache = QQmlMetaType::propertyCacheForType(*type); - Q_ASSERT(typeCache); - const QQmlPropertyData *typeProperty = typeCache->property(valueTypeIndex); - if (typeProperty == nullptr) { - return qQmlCompileError(alias.referenceLocation, - QQmlPropertyCacheCreatorBase::tr("Invalid alias target")); + QQmlPropertyCache::ConstPtr typeCache + = QQmlMetaType::propertyCacheForType(targetPropType); + + if (!typeCache) { + // See if it's a half-resolved composite type + if (const QV4::ResolvedTypeReference *typeRef + = objectContainer->resolvedType(targetPropType)) { + typeCache = typeRef->typePropertyCache(); + } } - *type = typeProperty->propType(); - writable = typeProperty->isWritable(); - resettable = typeProperty->isResettable(); - bindable = typeProperty->isBindable(); + const QQmlPropertyData *typeProperty = typeCache + ? typeCache->property(valueTypeIndex) + : nullptr; + if (typeProperty == nullptr) { + return qQmlCompileError( + alias.referenceLocation, + QQmlPropertyCacheCreatorBase::tr("Invalid alias target")); + } + populateWithPropertyData(typeProperty); } else { // value type or primitive type or enum - *type = targetProperty->propType(); - - writable = targetProperty->isWritable(); - resettable = targetProperty->isResettable(); - bindable = targetProperty->isBindable(); + populateWithPropertyData(targetProperty); if (valueTypeIndex != -1) { - const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForValueType(*type); - if (valueTypeMetaObject->property(valueTypeIndex).isEnumType()) - *type = QMetaType::fromType<int>(); - else - *type = valueTypeMetaObject->property(valueTypeIndex).metaType(); - } else { - if (targetProperty->isEnum()) { - *type = QMetaType::fromType<int>(); - } else { - // Copy type flags - propertyFlags->copyPropertyTypeFlags(targetProperty->flags()); - - if (targetProperty->isVarProperty()) - propertyFlags->setType(QQmlPropertyData::Flags::QVariantType); - } + const QMetaObject *valueTypeMetaObject + = QQmlMetaType::metaObjectForValueType(*type); + const QMetaProperty valueTypeMetaProperty + = valueTypeMetaObject->property(valueTypeIndex); + *type = resolveType(valueTypeMetaProperty.metaType()); + + // We can only write or reset the value type property if we can write + // the value type itself. + resettable = writable && valueTypeMetaProperty.isResettable(); + writable = writable && valueTypeMetaProperty.isWritable(); + + bindable = valueTypeMetaProperty.isBindable(); } } } - propertyFlags->setIsWritable(!(alias.hasFlag(QV4::CompiledData::Alias::IsReadOnly)) - && writable); + propertyFlags->setIsWritable( + writable && !alias.hasFlag(QV4::CompiledData::Alias::IsReadOnly)); propertyFlags->setIsResettable(resettable); propertyFlags->setIsBindable(bindable); return QQmlError(); diff --git a/src/qml/qml/qqmltypecompiler_p.h b/src/qml/qml/qqmltypecompiler_p.h index a379946664..2e183ed837 100644 --- a/src/qml/qml/qqmltypecompiler_p.h +++ b/src/qml/qml/qqmltypecompiler_p.h @@ -108,6 +108,15 @@ public: return resolvedTypes->value(id); } + QV4::ResolvedTypeReference *resolvedType(QMetaType type) const + { + for (QV4::ResolvedTypeReference *ref : std::as_const(*resolvedTypes)) { + if (ref->type().typeId() == type) + return ref; + } + return nullptr; + } + QQmlType qmlTypeForComponent(const QString &inlineComponentName = QString()) const; private: |
