diff options
Diffstat (limited to 'src/qml/qml/qqmltype_p_p.h')
-rw-r--r-- | src/qml/qml/qqmltype_p_p.h | 280 |
1 files changed, 187 insertions, 93 deletions
diff --git a/src/qml/qml/qqmltype_p_p.h b/src/qml/qml/qqmltype_p_p.h index 2a375baa83..2bf83ddb8b 100644 --- a/src/qml/qml/qqmltype_p_p.h +++ b/src/qml/qml/qqmltype_p_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2019 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QQMLTYPE_P_P_H #define QQMLTYPE_P_P_H @@ -57,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 *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(); } @@ -92,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; @@ -105,10 +89,13 @@ public: return regType == QQmlType::CompositeType || regType == QQmlType::CompositeSingletonType; } - QQmlType resolveCompositeBaseType(QQmlEnginePrivate *engine) const; - QQmlPropertyCache *compositePropertyCache(QQmlEnginePrivate *engine) const; + bool isValueType() const + { + return regType == QQmlType::CppType && !(typeId.flags() & QMetaType::PointerToQObject); + } - QQmlType::RegistrationType regType; + QQmlType resolveCompositeBaseType(QQmlEnginePrivate *engine) const; + QQmlPropertyCache::ConstPtr compositePropertyCache(QQmlEnginePrivate *engine) const; struct QQmlCppTypeData { @@ -125,71 +112,155 @@ public: const QMetaObject *attachedPropertiesType; int propertyValueSourceCast; int propertyValueInterceptorCast; + int finalizerCast; bool registerEnumClassesUnscoped; + bool registerEnumsFromRelatedTypes; + bool constructValueType; + bool populateValueType; }; 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; @@ -200,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; }; |