diff options
Diffstat (limited to 'src/qml/qml/qqmlpropertycachecreator_p.h')
-rw-r--r-- | src/qml/qml/qqmlpropertycachecreator_p.h | 529 |
1 files changed, 253 insertions, 276 deletions
diff --git a/src/qml/qml/qqmlpropertycachecreator_p.h b/src/qml/qml/qqmlpropertycachecreator_p.h index e58d8ece1b..4d49ca6ed4 100644 --- a/src/qml/qml/qqmlpropertycachecreator_p.h +++ b/src/qml/qml/qqmlpropertycachecreator_p.h @@ -21,8 +21,14 @@ #include <private/qqmltypedata_p.h> #include <private/inlinecomponentutils_p.h> #include <private/qqmlsourcecoordinate_p.h> +#include <private/qqmlsignalnames_p.h> #include <QScopedValueRollback> + +#if QT_CONFIG(regularexpression) +#include <QtCore/qregularexpression.h> +#endif + #include <vector> QT_BEGIN_NAMESPACE @@ -66,12 +72,62 @@ struct QQmlPropertyCacheCreatorBase public: static QAtomicInt Q_AUTOTEST_EXPORT classIndexCounter; - static QMetaType metaTypeForPropertyType(QV4::CompiledData::BuiltinType type); - static QMetaType listTypeForPropertyType(QV4::CompiledData::BuiltinType type); + static QMetaType metaTypeForPropertyType(QV4::CompiledData::CommonType type) + { + switch (type) { + case QV4::CompiledData::CommonType::Void: return QMetaType(); + case QV4::CompiledData::CommonType::Var: return QMetaType::fromType<QVariant>(); + case QV4::CompiledData::CommonType::Int: return QMetaType::fromType<int>(); + case QV4::CompiledData::CommonType::Bool: return QMetaType::fromType<bool>(); + case QV4::CompiledData::CommonType::Real: return QMetaType::fromType<qreal>(); + case QV4::CompiledData::CommonType::String: return QMetaType::fromType<QString>(); + case QV4::CompiledData::CommonType::Url: return QMetaType::fromType<QUrl>(); + case QV4::CompiledData::CommonType::Time: return QMetaType::fromType<QTime>(); + case QV4::CompiledData::CommonType::Date: return QMetaType::fromType<QDate>(); + case QV4::CompiledData::CommonType::DateTime: return QMetaType::fromType<QDateTime>(); +#if QT_CONFIG(regularexpression) + case QV4::CompiledData::CommonType::RegExp: return QMetaType::fromType<QRegularExpression>(); +#else + case QV4::CompiledData::CommonType::RegExp: return QMetaType(); +#endif + case QV4::CompiledData::CommonType::Rect: return QMetaType::fromType<QRectF>(); + case QV4::CompiledData::CommonType::Point: return QMetaType::fromType<QPointF>(); + case QV4::CompiledData::CommonType::Size: return QMetaType::fromType<QSizeF>(); + case QV4::CompiledData::CommonType::Invalid: break; + }; + return QMetaType {}; + } + + static QMetaType listTypeForPropertyType(QV4::CompiledData::CommonType type) + { + switch (type) { + case QV4::CompiledData::CommonType::Void: return QMetaType(); + case QV4::CompiledData::CommonType::Var: return QMetaType::fromType<QList<QVariant>>(); + case QV4::CompiledData::CommonType::Int: return QMetaType::fromType<QList<int>>(); + case QV4::CompiledData::CommonType::Bool: return QMetaType::fromType<QList<bool>>(); + case QV4::CompiledData::CommonType::Real: return QMetaType::fromType<QList<qreal>>(); + case QV4::CompiledData::CommonType::String: return QMetaType::fromType<QList<QString>>(); + case QV4::CompiledData::CommonType::Url: return QMetaType::fromType<QList<QUrl>>(); + case QV4::CompiledData::CommonType::Time: return QMetaType::fromType<QList<QTime>>(); + case QV4::CompiledData::CommonType::Date: return QMetaType::fromType<QList<QDate>>(); + case QV4::CompiledData::CommonType::DateTime: return QMetaType::fromType<QList<QDateTime>>(); +#if QT_CONFIG(regularexpression) + case QV4::CompiledData::CommonType::RegExp: return QMetaType::fromType<QList<QRegularExpression>>(); +#else + case QV4::CompiledData::CommonType::RegExp: return QMetaType(); +#endif + case QV4::CompiledData::CommonType::Rect: return QMetaType::fromType<QList<QRectF>>(); + case QV4::CompiledData::CommonType::Point: return QMetaType::fromType<QList<QPointF>>(); + case QV4::CompiledData::CommonType::Size: return QMetaType::fromType<QList<QSizeF>>(); + case QV4::CompiledData::CommonType::Invalid: break; + }; + return QMetaType {}; + } + static bool canCreateClassNameTypeByUrl(const QUrl &url); static QByteArray createClassNameTypeByUrl(const QUrl &url); - static QByteArray createClassNameForInlineComponent(const QUrl &baseUrl, int icId); + static QByteArray createClassNameForInlineComponent(const QUrl &baseUrl, const QString &name); struct IncrementalResult { // valid if and only if an error occurred @@ -115,14 +171,6 @@ public: */ QQmlError verifyNoICCycle(); - /*! - \internal - Fills the property caches for the CompiledObjects by - calling buildMetaObjectsIncrementally until it can no - longer resume. - */ - QQmlError buildMetaObjects(); - enum class VMEMetaObjectIsRequired { Maybe, Always @@ -165,7 +213,7 @@ inline QQmlPropertyCacheCreator<ObjectContainer>::QQmlPropertyCacheCreator(QQmlP , typeClassName(typeClassName) , currentRoot(-1) { - propertyCaches->resize(objectContainer->objectCount()); + propertyCaches->resetAndResize(objectContainer->objectCount()); using namespace icutils; @@ -179,7 +227,7 @@ inline QQmlPropertyCacheCreator<ObjectContainer>::QQmlPropertyCacheCreator(QQmlP } // create a graph on inline components referencing inline components - std::vector<Node> nodes; + std::vector<icutils::Node> nodes; nodes.resize(allICs.size()); std::iota(nodes.begin(), nodes.end(), 0); AdjacencyList adjacencyList; @@ -233,20 +281,6 @@ QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectsIncrementally() } template <typename ObjectContainer> -inline QQmlError -QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjects() -{ - QQmlError error = verifyNoICCycle(); - if (error.isValid()) - return error; - QQmlPropertyCacheCreatorBase::IncrementalResult result; - do { - result = buildMetaObjectsIncrementally(); - } while (result.canResume); - return result.error; -} - -template <typename ObjectContainer> inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context, VMEMetaObjectIsRequired isVMERequired) { auto isAddressable = [](const QUrl &url) { @@ -277,7 +311,10 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecur auto *typeRef = objectContainer->resolvedType(obj->inheritedTypeNameIndex); Q_ASSERT(typeRef); QQmlPropertyCache::ConstPtr baseTypeCache = typeRef->createPropertyCache(); - QQmlError error = createMetaObject(context.referencingObjectIndex, obj, baseTypeCache); + QQmlError error = baseTypeCache + ? createMetaObject(context.referencingObjectIndex, obj, baseTypeCache) + : qQmlCompileError(binding->location, QQmlPropertyCacheCreatorBase::tr( + "Type cannot be used for 'on' assignment")); if (error.isValid()) return error; } @@ -367,7 +404,13 @@ inline QQmlPropertyCache::ConstPtr QQmlPropertyCacheCreator<ObjectContainer>::pr } } - return typeRef->createPropertyCache(); + if (QQmlPropertyCache::ConstPtr propertyCache = typeRef->createPropertyCache()) + return propertyCache; + *error = qQmlCompileError( + obj->location, + QQmlPropertyCacheCreatorBase::tr("Type '%1' cannot declare new members.") + .arg(stringAt(obj->inheritedTypeNameIndex))); + return nullptr; } else if (const QV4::CompiledData::Binding *binding = context.instantiatingBinding) { if (binding->isAttachedProperty()) { auto *typeRef = objectContainer->resolvedType( @@ -375,8 +418,9 @@ inline QQmlPropertyCache::ConstPtr QQmlPropertyCacheCreator<ObjectContainer>::pr Q_ASSERT(typeRef); QQmlType qmltype = typeRef->type(); if (!qmltype.isValid()) { - imports->resolveType(stringAt(binding->propertyNameIndex), - &qmltype, nullptr, nullptr, nullptr); + imports->resolveType( + QQmlTypeLoader::get(enginePrivate), stringAt(binding->propertyNameIndex), + &qmltype, nullptr, nullptr); } const QMetaObject *attachedMo = qmltype.attachedPropertiesType(enginePrivate); @@ -385,23 +429,6 @@ inline QQmlPropertyCache::ConstPtr QQmlPropertyCacheCreator<ObjectContainer>::pr return nullptr; } return QQmlMetaType::propertyCache(attachedMo); - } else if (binding->isGroupProperty()) { - const auto *obj = objectContainer->objectAt(binding->value.objectIndex); - if (!stringAt(obj->inheritedTypeNameIndex).isEmpty()) - return nullptr; - - for (int i = 0, end = objectContainer->objectCount(); i != end; ++i) { - const auto *ext = objectContainer->objectAt(i); - if (ext->idNameIndex != binding->propertyNameIndex) - continue; - - if (ext->inheritedTypeNameIndex == 0) - return nullptr; - - QQmlBindingInstantiationContext pendingContext(i, &(*binding), QString(), nullptr); - pendingGroupPropertyBindings->append(pendingContext); - return nullptr; - } } } return nullptr; @@ -472,8 +499,13 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject( // For property change signal override detection. // We prepopulate a set of signal names which already exist in the object, // and throw an error if there is a signal/method defined as an override. - QSet<QString> seenSignals; - seenSignals << QStringLiteral("destroyed") << QStringLiteral("parentChanged") << QStringLiteral("objectNameChanged"); + // TODO: Remove AllowOverride once we can. No override should be allowed. + enum class AllowOverride { No, Yes }; + QHash<QString, AllowOverride> seenSignals { + { QStringLiteral("destroyed"), AllowOverride::No }, + { QStringLiteral("parentChanged"), AllowOverride::No }, + { QStringLiteral("objectNameChanged"), AllowOverride::No } + }; const QQmlPropertyCache *parentCache = cache.data(); while ((parentCache = parentCache->parent().data())) { if (int pSigCount = parentCache->signalCount()) { @@ -484,7 +516,15 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject( for (QQmlPropertyCache::StringCache::ConstIterator iter = parentCache->stringCache.begin(); iter != parentCache->stringCache.end(); ++iter) { if (currPSig == (*iter).second) { - seenSignals.insert(iter.key()); + if (currPSig->isOverridableSignal()) { + const qsizetype oldSize = seenSignals.size(); + AllowOverride &entry = seenSignals[iter.key()]; + if (seenSignals.size() != oldSize) + entry = AllowOverride::Yes; + } else { + seenSignals[iter.key()] = AllowOverride::No; + } + break; } } @@ -498,8 +538,9 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject( for ( ; p != pend; ++p) { auto flags = QQmlPropertyData::defaultSignalFlags(); - QString changedSigName = stringAt(p->nameIndex) + QLatin1String("Changed"); - seenSignals.insert(changedSigName); + const QString changedSigName = + QQmlSignalNames::propertyNameToChangedSignalName(stringAt(p->nameIndex)); + seenSignals[changedSigName] = AllowOverride::No; cache->appendSignal(changedSigName, flags, effectiveMethodIndex++); } @@ -509,8 +550,9 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject( for ( ; a != aend; ++a) { auto flags = QQmlPropertyData::defaultSignalFlags(); - QString changedSigName = stringAt(a->nameIndex()) + QLatin1String("Changed"); - seenSignals.insert(changedSigName); + const QString changedSigName = + QQmlSignalNames::propertyNameToChangedSignalName(stringAt(a->nameIndex())); + seenSignals[changedSigName] = AllowOverride::No; cache->appendSignal(changedSigName, flags, effectiveMethodIndex++); } @@ -562,10 +604,26 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject( flags.setHasArguments(true); QString signalName = stringAt(s->nameIndex); - if (seenSignals.contains(signalName)) - return qQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Duplicate signal name: invalid override of property change signal or superclass signal")); - seenSignals.insert(signalName); - + const auto it = seenSignals.find(signalName); + if (it == seenSignals.end()) { + seenSignals[signalName] = AllowOverride::No; + } else { + // TODO: Remove the AllowOverride::Yes branch once we can. + QQmlError message = qQmlCompileError( + s->location, + QQmlPropertyCacheCreatorBase::tr( + "Duplicate signal name: " + "invalid override of property change signal or superclass signal")); + switch (*it) { + case AllowOverride::No: + return message; + case AllowOverride::Yes: + message.setUrl(objectContainer->url()); + enginePrivate->warning(message); + *it = AllowOverride::No; // No further overriding allowed. + break; + } + } cache->appendSignal(signalName, flags, effectiveMethodIndex++, paramCount?paramTypes.constData():nullptr, names); } @@ -578,8 +636,23 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject( auto flags = QQmlPropertyData::defaultSlotFlags(); const QString slotName = stringAt(function->nameIndex); - if (seenSignals.contains(slotName)) - return qQmlCompileError(function->location, QQmlPropertyCacheCreatorBase::tr("Duplicate method name: invalid override of property change signal or superclass signal")); + const auto it = seenSignals.constFind(slotName); + if (it != seenSignals.constEnd()) { + // TODO: Remove the AllowOverride::Yes branch once we can. + QQmlError message = qQmlCompileError( + function->location, + QQmlPropertyCacheCreatorBase::tr( + "Duplicate method name: " + "invalid override of property change signal or superclass signal")); + switch (*it) { + case AllowOverride::No: + return message; + case AllowOverride::Yes: + message.setUrl(objectContainer->url()); + enginePrivate->warning(message); + break; + } + } // Note: we don't append slotName to the seenSignals list, since we don't // protect against overriding change signals or methods with properties. @@ -614,58 +687,53 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject( QTypeRevision propertyTypeVersion = QTypeRevision::zero(); QQmlPropertyData::Flags propertyFlags; - const QV4::CompiledData::BuiltinType type = p->builtinType(); + const QV4::CompiledData::CommonType type = p->commonType(); if (p->isList()) - propertyFlags.type = QQmlPropertyData::Flags::QListType; - else if (type == QV4::CompiledData::BuiltinType::Var) - propertyFlags.type = QQmlPropertyData::Flags::VarPropertyType; + propertyFlags.setType(QQmlPropertyData::Flags::QListType); + else if (type == QV4::CompiledData::CommonType::Var) + propertyFlags.setType(QQmlPropertyData::Flags::VarPropertyType); - if (type != QV4::CompiledData::BuiltinType::InvalidBuiltin) { + if (type != QV4::CompiledData::CommonType::Invalid) { propertyType = p->isList() ? listTypeForPropertyType(type) : metaTypeForPropertyType(type); } else { - Q_ASSERT(!p->isBuiltinType()); + Q_ASSERT(!p->isCommonType()); QQmlType qmltype; bool selfReference = false; - if (!imports->resolveType(stringAt(p->builtinTypeOrTypeNameIndex()), &qmltype, nullptr, nullptr, - nullptr, QQmlType::AnyRegistrationType, &selfReference)) { + if (!imports->resolveType( + QQmlTypeLoader::get(enginePrivate), + stringAt(p->commonTypeOrTypeNameIndex()), &qmltype, nullptr, nullptr, + nullptr, QQmlType::AnyRegistrationType, &selfReference)) { return qQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Invalid property type")); } // inline components are not necessarily valid yet - Q_ASSERT(qmltype.isValid() || qmltype.isInlineComponentType()); + Q_ASSERT(qmltype.isValid()); if (qmltype.isComposite() || qmltype.isInlineComponentType()) { - CompositeMetaTypeIds typeIds; + QQmlType compositeType; if (qmltype.isInlineComponentType()) { - auto objectId = qmltype.inlineComponentId(); - auto containingType = qmltype.containingType(); - if (containingType.isValid()) { - auto icType = containingType.lookupInlineComponentById(objectId); - typeIds = {icType.typeId(), icType.qListTypeId()}; - } else { - typeIds = {}; - } - if (!typeIds.isValid()) // type has not been registered yet, we must be in containing type - typeIds = objectContainer->typeIdsForComponent(objectId); - Q_ASSERT(typeIds.isValid()); + compositeType = qmltype; + Q_ASSERT(compositeType.isValid()); } else if (selfReference) { - typeIds = objectContainer->typeIdsForComponent(); + compositeType = objectContainer->qmlTypeForComponent(); } else { - QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl()); + // compositeType may not be the same type as qmlType because multiple engines + // may load different types for the same document. Therefore we have to ask + // our engine's type loader here. + QQmlRefPointer<QQmlTypeData> tdata + = enginePrivate->typeLoader.getType(qmltype.sourceUrl()); Q_ASSERT(tdata); Q_ASSERT(tdata->isComplete()); - - auto compilationUnit = tdata->compilationUnit(); - typeIds = compilationUnit->typeIdsForComponent(); + compositeType = tdata->compilationUnit()->qmlTypeForComponent(); } if (p->isList()) { - propertyType = typeIds.listId; + propertyType = compositeType.qListTypeId(); } else { - propertyType = typeIds.id; + propertyType = compositeType.typeId(); } } else { if (p->isList()) @@ -676,11 +744,9 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject( } if (p->isList()) - propertyFlags.type = QQmlPropertyData::Flags::QListType; + propertyFlags.setType(QQmlPropertyData::Flags::QListType); else if (propertyType.flags().testFlag(QMetaType::PointerToQObject)) - propertyFlags.type = QQmlPropertyData::Flags::QObjectDerivedType; - else - propertyFlags.type = QQmlPropertyData::Flags::ValueType; + propertyFlags.setType(QQmlPropertyData::Flags::QObjectDerivedType); } if (!p->isReadOnly() && !propertyType.flags().testFlag(QMetaType::IsQmlList)) @@ -701,50 +767,56 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject( } template <typename ObjectContainer> -inline QMetaType QQmlPropertyCacheCreator<ObjectContainer>::metaTypeForParameter(const QV4::CompiledData::ParameterType ¶m, - QString *customTypeName) +inline QMetaType QQmlPropertyCacheCreator<ObjectContainer>::metaTypeForParameter( + const QV4::CompiledData::ParameterType ¶m, QString *customTypeName) { - const quint32 typeId = param.typeNameIndexOrBuiltinType(); - if (param.indexIsBuiltinType()) { + const quint32 typeId = param.typeNameIndexOrCommonType(); + if (param.indexIsCommonType()) { // built-in type if (param.isList()) - return listTypeForPropertyType(QV4::CompiledData::BuiltinType(typeId)); - return metaTypeForPropertyType(QV4::CompiledData::BuiltinType(typeId)); + return listTypeForPropertyType(QV4::CompiledData::CommonType(typeId)); + return metaTypeForPropertyType(QV4::CompiledData::CommonType(typeId)); } // lazily resolved type - const QString typeName = stringAt(param.typeNameIndexOrBuiltinType()); + const QString typeName = stringAt(param.typeNameIndexOrCommonType()); if (customTypeName) *customTypeName = typeName; QQmlType qmltype; bool selfReference = false; - if (!imports->resolveType(typeName, &qmltype, nullptr, nullptr, nullptr, - QQmlType::AnyRegistrationType, &selfReference)) + if (!imports->resolveType( + &enginePrivate->typeLoader, typeName, &qmltype, nullptr, nullptr, nullptr, + QQmlType::AnyRegistrationType, &selfReference)) return QMetaType(); if (!qmltype.isComposite()) { const QMetaType typeId = param.isList() ? qmltype.qListTypeId() : qmltype.typeId(); if (!typeId.isValid() && qmltype.isInlineComponentType()) { - const int objectId = qmltype.inlineComponentId(); - const auto typeIds = objectContainer->typeIdsForComponent(objectId); - return param.isList() ? typeIds.listId : typeIds.id; + const QQmlType qmlType = objectContainer->qmlTypeForComponent(qmltype.elementName()); + return param.isList() ? qmlType.qListTypeId() : qmlType.typeId(); } else { return typeId; } } if (selfReference) { - const auto typeIds = objectContainer->typeIdsForComponent(); - return param.isList() ? typeIds.listId : typeIds.id; + const QQmlType qmlType = objectContainer->qmlTypeForComponent(); + return param.isList() ? qmlType.qListTypeId() : qmlType.typeId(); } - QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl()); - Q_ASSERT(tdata); - Q_ASSERT(tdata->isComplete()); - - auto compilationUnit = tdata->compilationUnit(); + return param.isList() ? qmltype.qListTypeId() : qmltype.typeId(); +} - 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> @@ -753,126 +825,27 @@ class QQmlPropertyCacheAliasCreator public: typedef typename ObjectContainer::CompiledObject CompiledObject; - QQmlPropertyCacheAliasCreator(QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer); - - void appendAliasPropertiesToMetaObjects(QQmlEnginePrivate *enginePriv); - - QQmlError appendAliasesToPropertyCache(const CompiledObject &component, int objectIndex, QQmlEnginePrivate *enginePriv); + QQmlPropertyCacheAliasCreator( + QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer); + QQmlError appendAliasesToPropertyCache( + const CompiledObject &component, int objectIndex, QQmlEnginePrivate *enginePriv); private: - void appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex, QQmlEnginePrivate *enginePriv); - QQmlError propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, QMetaType *type, QTypeRevision *version, QQmlPropertyData::Flags *propertyFlags, QQmlEnginePrivate *enginePriv); - - void collectObjectsWithAliasesRecursively(int objectIndex, QVector<int> *objectsWithAliases) const; - - int objectForId(const CompiledObject &component, int id) const; + QQmlError propertyDataForAlias( + const CompiledObject &component, const QV4::CompiledData::Alias &alias, QMetaType *type, + QTypeRevision *version, QQmlPropertyData::Flags *propertyFlags, + QQmlEnginePrivate *enginePriv); QQmlPropertyCacheVector *propertyCaches; const ObjectContainer *objectContainer; }; template <typename ObjectContainer> -inline QQmlPropertyCacheAliasCreator<ObjectContainer>::QQmlPropertyCacheAliasCreator(QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer) +inline QQmlPropertyCacheAliasCreator<ObjectContainer>::QQmlPropertyCacheAliasCreator( + QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer) : propertyCaches(propertyCaches) , objectContainer(objectContainer) { - -} - -template <typename ObjectContainer> -inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertiesToMetaObjects(QQmlEnginePrivate *enginePriv) -{ - // skip the root object (index 0) as that one does not have a first object index originating - // from a binding. - for (int i = 1; i < objectContainer->objectCount(); ++i) { - const CompiledObject &component = *objectContainer->objectAt(i); - if (!component.hasFlag(QV4::CompiledData::Object::IsComponent)) - continue; - - const auto rootBinding = component.bindingsBegin(); - appendAliasPropertiesInMetaObjectsWithinComponent(component, rootBinding->value.objectIndex, enginePriv); - } - - const int rootObjectIndex = 0; - appendAliasPropertiesInMetaObjectsWithinComponent(*objectContainer->objectAt(rootObjectIndex), rootObjectIndex, enginePriv); -} - -template <typename ObjectContainer> -inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex, QQmlEnginePrivate *enginePriv) -{ - QVector<int> objectsWithAliases; - collectObjectsWithAliasesRecursively(firstObjectIndex, &objectsWithAliases); - if (objectsWithAliases.isEmpty()) - return; - - const auto allAliasTargetsExist = [this, &component](const CompiledObject &object) { - auto alias = object.aliasesBegin(); - auto end = object.aliasesEnd(); - for ( ; alias != end; ++alias) { - Q_ASSERT(alias->hasFlag(QV4::CompiledData::Alias::Resolved)); - - const int targetObjectIndex = objectForId(component, alias->targetObjectId()); - Q_ASSERT(targetObjectIndex >= 0); - - if (alias->isAliasToLocalAlias()) - continue; - - if (alias->encodedMetaPropertyIndex == -1) - continue; - - const QQmlPropertyCache::ConstPtr targetCache - = propertyCaches->at(targetObjectIndex); - Q_ASSERT(targetCache); - - int coreIndex = QQmlPropertyIndex::fromEncoded(alias->encodedMetaPropertyIndex).coreIndex(); - const QQmlPropertyData *targetProperty = targetCache->property(coreIndex); - if (!targetProperty) - return false; - } - return true; - }; - - do { - QVector<int> pendingObjects; - - for (int objectIndex: std::as_const(objectsWithAliases)) { - const CompiledObject &object = *objectContainer->objectAt(objectIndex); - - if (allAliasTargetsExist(object)) { - appendAliasesToPropertyCache(component, objectIndex, enginePriv); - } else { - pendingObjects.append(objectIndex); - } - - } - objectsWithAliases = std::move(pendingObjects); - } while (!objectsWithAliases.isEmpty()); -} - -template <typename ObjectContainer> -inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::collectObjectsWithAliasesRecursively(int objectIndex, QVector<int> *objectsWithAliases) const -{ - const CompiledObject &object = *objectContainer->objectAt(objectIndex); - if (object.aliasCount() > 0) - objectsWithAliases->append(objectIndex); - - // Stop at Component boundary - if (object.hasFlag(QV4::CompiledData::Object::IsComponent) && objectIndex != /*root object*/0) - return; - - auto binding = object.bindingsBegin(); - auto end = object.bindingsEnd(); - for (; binding != end; ++binding) { - switch (binding->type()) { - case QV4::CompiledData::Binding::Type_Object: - case QV4::CompiledData::Binding::Type_AttachedProperty: - case QV4::CompiledData::Binding::Type_GroupProperty: - collectObjectsWithAliasesRecursively(binding->value.objectIndex, objectsWithAliases); - break; - default: - break; - } - } } template <typename ObjectContainer> @@ -893,7 +866,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); @@ -912,10 +886,11 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor lastAlias = targetAlias; } while (lastAlias->isAliasToLocalAlias()); - return propertyDataForAlias(component, *lastAlias, type, version, propertyFlags, enginePriv); + return propertyDataForAlias( + 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); @@ -934,20 +909,20 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor if (referencedType.isValid()) { *type = referencedType.typeId(); if (!type->isValid() && referencedType.isInlineComponentType()) { - int objectId = referencedType.inlineComponentId(); - *type = objectContainer->typeIdsForComponent(objectId).id; + *type = objectContainer->qmlTypeForComponent(referencedType.elementName()).typeId(); Q_ASSERT(type->isValid()); } } else { - *type = typeRef->compilationUnit()->typeIds.id; + *type = typeRef->compilationUnit()->metaType(); } *version = typeRef->version(); - propertyFlags->type = QQmlPropertyData::Flags::QObjectDerivedType; + propertyFlags->setType(QQmlPropertyData::Flags::QObjectDerivedType); } else { int coreIndex = QQmlPropertyIndex::fromEncoded(alias.encodedMetaPropertyIndex).coreIndex(); - int valueTypeIndex = QQmlPropertyIndex::fromEncoded(alias.encodedMetaPropertyIndex).valueTypeIndex(); + int valueTypeIndex = QQmlPropertyIndex::fromEncoded( + alias.encodedMetaPropertyIndex).valueTypeIndex(); QQmlPropertyCache::ConstPtr targetCache = propertyCaches->at(targetObjectIndex); Q_ASSERT(targetCache); @@ -955,53 +930,67 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor const QQmlPropertyData *targetProperty = targetCache->property(coreIndex); Q_ASSERT(targetProperty); + const QMetaType targetPropType = targetProperty->propType(); + + const auto populateWithPropertyData = [&](const QQmlPropertyData *property) { + *type = property->propType(); + writable = property->isWritable(); + resettable = property->isResettable(); + bindable = property->isBindable(); + + if (property->isVarProperty()) + propertyFlags->setType(QQmlPropertyData::Flags::QVariantType); + else + propertyFlags->copyPropertyTypeFlags(property->flags()); + }; + // 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->type = QQmlPropertyData::Flags::QVariantType; - } + const QMetaObject *valueTypeMetaObject + = QQmlMetaType::metaObjectForValueType(*type); + const QMetaProperty valueTypeMetaProperty + = valueTypeMetaObject->property(valueTypeIndex); + *type = 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(); @@ -1047,18 +1036,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 |