diff options
Diffstat (limited to 'src/qml/qml/qqmltype_p_p.h')
-rw-r--r-- | src/qml/qml/qqmltype_p_p.h | 234 |
1 files changed, 180 insertions, 54 deletions
diff --git a/src/qml/qml/qqmltype_p_p.h b/src/qml/qml/qqmltype_p_p.h index d2b282955f..2bf83ddb8b 100644 --- a/src/qml/qml/qqmltype_p_p.h +++ b/src/qml/qml/qqmltype_p_p.h @@ -21,32 +21,52 @@ #include <private/qqmlrefcount_p.h> #include <private/qqmlpropertycache_p.h> #include <private/qqmlmetatype_p.h> +#include <private/qqmltypeloader_p.h> +#include <private/qv4executablecompilationunit_p.h> +#include <private/qv4engine_p.h> #include <QAtomicInteger> QT_BEGIN_NAMESPACE -class QQmlTypePrivate : public QQmlRefCount +class QQmlTypePrivate final : public QQmlRefCounted<QQmlTypePrivate> { Q_DISABLE_COPY_MOVE(QQmlTypePrivate) public: + struct ProxyMetaObjects + { + ~ProxyMetaObjects() + { + for (const QQmlProxyMetaObject::ProxyData &metaObject : data) + free(metaObject.metaObject); + } + + QList<QQmlProxyMetaObject::ProxyData> data; + bool containsRevisionedAttributes = false; + }; + + struct Enums + { + ~Enums() { qDeleteAll(scopedEnums); } + + QStringHash<int> enums; + QStringHash<int> scopedEnumIndex; // maps from enum name to index in scopedEnums + QList<QStringHash<int> *> scopedEnums; + }; + QQmlTypePrivate(QQmlType::RegistrationType type); - void init() const; - void initEnums(QQmlEnginePrivate *engine) const; - void insertEnums(const QMetaObject *metaObject) const; - void insertEnumsFromPropertyCache(const QQmlPropertyCache::ConstPtr &cache) const; - void setContainingType(QQmlType *containingType); + const ProxyMetaObjects *init() const; QUrl sourceUrl() const { switch (regType) { case QQmlType::CompositeType: - return extraData.fd->url; + return extraData.compositeTypeData; case QQmlType::CompositeSingletonType: - return extraData.sd->singletonInstanceInfo->url; + return extraData.singletonTypeData->singletonInstanceInfo->url; case QQmlType::InlineComponentType: - return extraData.id->url; + return extraData.inlineComponentTypeData; default: return QUrl(); } @@ -56,7 +76,7 @@ public: { for (const QQmlTypePrivate *d = this; d; d = d->resolveCompositeBaseType(engine).d.data()) { if (d->regType == QQmlType::CppType) - return d->extraData.cd->attachedPropertiesType ? d : nullptr; + return d->extraData.cppTypeData->attachedPropertiesType ? d : nullptr; if (d->regType != QQmlType::CompositeType) return nullptr; @@ -69,11 +89,14 @@ public: return regType == QQmlType::CompositeType || regType == QQmlType::CompositeSingletonType; } + bool isValueType() const + { + return regType == QQmlType::CppType && !(typeId.flags() & QMetaType::PointerToQObject); + } + QQmlType resolveCompositeBaseType(QQmlEnginePrivate *engine) const; QQmlPropertyCache::ConstPtr compositePropertyCache(QQmlEnginePrivate *engine) const; - QQmlType::RegistrationType regType; - struct QQmlCppTypeData { int allocationSize; @@ -98,66 +121,146 @@ public: struct QQmlSingletonTypeData { - QQmlType::SingletonInstanceInfo *singletonInstanceInfo; + QQmlType::SingletonInstanceInfo::ConstPtr singletonInstanceInfo; QObject *(*extFunc)(QObject *); const QMetaObject *extMetaObject; }; - struct QQmlCompositeTypeData - { - QUrl url; - }; - - struct QQmlInlineTypeData - { - QUrl url = QUrl(); - // The containing type stores a pointer to the inline component type - // Using QQmlType here would create a reference cycle - // As the inline component type cannot outlive the containing type - // this should still be fine - QQmlTypePrivate const * containingType = nullptr; - QString inlineComponentName = QString(); - int objectId = -1; - }; - - using QQmlSequenceTypeData = QMetaSequence; + int index = -1; union extraData { - QQmlCppTypeData* cd; - QQmlSingletonTypeData* sd; - QQmlCompositeTypeData* fd; - QQmlInlineTypeData* id; - QQmlSequenceTypeData* ld; + extraData() {} // QQmlTypePrivate() does the actual construction. + ~extraData() {} // ~QQmlTypePrivate() does the actual destruction. + + QQmlCppTypeData *cppTypeData; + QQmlSingletonTypeData *singletonTypeData; + QUrl compositeTypeData; + QUrl inlineComponentTypeData; + QMetaSequence sequentialContainerTypeData; + const char *interfaceTypeData; } extraData; + static_assert(sizeof(extraData) == sizeof(void *)); - const char *iid; QHashedString module; QString name; QString elementName; QMetaType typeId; QMetaType listId; + QQmlType::RegistrationType regType; QTypeRevision version; - QTypeRevision revision; - mutable bool containsRevisionedAttributes; - mutable QQmlType superType; - const QMetaObject *baseMetaObject; - - int index; - mutable QAtomicInteger<bool> isSetup; - mutable QAtomicInteger<bool> isEnumFromCacheSetup; - mutable QAtomicInteger<bool> isEnumFromBaseSetup; - mutable bool haveSuperType; - mutable QList<QQmlProxyMetaObject::ProxyData> metaObjects; - mutable QStringHash<int> enums; - mutable QStringHash<int> scopedEnumIndex; // maps from enum name to index in scopedEnums - mutable QList<QStringHash<int>*> scopedEnums; + QTypeRevision revision = QTypeRevision::zero(); + const QMetaObject *baseMetaObject = nullptr; void setName(const QString &uri, const QString &element); - mutable QHash<QString, int> namesToInlineComponentObjectIndex; - mutable QHash<int, QQmlType> objectIdToICType; + + template<typename String> + static int enumValue( + const QQmlRefPointer<const QQmlTypePrivate> &d, QQmlEnginePrivate *engine, + const String &name, bool *ok) + { + return doGetEnumValue(d, engine, [&](const QQmlTypePrivate::Enums *enums) { + return enums->enums.value(name); + }, ok); + } + + template<typename String> + static int scopedEnumIndex( + const QQmlRefPointer<const QQmlTypePrivate> &d, QQmlEnginePrivate *engine, + const String &name, bool *ok) + { + return doGetEnumValue(d, engine, [&](const QQmlTypePrivate::Enums *enums) { + return enums->scopedEnumIndex.value(name); + }, ok); + } + + template<typename String> + static int scopedEnumValue( + const QQmlRefPointer<const QQmlTypePrivate> &d, QQmlEnginePrivate *engine, int index, + const String &name, bool *ok) + { + return doGetEnumValue(d, engine, [&](const QQmlTypePrivate::Enums *enums) { + Q_ASSERT(index > -1 && index < enums->scopedEnums.size()); + return enums->scopedEnums.at(index)->value(name); + }, ok); + } + + template<typename String1, typename String2> + static int scopedEnumValue( + const QQmlRefPointer<const QQmlTypePrivate> &d, QQmlEnginePrivate *engine, + const String1 &scopedEnumName, const String2 &name, bool *ok) + { + return doGetEnumValue(d, engine, [&](const QQmlTypePrivate::Enums *enums) -> const int * { + const int *rv = enums->scopedEnumIndex.value(scopedEnumName); + if (!rv) + return nullptr; + + const int index = *rv; + Q_ASSERT(index > -1 && index < enums->scopedEnums.size()); + return enums->scopedEnums.at(index)->value(name); + }, ok); + } + + const QMetaObject *metaObject() const + { + if (isValueType()) + return metaObjectForValueType(); + + const QQmlTypePrivate::ProxyMetaObjects *proxies = init(); + return proxies->data.isEmpty() + ? baseMetaObject + : proxies->data.constFirst().metaObject; + } + + const QMetaObject *metaObjectForValueType() const + { + Q_ASSERT(isValueType()); + + // Prefer the extension meta object, if any. + // Extensions allow registration of non-gadget value types. + if (const QMetaObject *extensionMetaObject = extraData.cppTypeData->extMetaObject) { + // This may be a namespace even if the original metaType isn't. + // You can do such things with QML_FOREIGN declarations. + if (extensionMetaObject->metaType().flags() & QMetaType::IsGadget) + return extensionMetaObject; + } + + if (baseMetaObject) { + // This may be a namespace even if the original metaType isn't. + // You can do such things with QML_FOREIGN declarations. + if (baseMetaObject->metaType().flags() & QMetaType::IsGadget) + return baseMetaObject; + } + + return nullptr; + } + + static QQmlType compositeQmlType( + const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit, + QQmlTypeLoader *typeLoader, const QString &type) + { + Q_ASSERT(typeLoader); + + const QQmlType qmltype + = unit->typeNameCache->query<QQmlImport::AllowRecursion>(type, typeLoader).type; + if (!qmltype.isValid()) + return qmltype; + + if (qmltype.isInlineComponentType() + && !QQmlMetaType::obtainCompilationUnit(qmltype.typeId())) { + // If it seems to be an IC type, make sure there is an actual + // compilation unit for it. We create inline component types speculatively. + return QQmlType(); + } + + return qmltype; + } private: - ~QQmlTypePrivate() override; + mutable QAtomicPointer<const ProxyMetaObjects> proxyMetaObjects; + mutable QAtomicPointer<const Enums> enums; + + ~QQmlTypePrivate(); + friend class QQmlRefCounted<QQmlTypePrivate>; struct EnumInfo { QStringList path; @@ -168,6 +271,29 @@ private: bool scoped; }; + template<typename Op> + static int doGetEnumValue( + const QQmlRefPointer<const QQmlTypePrivate> &d, QQmlEnginePrivate *engine, + Op &&op, bool *ok) + { + Q_ASSERT(ok); + if (d) { + if (const QQmlTypePrivate::Enums *enums = d->initEnums(engine)) { + if (const int *rv = op(enums)) { + *ok = true; + return *rv; + } + } + } + + *ok = false; + return -1; + } + + const Enums *initEnums(QQmlEnginePrivate *engine) const; + void insertEnums(Enums *enums, const QMetaObject *metaObject) const; + void insertEnumsFromPropertyCache(Enums *enums, const QQmlPropertyCache::ConstPtr &cache) const; + void createListOfPossibleConflictingItems(const QMetaObject *metaObject, QList<EnumInfo> &enumInfoList, QStringList path) const; void createEnumConflictReport(const QMetaObject *metaObject, const QString &conflictingKey) const; }; |