diff options
Diffstat (limited to 'src/qml/qml/qqmlmetatype.cpp')
-rw-r--r-- | src/qml/qml/qqmlmetatype.cpp | 2299 |
1 files changed, 466 insertions, 1833 deletions
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 0f8a850584..c2674b402a 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -37,410 +37,78 @@ ** ****************************************************************************/ -#include <QtQml/qqmlprivate.h> #include "qqmlmetatype_p.h" -#include <private/qqmlproxymetaobject_p.h> -#include <private/qqmlcustomparser_p.h> -#include <private/qhashedstring_p.h> -#include <private/qqmlimport_p.h> - -#include <QtCore/qdebug.h> -#include <QtCore/qstringlist.h> -#include <QtCore/qmetaobject.h> -#include <QtCore/qbitarray.h> -#include <QtCore/qreadwritelock.h> -#include <QtCore/private/qmetaobject_p.h> -#include <QtCore/qloggingcategory.h> - -#include <qmetatype.h> -#include <qobjectdefs.h> -#include <qbytearray.h> -#include <qreadwritelock.h> -#include <qstring.h> -#include <qstringlist.h> -#include <qvector.h> +#include <private/qqmlmetatypedata_p.h> +#include <private/qqmltypemodule_p_p.h> +#include <private/qqmltype_p_p.h> +#include <private/qqmltypeloader_p.h> +#include <private/qqmlextensionplugin_p.h> +#include <private/qv4executablecompilationunit_p.h> -#include <ctype.h> -#include "qqmlcomponent.h" +#include <QtCore/qcoreapplication.h> +#include <QtCore/qmutex.h> +#include <QtCore/qloggingcategory.h> Q_DECLARE_LOGGING_CATEGORY(DBG_DISK_CACHE) QT_BEGIN_NAMESPACE -struct QQmlMetaTypeData +struct LockedData : private QQmlMetaTypeData { - QQmlMetaTypeData(); - ~QQmlMetaTypeData(); - void registerType(QQmlTypePrivate *priv); - QList<QQmlType> types; - QSet<QQmlType> undeletableTypes; - typedef QHash<int, QQmlTypePrivate *> Ids; - Ids idToType; - typedef QHash<QHashedStringRef, QQmlTypePrivate *> Names; - Names nameToType; - typedef QHash<QUrl, QQmlTypePrivate *> Files; //For file imported composite types only - Files urlToType; - Files urlToNonFileImportType; // For non-file imported composite and composite - // singleton types. This way we can locate any - // of them by url, even if it was registered as - // a module via QQmlPrivate::RegisterCompositeType - typedef QHash<const QMetaObject *, QQmlTypePrivate *> MetaObjects; - MetaObjects metaObjectToType; - typedef QHash<int, QQmlMetaType::StringConverter> StringConverters; - StringConverters stringConverters; - - struct VersionedUri { - VersionedUri() - : majorVersion(0) {} - VersionedUri(const QHashedString &uri, int majorVersion) - : uri(uri), majorVersion(majorVersion) {} - bool operator==(const VersionedUri &other) const { - return other.majorVersion == majorVersion && other.uri == uri; - } - QHashedString uri; - int majorVersion; - }; - typedef QHash<VersionedUri, QQmlTypeModule *> TypeModules; - TypeModules uriToModule; - - QBitArray objects; - QBitArray interfaces; - QBitArray lists; - - QList<QQmlPrivate::AutoParentFunction> parentFunctions; - QVector<QQmlPrivate::QmlUnitCacheLookupFunction> lookupCachedQmlUnit; - - QSet<QString> protectedNamespaces; - - QString typeRegistrationNamespace; - - QHash<int, int> qmlLists; - - QHash<const QMetaObject *, QQmlPropertyCache *> propertyCaches; - QQmlPropertyCache *propertyCache(const QMetaObject *metaObject, int minorVersion); - QQmlPropertyCache *propertyCache(const QQmlType &type, int minorVersion); - - void startRecordingTypeRegFailures(QStringList *storage) - { typeRegistrationFailures = storage; } - void stopRecordingTypeRegFailures() - { startRecordingTypeRegFailures(nullptr); } - void recordTypeRegFailure(const QString &message) - { - if (typeRegistrationFailures) - typeRegistrationFailures->append(message); - else - qWarning("%s", message.toUtf8().constData()); - } - -private: - QStringList *typeRegistrationFailures = nullptr; + friend class QQmlMetaTypeDataPtr; }; -struct EnumInfo { - QStringList path; - QString metaObjectName; - QString enumName; - QString enumKey; - QString metaEnumScope; - bool scoped; -}; +Q_GLOBAL_STATIC(LockedData, metaTypeData) +Q_GLOBAL_STATIC(QRecursiveMutex, metaTypeDataLock) -class QQmlTypeModulePrivate +class QQmlMetaTypeDataPtr { + Q_DISABLE_COPY_MOVE(QQmlMetaTypeDataPtr) public: - QQmlTypeModulePrivate() - : minMinorVersion(INT_MAX), maxMinorVersion(0), locked(false) {} - - static QQmlTypeModulePrivate* get(QQmlTypeModule* q) { return q->d; } + QQmlMetaTypeDataPtr() : locker(metaTypeDataLock()), data(metaTypeData()) {} + ~QQmlMetaTypeDataPtr() = default; - QQmlMetaTypeData::VersionedUri uri; + QQmlMetaTypeData &operator*() { return *data; } + QQmlMetaTypeData *operator->() { return data; } + operator QQmlMetaTypeData *() { return data; } - int minMinorVersion; - int maxMinorVersion; - bool locked; + const QQmlMetaTypeData &operator*() const { return *data; } + const QQmlMetaTypeData *operator->() const { return data; } + operator const QQmlMetaTypeData *() const { return data; } - void add(QQmlTypePrivate *); - void remove(const QQmlTypePrivate *type); - - typedef QStringHash<QList<QQmlTypePrivate *> > TypeHash; - TypeHash typeHash; -}; - -Q_GLOBAL_STATIC(QQmlMetaTypeData, metaTypeData) -Q_GLOBAL_STATIC_WITH_ARGS(QMutex, metaTypeDataLock, (QMutex::Recursive)) - -static uint qHash(const QQmlMetaTypeData::VersionedUri &v) -{ - return v.uri.hash() ^ qHash(v.majorVersion); -} + bool isValid() const { return data != nullptr; } -QQmlMetaTypeRegistrationFailureRecorder::QQmlMetaTypeRegistrationFailureRecorder() -{ - metaTypeData()->startRecordingTypeRegFailures(&_failures); -} - -QQmlMetaTypeRegistrationFailureRecorder::~QQmlMetaTypeRegistrationFailureRecorder() -{ - metaTypeData()->stopRecordingTypeRegFailures(); -} - -QQmlMetaTypeData::QQmlMetaTypeData() -{ -} - -QQmlMetaTypeData::~QQmlMetaTypeData() -{ - for (TypeModules::const_iterator i = uriToModule.constBegin(), cend = uriToModule.constEnd(); i != cend; ++i) - delete *i; - for (QHash<const QMetaObject *, QQmlPropertyCache *>::Iterator it = propertyCaches.begin(), end = propertyCaches.end(); - it != end; ++it) - (*it)->release(); -} - -class QQmlTypePrivate -{ - Q_DISABLE_COPY(QQmlTypePrivate) -public: - QQmlTypePrivate(QQmlType::RegistrationType type); - ~QQmlTypePrivate(); - - void init() const; - void initEnums(const QQmlPropertyCache *cache = nullptr) const; - void insertEnums(const QMetaObject *metaObject) const; - void insertEnumsFromPropertyCache(const QQmlPropertyCache *cache) const; - - QAtomicInt refCount; - QQmlType::RegistrationType regType; - - struct QQmlCppTypeData - { - int allocationSize; - void (*newFunc)(void *); - QString noCreationReason; - int parserStatusCast; - QObject *(*extFunc)(QObject *); - const QMetaObject *extMetaObject; - QQmlCustomParser *customParser; - QQmlAttachedPropertiesFunc attachedPropertiesFunc; - const QMetaObject *attachedPropertiesType; - int propertyValueSourceCast; - int propertyValueInterceptorCast; - bool registerEnumClassesUnscoped; - }; - - struct QQmlSingletonTypeData - { - QQmlType::SingletonInstanceInfo *singletonInstanceInfo; - }; - - struct QQmlCompositeTypeData - { - QUrl url; - }; - - union extraData { - QQmlCppTypeData* cd; - QQmlSingletonTypeData* sd; - QQmlCompositeTypeData* fd; - } extraData; - - const char *iid; - QHashedString module; - QString name; - QString elementName; - int version_maj; - int version_min; - int typeId; - int listId; - int revision; - mutable bool containsRevisionedAttributes; - mutable QQmlType superType; - const QMetaObject *baseMetaObject; - - int index; - mutable volatile bool isSetup:1; - mutable volatile bool isEnumFromCacheSetup:1; - mutable volatile bool isEnumFromBaseSetup:1; - mutable bool haveSuperType:1; - 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; - - struct PropertyCacheByMinorVersion - { - PropertyCacheByMinorVersion() : cache(nullptr), minorVersion(-1) {} - explicit PropertyCacheByMinorVersion(QQmlPropertyCache *pc, int ver) : cache(pc), minorVersion(ver) {} - QQmlPropertyCachePtr cache; - int minorVersion; - }; - QVector<PropertyCacheByMinorVersion> propertyCaches; - QQmlPropertyCache *propertyCacheForMinorVersion(int minorVersion) const; - void setPropertyCacheForMinorVersion(int minorVersion, QQmlPropertyCache *cache); private: - void createListOfPossibleConflictingItems(const QMetaObject *metaObject, QList<EnumInfo> &enumInfoList, QStringList path) const; - void createEnumConflictReport(const QMetaObject *metaObject, const QString &conflictingKey) const; + QMutexLocker locker; + LockedData *data = nullptr; }; -void QQmlMetaTypeData::registerType(QQmlTypePrivate *priv) +static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, + const QQmlPrivate::RegisterInterface &type) { - for (int i = 0; i < types.count(); ++i) { - if (!types.at(i).isValid()) { - types[i] = QQmlType(priv); - priv->index = i; - return; - } - } - types.append(QQmlType(priv)); - priv->index = types.count() - 1; -} - -void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e) -{ - if (scriptCallback && scriptApi(e).isUndefined()) { - QJSValue value = scriptCallback(e, e); - if (value.isQObject()) { - QObject *o = value.toQObject(); - // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj) - // should behave identically to QML singleton types. - e->setContextForObject(o, new QQmlContext(e->rootContext(), e)); - } - setScriptApi(e, value); - } else if (qobjectCallback && !qobjectApi(e)) { - QObject *o = qobjectCallback(e, e); - setQObjectApi(e, o); - if (!o) { - qFatal("qmlRegisterSingletonType(): \"%s\" is not available because the callback function returns a null pointer.", qPrintable(typeName)); - } - // if this object can use a property cache, create it now - QQmlData::ensurePropertyCache(e, o); - // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj) - // should behave identically to QML singleton types. - e->setContextForObject(o, new QQmlContext(e->rootContext(), e)); - } else if (!url.isEmpty() && !qobjectApi(e)) { - QQmlComponent component(e, url, QQmlComponent::PreferSynchronous); - QObject *o = component.beginCreate(e->rootContext()); - setQObjectApi(e, o); - if (o) - component.completeCreate(); - } -} - -void QQmlType::SingletonInstanceInfo::destroy(QQmlEngine *e) -{ - // cleans up the engine-specific singleton instances if they exist. - scriptApis.remove(e); - QObject *o = qobjectApis.take(e); - if (o) { - QQmlData *ddata = QQmlData::get(o, false); - if (url.isEmpty() && ddata && ddata->indestructible && ddata->explicitIndestructibleSet) - return; - delete o; - } -} - -void QQmlType::SingletonInstanceInfo::setQObjectApi(QQmlEngine *e, QObject *o) -{ - qobjectApis.insert(e, o); -} - -QObject *QQmlType::SingletonInstanceInfo::qobjectApi(QQmlEngine *e) const -{ - return qobjectApis.value(e); -} - -void QQmlType::SingletonInstanceInfo::setScriptApi(QQmlEngine *e, const QJSValue &v) -{ - scriptApis.insert(e, v); -} - -QJSValue QQmlType::SingletonInstanceInfo::scriptApi(QQmlEngine *e) const -{ - return scriptApis.value(e); -} - -QQmlTypePrivate::QQmlTypePrivate(QQmlType::RegistrationType type) -: refCount(1), regType(type), iid(nullptr), typeId(0), listId(0), revision(0), - containsRevisionedAttributes(false), baseMetaObject(nullptr), - index(-1), isSetup(false), isEnumFromCacheSetup(false), isEnumFromBaseSetup(false), - haveSuperType(false) -{ - switch (type) { - case QQmlType::CppType: - extraData.cd = new QQmlCppTypeData; - extraData.cd->allocationSize = 0; - extraData.cd->newFunc = nullptr; - extraData.cd->parserStatusCast = -1; - extraData.cd->extFunc = nullptr; - extraData.cd->extMetaObject = nullptr; - extraData.cd->customParser = nullptr; - extraData.cd->attachedPropertiesFunc = nullptr; - extraData.cd->attachedPropertiesType = nullptr; - extraData.cd->propertyValueSourceCast = -1; - extraData.cd->propertyValueInterceptorCast = -1; - extraData.cd->registerEnumClassesUnscoped = true; - break; - case QQmlType::SingletonType: - case QQmlType::CompositeSingletonType: - extraData.sd = new QQmlSingletonTypeData; - extraData.sd->singletonInstanceInfo = nullptr; - break; - case QQmlType::InterfaceType: - extraData.cd = nullptr; - break; - case QQmlType::CompositeType: - extraData.fd = new QQmlCompositeTypeData; - break; - default: qFatal("QQmlTypePrivate Internal Error."); - } -} - -QQmlTypePrivate::~QQmlTypePrivate() -{ - qDeleteAll(scopedEnums); - switch (regType) { - case QQmlType::CppType: - delete extraData.cd->customParser; - delete extraData.cd; - break; - case QQmlType::SingletonType: - case QQmlType::CompositeSingletonType: - delete extraData.sd->singletonInstanceInfo; - delete extraData.sd; - break; - case QQmlType::CompositeType: - delete extraData.fd; - break; - default: //Also InterfaceType, because it has no extra data - break; - } -} - -QQmlType::QQmlType(QQmlMetaTypeData *data, const QQmlPrivate::RegisterInterface &interface) - : d(new QQmlTypePrivate(InterfaceType)) -{ - d->iid = interface.iid; - d->typeId = interface.typeId; - d->listId = interface.listId; + auto *d = new QQmlTypePrivate(QQmlType::InterfaceType); + d->iid = type.iid; + d->typeId = type.typeId; + d->listId = type.listId; d->isSetup = true; d->version_maj = 0; d->version_min = 0; data->registerType(d); + return d; } -QQmlType::QQmlType(QQmlMetaTypeData *data, const QString &elementName, const QQmlPrivate::RegisterSingletonType &type) - : d(new QQmlTypePrivate(SingletonType)) +static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName, + const QQmlPrivate::RegisterSingletonType &type) { + auto *d = new QQmlTypePrivate(QQmlType::SingletonType); data->registerType(d); - d->elementName = elementName; - d->module = QString::fromUtf8(type.uri); - + d->setName(QString::fromUtf8(type.uri), elementName); d->version_maj = type.versionMajor; d->version_min = type.versionMinor; - if (type.qobjectApi) { + if (type.qobjectApi || (type.version >= 3 && type.generalizedQobjectApi)) { if (type.version >= 1) // static metaobject added in version 1 d->baseMetaObject = type.instanceMetaObject; if (type.version >= 2) // typeId added in version 2 @@ -449,37 +117,26 @@ QQmlType::QQmlType(QQmlMetaTypeData *data, const QString &elementName, const QQm d->revision = type.revision; } - d->extraData.sd->singletonInstanceInfo = new SingletonInstanceInfo; + d->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo; d->extraData.sd->singletonInstanceInfo->scriptCallback = type.scriptApi; - d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.qobjectApi; + if (type.version >= 3) { + d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.generalizedQobjectApi; + } else { + d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.qobjectApi; + } d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName); d->extraData.sd->singletonInstanceInfo->instanceMetaObject - = (type.qobjectApi && type.version >= 1) ? type.instanceMetaObject : nullptr; -} - -QQmlType::QQmlType(QQmlMetaTypeData *data, const QString &elementName, const QQmlPrivate::RegisterCompositeSingletonType &type) - : d(new QQmlTypePrivate(CompositeSingletonType)) -{ - data->registerType(d); - - d->elementName = elementName; - d->module = QString::fromUtf8(type.uri); - - d->version_maj = type.versionMajor; - d->version_min = type.versionMinor; + = ((type.qobjectApi || (type.version >= 3 && type.generalizedQobjectApi) ) && type.version >= 1) ? type.instanceMetaObject : nullptr; - d->extraData.sd->singletonInstanceInfo = new SingletonInstanceInfo; - d->extraData.sd->singletonInstanceInfo->url = QQmlTypeLoader::normalize(type.url); - d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName); + return d; } -QQmlType::QQmlType(QQmlMetaTypeData *data, const QString &elementName, const QQmlPrivate::RegisterType &type) - : d(new QQmlTypePrivate(CppType)) +static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName, + const QQmlPrivate::RegisterType &type) { + QQmlTypePrivate *d = new QQmlTypePrivate(QQmlType::CppType); data->registerType(d); - - d->elementName = elementName; - d->module = QString::fromUtf8(type.uri); + d->setName(QString::fromUtf8(type.uri), elementName); d->version_maj = type.versionMajor; d->version_min = type.versionMinor; @@ -509,141 +166,41 @@ QQmlType::QQmlType(QQmlMetaTypeData *data, const QString &elementName, const QQm if (indexOfClassInfo != -1 && QString::fromUtf8(d->baseMetaObject->classInfo(indexOfClassInfo).value()) == QLatin1String("false")) d->extraData.cd->registerEnumClassesUnscoped = false; } + + return d; } -QQmlType::QQmlType(QQmlMetaTypeData *data, const QString &elementName, const QQmlPrivate::RegisterCompositeType &type) - : d(new QQmlTypePrivate(CompositeType)) +static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName, + const QQmlPrivate::RegisterCompositeType &type) { + auto *d = new QQmlTypePrivate(QQmlType::CompositeType); data->registerType(d); - - d->elementName = elementName; - - d->module = QString::fromUtf8(type.uri); + d->setName(QString::fromUtf8(type.uri), elementName); d->version_maj = type.versionMajor; d->version_min = type.versionMinor; d->extraData.fd->url = QQmlTypeLoader::normalize(type.url); + return d; } -QQmlType::QQmlType() - : d(nullptr) -{ -} - -QQmlType::QQmlType(const QQmlType &other) - : d(other.d) -{ - if (d) - d->refCount.ref(); -} - -QQmlType &QQmlType::operator =(const QQmlType &other) -{ - if (d != other.d) { - if (d && !d->refCount.deref()) - delete d; - d = other.d; - if (d) - d->refCount.ref(); - } - return *this; -} - -QQmlType::QQmlType(QQmlTypePrivate *priv) - : d(priv) -{ - if (d) - d->refCount.ref(); -} - -QQmlType::~QQmlType() -{ - if (d && !d->refCount.deref()) - delete d; -} - -QHashedString QQmlType::module() const -{ - if (!d) - return QHashedString(); - return d->module; -} - -int QQmlType::majorVersion() const -{ - if (!d) - return -1; - return d->version_maj; -} - -int QQmlType::minorVersion() const +static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName, + const QQmlPrivate::RegisterCompositeSingletonType &type) { - if (!d) - return -1; - return d->version_min; -} - -bool QQmlType::availableInVersion(int vmajor, int vminor) const -{ - Q_ASSERT(vmajor >= 0 && vminor >= 0); - if (!d) - return false; - return vmajor == d->version_maj && vminor >= d->version_min; -} - -bool QQmlType::availableInVersion(const QHashedStringRef &module, int vmajor, int vminor) const -{ - Q_ASSERT(vmajor >= 0 && vminor >= 0); - if (!d) - return false; - return module == d->module && vmajor == d->version_maj && vminor >= d->version_min; -} - -// returns the nearest _registered_ super class -QQmlType QQmlType::superType() const -{ - if (!d) - return QQmlType(); - if (!d->haveSuperType && d->baseMetaObject) { - const QMetaObject *mo = d->baseMetaObject->superClass(); - while (mo && !d->superType.isValid()) { - d->superType = QQmlMetaType::qmlType(mo, d->module, d->version_maj, d->version_min); - mo = mo->superClass(); - } - d->haveSuperType = true; - } - - return d->superType; -} + auto *d = new QQmlTypePrivate(QQmlType::CompositeSingletonType); + data->registerType(d); + d->setName(QString::fromUtf8(type.uri), elementName); -QQmlType QQmlType::resolveCompositeBaseType(QQmlEnginePrivate *engine) const -{ - Q_ASSERT(isComposite()); - if (!engine || !d) - return QQmlType(); - QQmlRefPointer<QQmlTypeData> td(engine->typeLoader.getType(sourceUrl())); - if (td.isNull() || !td->isComplete()) - return QQmlType(); - QV4::CompiledData::CompilationUnit *compilationUnit = td->compilationUnit(); - const QMetaObject *mo = compilationUnit->rootPropertyCache()->firstCppMetaObject(); - return QQmlMetaType::qmlType(mo); -} + d->version_maj = type.versionMajor; + d->version_min = type.versionMinor; -QQmlPropertyCache *QQmlType::compositePropertyCache(QQmlEnginePrivate *engine) const -{ - // similar logic to resolveCompositeBaseType - Q_ASSERT(isComposite()); - if (!engine) - return nullptr; - QQmlRefPointer<QQmlTypeData> td(engine->typeLoader.getType(sourceUrl())); - if (td.isNull() || !td->isComplete()) - return nullptr; - QV4::CompiledData::CompilationUnit *compilationUnit = td->compilationUnit(); - return compilationUnit->rootPropertyCache().data(); + d->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo; + d->extraData.sd->singletonInstanceInfo->url = QQmlTypeLoader::normalize(type.url); + d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName); + return d; } -static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo, - const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd) +void QQmlMetaType::clone(QMetaObjectBuilder &builder, const QMetaObject *mo, + const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd) { // Set classname builder.setClassName(ignoreEnd->className()); @@ -710,918 +267,10 @@ static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo, } } -static bool isPropertyRevisioned(const QMetaObject *mo, int index) -{ - int i = index; - i -= mo->propertyOffset(); - if (i < 0 && mo->d.superdata) - return isPropertyRevisioned(mo->d.superdata, index); - - const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate*>(mo->d.data); - if (i >= 0 && i < mop->propertyCount) { - int handle = mop->propertyData + 3*i; - int flags = mo->d.data[handle + 2]; - - return (flags & Revisioned); - } - - return false; -} - -void QQmlTypePrivate::init() const -{ - if (isSetup) - return; - - QMutexLocker lock(metaTypeDataLock()); - if (isSetup) - return; - - const QMetaObject *mo = baseMetaObject; - if (!mo) { - // version 0 singleton type without metaobject information - return; - } - - if (regType == QQmlType::CppType) { - // Setup extended meta object - // XXX - very inefficient - if (extraData.cd->extFunc) { - QMetaObjectBuilder builder; - clone(builder, extraData.cd->extMetaObject, extraData.cd->extMetaObject, extraData.cd->extMetaObject); - builder.setFlags(QMetaObjectBuilder::DynamicMetaObject); - QMetaObject *mmo = builder.toMetaObject(); - mmo->d.superdata = mo; - QQmlProxyMetaObject::ProxyData data = { mmo, extraData.cd->extFunc, 0, 0 }; - metaObjects << data; - } - } - - mo = mo->d.superdata; - while(mo) { - QQmlTypePrivate *t = metaTypeData()->metaObjectToType.value(mo); - if (t) { - if (t->regType == QQmlType::CppType) { - if (t->extraData.cd->extFunc) { - QMetaObjectBuilder builder; - clone(builder, t->extraData.cd->extMetaObject, t->baseMetaObject, baseMetaObject); - builder.setFlags(QMetaObjectBuilder::DynamicMetaObject); - QMetaObject *mmo = builder.toMetaObject(); - mmo->d.superdata = baseMetaObject; - if (!metaObjects.isEmpty()) - metaObjects.constLast().metaObject->d.superdata = mmo; - QQmlProxyMetaObject::ProxyData data = { mmo, t->extraData.cd->extFunc, 0, 0 }; - metaObjects << data; - } - } - } - mo = mo->d.superdata; - } - - for (int ii = 0; ii < metaObjects.count(); ++ii) { - metaObjects[ii].propertyOffset = - metaObjects.at(ii).metaObject->propertyOffset(); - metaObjects[ii].methodOffset = - metaObjects.at(ii).metaObject->methodOffset(); - } - - // Check for revisioned details - { - const QMetaObject *mo = nullptr; - if (metaObjects.isEmpty()) - mo = baseMetaObject; - else - mo = metaObjects.constFirst().metaObject; - - for (int ii = 0; !containsRevisionedAttributes && ii < mo->propertyCount(); ++ii) { - if (isPropertyRevisioned(mo, ii)) - containsRevisionedAttributes = true; - } - - for (int ii = 0; !containsRevisionedAttributes && ii < mo->methodCount(); ++ii) { - if (mo->method(ii).revision() != 0) - containsRevisionedAttributes = true; - } - } - - isSetup = true; - lock.unlock(); -} - -void QQmlTypePrivate::initEnums(const QQmlPropertyCache *cache) const -{ - if ((isEnumFromBaseSetup || !baseMetaObject) - && (isEnumFromCacheSetup || !cache)) { - return; - } - - init(); - - QMutexLocker lock(metaTypeDataLock()); - - if (!isEnumFromCacheSetup && cache) { - insertEnumsFromPropertyCache(cache); - isEnumFromCacheSetup = true; - } - - if (!isEnumFromBaseSetup && baseMetaObject) { // could be singleton type without metaobject - insertEnums(baseMetaObject); - isEnumFromBaseSetup = true; - } -} - -void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const -{ - // Add any enum values defined by 'related' classes - if (metaObject->d.relatedMetaObjects) { - const auto *related = metaObject->d.relatedMetaObjects; - if (related) { - while (*related) - insertEnums(*related++); - } - } - - QSet<QString> localEnums; - const QMetaObject *localMetaObject = nullptr; - - // Add any enum values defined by this class, overwriting any inherited values - for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) { - QMetaEnum e = metaObject->enumerator(ii); - const bool isScoped = e.isScoped(); - QStringHash<int> *scoped = isScoped ? new QStringHash<int>() : nullptr; - - // We allow enums in sub-classes to overwrite enums from base-classes, such as - // ListView.Center (from enum PositionMode) overwriting Item.Center (from enum TransformOrigin). - // This is acceptable because the _use_ of the enum from the QML side requires qualification - // anyway, i.e. ListView.Center vs. Item.Center. - // However if a class defines two enums with the same value, then that must produce a warning - // because it represents a valid conflict. - if (e.enclosingMetaObject() != localMetaObject) { - localEnums.clear(); - localMetaObject = e.enclosingMetaObject(); - } - - for (int jj = 0; jj < e.keyCount(); ++jj) { - const QString key = QString::fromUtf8(e.key(jj)); - const int value = e.value(jj); - if (!isScoped || (regType == QQmlType::CppType && extraData.cd->registerEnumClassesUnscoped)) { - if (localEnums.contains(key)) { - auto existingEntry = enums.find(key); - if (existingEntry != enums.end() && existingEntry.value() != value) { - qWarning("Previously registered enum will be overwritten due to name clash: %s.%s", metaObject->className(), key.toUtf8().constData()); - createEnumConflictReport(metaObject, key); - } - } else { - localEnums.insert(key); - } - enums.insert(key, value); - } - if (isScoped) - scoped->insert(key, value); - } - - if (isScoped) { - scopedEnums << scoped; - scopedEnumIndex.insert(QString::fromUtf8(e.name()), scopedEnums.count()-1); - } - } -} - -void QQmlTypePrivate::createListOfPossibleConflictingItems(const QMetaObject *metaObject, QList<EnumInfo> &enumInfoList, QStringList path) const -{ - path.append(QString::fromUtf8(metaObject->className())); - - if (metaObject->d.relatedMetaObjects) { - const auto *related = metaObject->d.relatedMetaObjects; - if (related) { - while (*related) - createListOfPossibleConflictingItems(*related++, enumInfoList, path); - } - } - - for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) { - const auto e = metaObject->enumerator(ii); - - for (int jj = 0; jj < e.keyCount(); ++jj) { - const QString key = QString::fromUtf8(e.key(jj)); - - EnumInfo enumInfo; - enumInfo.metaObjectName = QString::fromUtf8(metaObject->className()); - enumInfo.enumName = QString::fromUtf8(e.name()); - enumInfo.enumKey = key; - enumInfo.scoped = e.isScoped(); - enumInfo.path = path; - enumInfo.metaEnumScope = QString::fromUtf8(e.scope()); - enumInfoList.append(enumInfo); - } - } -} - -void QQmlTypePrivate::createEnumConflictReport(const QMetaObject *metaObject, const QString &conflictingKey) const -{ - QList<EnumInfo> enumInfoList; - - if (baseMetaObject) // prefer baseMetaObject if available - metaObject = baseMetaObject; - - if (!metaObject) { // If there is no metaObject at all return early - qWarning() << "No meta object information available. Skipping conflict analysis."; - return; - } - - createListOfPossibleConflictingItems(metaObject, enumInfoList, QStringList()); - - qWarning().noquote() << QLatin1String("Possible conflicting items:"); - // find items with conflicting key - for (const auto i : enumInfoList) { - if (i.enumKey == conflictingKey) - qWarning().noquote().nospace() << " " << i.metaObjectName << "." << i.enumName << "." << i.enumKey << " from scope " - << i.metaEnumScope << " injected by " << i.path.join(QLatin1String("->")); - } -} - -void QQmlTypePrivate::insertEnumsFromPropertyCache(const QQmlPropertyCache *cache) const -{ - const QMetaObject *cppMetaObject = cache->firstCppMetaObject(); - - while (cache && cache->metaObject() != cppMetaObject) { - - int count = cache->qmlEnumCount(); - for (int ii = 0; ii < count; ++ii) { - QStringHash<int> *scoped = new QStringHash<int>(); - QQmlEnumData *enumData = cache->qmlEnum(ii); - - for (int jj = 0; jj < enumData->values.count(); ++jj) { - const QQmlEnumValue &value = enumData->values.at(jj); - enums.insert(value.namedValue, value.value); - scoped->insert(value.namedValue, value.value); - } - scopedEnums << scoped; - scopedEnumIndex.insert(enumData->name, scopedEnums.count()-1); - } - cache = cache->parent(); - } - insertEnums(cppMetaObject); -} - - -QQmlPropertyCache *QQmlTypePrivate::propertyCacheForMinorVersion(int minorVersion) const -{ - for (int i = 0; i < propertyCaches.count(); ++i) - if (propertyCaches.at(i).minorVersion == minorVersion) - return propertyCaches.at(i).cache.data(); - return nullptr; -} - -void QQmlTypePrivate::setPropertyCacheForMinorVersion(int minorVersion, QQmlPropertyCache *cache) -{ - for (int i = 0; i < propertyCaches.count(); ++i) { - if (propertyCaches.at(i).minorVersion == minorVersion) { - propertyCaches[i].cache = cache; - return; - } - } - propertyCaches.append(PropertyCacheByMinorVersion(cache, minorVersion)); -} - -QByteArray QQmlType::typeName() const -{ - if (d) { - if (d->regType == SingletonType || d->regType == CompositeSingletonType) - return d->extraData.sd->singletonInstanceInfo->typeName.toUtf8(); - else if (d->baseMetaObject) - return d->baseMetaObject->className(); - } - return QByteArray(); -} - -QString QQmlType::elementName() const -{ - if (!d) - return QString(); - return d->elementName; -} - -QString QQmlType::qmlTypeName() const -{ - if (!d) - return QString(); - if (d->name.isEmpty()) { - if (!d->module.isEmpty()) - d->name = static_cast<QString>(d->module) + QLatin1Char('/') + d->elementName; - else - d->name = d->elementName; - } - - return d->name; -} - -QObject *QQmlType::create() const -{ - if (!d || !isCreatable()) - return nullptr; - - d->init(); - - QObject *rv = (QObject *)operator new(d->extraData.cd->allocationSize); - d->extraData.cd->newFunc(rv); - - if (rv && !d->metaObjects.isEmpty()) - (void)new QQmlProxyMetaObject(rv, &d->metaObjects); - - return rv; -} - -void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) const -{ - if (!d || !isCreatable()) - return; - - d->init(); - - QObject *rv = (QObject *)operator new(d->extraData.cd->allocationSize + additionalMemory); - d->extraData.cd->newFunc(rv); - - if (rv && !d->metaObjects.isEmpty()) - (void)new QQmlProxyMetaObject(rv, &d->metaObjects); - - *out = rv; - *memory = ((char *)rv) + d->extraData.cd->allocationSize; -} - -QQmlType::SingletonInstanceInfo *QQmlType::singletonInstanceInfo() const -{ - if (!d) - return nullptr; - if (d->regType != SingletonType && d->regType != CompositeSingletonType) - return nullptr; - return d->extraData.sd->singletonInstanceInfo; -} - -QQmlCustomParser *QQmlType::customParser() const -{ - if (!d) - return nullptr; - if (d->regType != CppType) - return nullptr; - return d->extraData.cd->customParser; -} - -QQmlType::CreateFunc QQmlType::createFunction() const -{ - if (!d || d->regType != CppType) - return nullptr; - return d->extraData.cd->newFunc; -} - -QString QQmlType::noCreationReason() const -{ - if (!d || d->regType != CppType) - return QString(); - return d->extraData.cd->noCreationReason; -} - -bool QQmlType::isCreatable() const -{ - return d && d->regType == CppType && d->extraData.cd->newFunc; -} - -QQmlType::ExtensionFunc QQmlType::extensionFunction() const -{ - if (!d || d->regType != CppType) - return nullptr; - return d->extraData.cd->extFunc; -} - -bool QQmlType::isExtendedType() const -{ - if (!d) - return false; - d->init(); - - return !d->metaObjects.isEmpty(); -} - -bool QQmlType::isSingleton() const -{ - return d && (d->regType == SingletonType || d->regType == CompositeSingletonType); -} - -bool QQmlType::isInterface() const -{ - return d && d->regType == InterfaceType; -} - -bool QQmlType::isComposite() const -{ - return d && (d->regType == CompositeType || d->regType == CompositeSingletonType); -} - -bool QQmlType::isCompositeSingleton() const -{ - return d && d->regType == CompositeSingletonType; -} - -int QQmlType::typeId() const -{ - return d ? d->typeId : -1; -} - -int QQmlType::qListTypeId() const -{ - return d ? d->listId : -1; -} - -const QMetaObject *QQmlType::metaObject() const -{ - if (!d) - return nullptr; - d->init(); - - if (d->metaObjects.isEmpty()) - return d->baseMetaObject; - else - return d->metaObjects.constFirst().metaObject; - -} - -const QMetaObject *QQmlType::baseMetaObject() const -{ - return d ? d->baseMetaObject : nullptr; -} - -bool QQmlType::containsRevisionedAttributes() const -{ - if (!d) - return false; - d->init(); - - return d->containsRevisionedAttributes; -} - -int QQmlType::metaObjectRevision() const -{ - return d ? d->revision : -1; -} - -QQmlAttachedPropertiesFunc QQmlType::attachedPropertiesFunction(QQmlEnginePrivate *engine) const -{ - if (!d) - return nullptr; - if (d->regType == CppType) - return d->extraData.cd->attachedPropertiesFunc; - - QQmlType base; - if (d->regType == CompositeType) - base = resolveCompositeBaseType(engine); - return base.attachedPropertiesFunction(engine); -} - -const QMetaObject *QQmlType::attachedPropertiesType(QQmlEnginePrivate *engine) const -{ - if (!d) - return nullptr; - if (d->regType == CppType) - return d->extraData.cd->attachedPropertiesType; - - QQmlType base; - if (d->regType == CompositeType) - base = resolveCompositeBaseType(engine); - return base.attachedPropertiesType(engine); -} - -/* -This is the id passed to qmlAttachedPropertiesById(). This is different from the index -for the case that a single class is registered under two or more names (eg. Item in -Qt 4.7 and QtQuick 1.0). -*/ -int QQmlType::attachedPropertiesId(QQmlEnginePrivate *engine) const -{ - if (!d) - return -1; - if (d->regType == CppType) - return d->extraData.cd->attachedPropertiesType ? d->index : -1; - - QQmlType base; - if (d->regType == CompositeType) - base = resolveCompositeBaseType(engine); - return base.attachedPropertiesId(engine); -} - -int QQmlType::parserStatusCast() const -{ - if (!d || d->regType != CppType) - return -1; - return d->extraData.cd->parserStatusCast; -} - -int QQmlType::propertyValueSourceCast() const -{ - if (!d || d->regType != CppType) - return -1; - return d->extraData.cd->propertyValueSourceCast; -} - -int QQmlType::propertyValueInterceptorCast() const -{ - if (!d || d->regType != CppType) - return -1; - return d->extraData.cd->propertyValueInterceptorCast; -} - -const char *QQmlType::interfaceIId() const -{ - if (!d || d->regType != InterfaceType) - return nullptr; - return d->iid; -} - -int QQmlType::index() const -{ - return d ? d->index : -1; -} - -QUrl QQmlType::sourceUrl() const -{ - if (d) { - if (d->regType == CompositeType) - return d->extraData.fd->url; - else if (d->regType == CompositeSingletonType) - return d->extraData.sd->singletonInstanceInfo->url; - } - return QUrl(); -} - -int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedStringRef &name, bool *ok) const -{ - Q_ASSERT(ok); - if (d) { - const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : nullptr; - - *ok = true; - - d->initEnums(cache); - - int *rv = d->enums.value(name); - if (rv) - return *rv; - } - - *ok = false; - return -1; -} - -int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedCStringRef &name, bool *ok) const -{ - Q_ASSERT(ok); - if (d) { - const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : nullptr; - - *ok = true; - - d->initEnums(cache); - - int *rv = d->enums.value(name); - if (rv) - return *rv; - } - - *ok = false; - return -1; -} - -int QQmlType::enumValue(QQmlEnginePrivate *engine, const QV4::String *name, bool *ok) const -{ - Q_ASSERT(ok); - if (d) { - const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : nullptr; - *ok = true; - - d->initEnums(cache); - - int *rv = d->enums.value(name); - if (rv) - return *rv; - } - - *ok = false; - return -1; -} - -int QQmlType::scopedEnumIndex(QQmlEnginePrivate *engine, const QV4::String *name, bool *ok) const -{ - Q_ASSERT(ok); - if (d) { - const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : nullptr; - *ok = true; - - d->initEnums(cache); - - int *rv = d->scopedEnumIndex.value(name); - if (rv) - return *rv; - } - - *ok = false; - return -1; -} - -int QQmlType::scopedEnumIndex(QQmlEnginePrivate *engine, const QString &name, bool *ok) const -{ - Q_ASSERT(ok); - if (d) { - const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : nullptr; - *ok = true; - - d->initEnums(cache); - - int *rv = d->scopedEnumIndex.value(name); - if (rv) - return *rv; - } - - *ok = false; - return -1; -} - -int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, int index, const QV4::String *name, bool *ok) const -{ - Q_UNUSED(engine) - Q_ASSERT(ok); - *ok = true; - - if (d) { - Q_ASSERT(index > -1 && index < d->scopedEnums.count()); - int *rv = d->scopedEnums.at(index)->value(name); - if (rv) - return *rv; - } - - *ok = false; - return -1; -} - -int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, int index, const QString &name, bool *ok) const -{ - Q_UNUSED(engine) - Q_ASSERT(ok); - *ok = true; - - if (d) { - Q_ASSERT(index > -1 && index < d->scopedEnums.count()); - int *rv = d->scopedEnums.at(index)->value(name); - if (rv) - return *rv; - } - - *ok = false; - return -1; -} - -int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &scopedEnumName, const QByteArray &name, bool *ok) const -{ - Q_ASSERT(ok); - if (d) { - const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : nullptr; - *ok = true; - - d->initEnums(cache); - - int *rv = d->scopedEnumIndex.value(QHashedCStringRef(scopedEnumName.constData(), scopedEnumName.length())); - if (rv) { - int index = *rv; - Q_ASSERT(index > -1 && index < d->scopedEnums.count()); - rv = d->scopedEnums.at(index)->value(QHashedCStringRef(name.constData(), name.length())); - if (rv) - return *rv; - } - } - - *ok = false; - return -1; -} - -int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QStringRef &scopedEnumName, const QStringRef &name, bool *ok) const -{ - Q_ASSERT(ok); - if (d) { - const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : nullptr; - *ok = true; - - d->initEnums(cache); - - int *rv = d->scopedEnumIndex.value(QHashedStringRef(scopedEnumName)); - if (rv) { - int index = *rv; - Q_ASSERT(index > -1 && index < d->scopedEnums.count()); - rv = d->scopedEnums.at(index)->value(QHashedStringRef(name)); - if (rv) - return *rv; - } - } - - *ok = false; - return -1; -} - -void QQmlType::refHandle(QQmlTypePrivate *priv) -{ - if (priv) - priv->refCount.ref(); -} - -void QQmlType::derefHandle(QQmlTypePrivate *priv) -{ - if (priv && !priv->refCount.deref()) - delete priv; -} - -int QQmlType::refCount(QQmlTypePrivate *priv) -{ - if (priv) - return priv->refCount; - return -1; -} - -namespace { -template <typename QQmlTypeContainer> -void removeQQmlTypePrivate(QQmlTypeContainer &container, const QQmlTypePrivate *reference) -{ - for (typename QQmlTypeContainer::iterator it = container.begin(); it != container.end();) { - if (*it == reference) - it = container.erase(it); - else - ++it; - } -} - -struct IsQQmlTypePrivate -{ - const QQmlTypePrivate *reference; - explicit IsQQmlTypePrivate(const QQmlTypePrivate *ref) : reference(ref) {} - - bool operator()(const QQmlTypePrivate *priv) const { return reference == priv; } -}; -} - -QQmlTypeModule::QQmlTypeModule() -: d(new QQmlTypeModulePrivate) -{ -} - -QQmlTypeModule::~QQmlTypeModule() -{ - delete d; d = nullptr; -} - -QString QQmlTypeModule::module() const -{ - return d->uri.uri; -} - -int QQmlTypeModule::majorVersion() const -{ - return d->uri.majorVersion; -} - -int QQmlTypeModule::minimumMinorVersion() const -{ - return d->minMinorVersion; -} - -int QQmlTypeModule::maximumMinorVersion() const -{ - return d->maxMinorVersion; -} - -void QQmlTypeModulePrivate::add(QQmlTypePrivate *type) -{ - int minVersion = type->version_min; - minMinorVersion = qMin(minMinorVersion, minVersion); - maxMinorVersion = qMax(maxMinorVersion, minVersion); - - QList<QQmlTypePrivate *> &list = typeHash[type->elementName]; - for (int ii = 0; ii < list.count(); ++ii) { - Q_ASSERT(list.at(ii)); - if (list.at(ii)->version_min < minVersion) { - list.insert(ii, type); - return; - } - } - list.append(type); -} - -void QQmlTypeModulePrivate::remove(const QQmlTypePrivate *type) -{ - for (TypeHash::ConstIterator elementIt = typeHash.begin(); elementIt != typeHash.end();) { - QList<QQmlTypePrivate *> &list = const_cast<QList<QQmlTypePrivate *> &>(elementIt.value()); - - removeQQmlTypePrivate(list, type); - -#if 0 - if (list.isEmpty()) - elementIt = typeHash.erase(elementIt); - else - ++elementIt; -#else - ++elementIt; -#endif - } -} - -QQmlType QQmlTypeModule::type(const QHashedStringRef &name, int minor) const -{ - QMutexLocker lock(metaTypeDataLock()); - - QList<QQmlTypePrivate *> *types = d->typeHash.value(name); - if (types) { - for (int ii = 0; ii < types->count(); ++ii) - if (types->at(ii)->version_min <= minor) - return QQmlType(types->at(ii)); - } - - return QQmlType(); -} - -QQmlType QQmlTypeModule::type(const QV4::String *name, int minor) const -{ - QMutexLocker lock(metaTypeDataLock()); - - QList<QQmlTypePrivate *> *types = d->typeHash.value(name); - if (types) { - for (int ii = 0; ii < types->count(); ++ii) - if (types->at(ii)->version_min <= minor) - return QQmlType(types->at(ii)); - } - - return QQmlType(); -} - -void QQmlTypeModule::walkCompositeSingletons(const std::function<void(const QQmlType &)> &callback) const -{ - QMutexLocker lock(metaTypeDataLock()); - for (auto typeCandidates = d->typeHash.begin(), end = d->typeHash.end(); - typeCandidates != end; ++typeCandidates) { - for (auto type: typeCandidates.value()) { - if (type->regType == QQmlType::CompositeSingletonType) - callback(QQmlType(type)); - } - } -} - -QQmlTypeModuleVersion::QQmlTypeModuleVersion() -: m_module(nullptr), m_minor(0) -{ -} - -QQmlTypeModuleVersion::QQmlTypeModuleVersion(QQmlTypeModule *module, int minor) -: m_module(module), m_minor(minor) -{ - Q_ASSERT(m_module); - Q_ASSERT(m_minor >= 0); -} - -QQmlTypeModuleVersion::QQmlTypeModuleVersion(const QQmlTypeModuleVersion &o) -: m_module(o.m_module), m_minor(o.m_minor) -{ -} - -QQmlTypeModuleVersion &QQmlTypeModuleVersion::operator=(const QQmlTypeModuleVersion &o) -{ - m_module = o.m_module; - m_minor = o.m_minor; - return *this; -} - -QQmlTypeModule *QQmlTypeModuleVersion::module() const -{ - return m_module; -} - -int QQmlTypeModuleVersion::minorVersion() const -{ - return m_minor; -} - -QQmlType QQmlTypeModuleVersion::type(const QHashedStringRef &name) const -{ - if (!m_module) - return QQmlType(); - return m_module->type(name, m_minor); -} - -QQmlType QQmlTypeModuleVersion::type(const QV4::String *name) const -{ - if (!m_module) - return QQmlType(); - return m_module->type(name, m_minor); -} - -void qmlClearTypeRegistrations() // Declared in qqml.h +void QQmlMetaType::clearTypeRegistrations() { //Only cleans global static, assumed no running engine - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + QQmlMetaTypeDataPtr data; for (QQmlMetaTypeData::TypeModules::const_iterator i = data->uriToModule.constBegin(), cend = data->uriToModule.constEnd(); i != cend; ++i) delete *i; @@ -1630,44 +279,35 @@ void qmlClearTypeRegistrations() // Declared in qqml.h data->idToType.clear(); data->nameToType.clear(); data->urlToType.clear(); + data->typePropertyCaches.clear(); data->urlToNonFileImportType.clear(); data->metaObjectToType.clear(); data->uriToModule.clear(); data->undeletableTypes.clear(); - - QQmlEnginePrivate::baseModulesUninitialized = true; //So the engine re-registers its types -#if QT_CONFIG(library) - qmlClearEnginePlugins(); -#endif -} - -static void unregisterAutoParentFunction(const QQmlPrivate::AutoParentFunction &function) -{ - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); - data->parentFunctions.removeOne(function); } -static int registerAutoParentFunction(const QQmlPrivate::RegisterAutoParent &autoparent) +int QQmlMetaType::registerAutoParentFunction(const QQmlPrivate::RegisterAutoParent &autoparent) { - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + QQmlMetaTypeDataPtr data; data->parentFunctions.append(autoparent.function); return data->parentFunctions.count() - 1; } -QQmlType registerInterface(const QQmlPrivate::RegisterInterface &interface) +void QQmlMetaType::unregisterAutoParentFunction(const QQmlPrivate::AutoParentFunction &function) { - if (interface.version > 0) - qFatal("qmlRegisterType(): Cannot mix incompatible QML versions."); + QQmlMetaTypeDataPtr data; + data->parentFunctions.removeOne(function); +} - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); +QQmlType QQmlMetaType::registerInterface(const QQmlPrivate::RegisterInterface &type) +{ + if (type.version > 0) + qFatal("qmlRegisterType(): Cannot mix incompatible QML versions."); - QQmlType type(data, interface); - QQmlTypePrivate *priv = type.priv(); + QQmlMetaTypeDataPtr data; + QQmlTypePrivate *priv = createQQmlType(data, type); Q_ASSERT(priv); data->idToType.insert(priv->typeId, priv); @@ -1676,14 +316,14 @@ QQmlType registerInterface(const QQmlPrivate::RegisterInterface &interface) if (!priv->elementName.isEmpty()) data->nameToType.insert(priv->elementName, priv); - if (data->interfaces.size() <= interface.typeId) - data->interfaces.resize(interface.typeId + 16); - if (data->lists.size() <= interface.listId) - data->lists.resize(interface.listId + 16); - data->interfaces.setBit(interface.typeId, true); - data->lists.setBit(interface.listId, true); + if (data->interfaces.size() <= type.typeId) + data->interfaces.resize(type.typeId + 16); + if (data->lists.size() <= type.listId) + data->lists.resize(type.listId + 16); + data->interfaces.setBit(type.typeId, true); + data->lists.setBit(type.listId, true); - return type; + return QQmlType(priv); } QString registrationTypeString(QQmlType::RegistrationType typeType) @@ -1701,7 +341,8 @@ QString registrationTypeString(QQmlType::RegistrationType typeType) } // NOTE: caller must hold a QMutexLocker on "data" -bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *data, const char *uri, const QString &typeName, int majorVersion = -1) +bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *data, + const char *uri, const QString &typeName, int majorVersion = -1) { if (!typeName.isEmpty()) { if (typeName.at(0).isLower()) { @@ -1736,7 +377,7 @@ bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *da versionedUri.uri = nameSpace; versionedUri.majorVersion = majorVersion; if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0)){ - if (QQmlTypeModulePrivate::get(qqtm)->locked){ + if (qqtm->isLocked()){ QString failure(QCoreApplication::translate("qmlRegisterType", "Cannot install %1 '%2' into protected module '%3' version '%4'")); data->recordTypeRegFailure(failure.arg(registrationTypeString(typeType)).arg(typeName).arg(nameSpace).arg(majorVersion)); @@ -1755,8 +396,7 @@ QQmlTypeModule *getTypeModule(const QHashedString &uri, int majorVersion, QQmlMe QQmlMetaTypeData::VersionedUri versionedUri(uri, majorVersion); QQmlTypeModule *module = data->uriToModule.value(versionedUri); if (!module) { - module = new QQmlTypeModule; - module->d->uri = versionedUri; + module = new QQmlTypeModule(versionedUri.uri, versionedUri.majorVersion); data->uriToModule.insert(versionedUri, module); } return module; @@ -1792,47 +432,47 @@ void addTypeToData(QQmlTypePrivate *type, QQmlMetaTypeData *data) QQmlTypeModule *module = getTypeModule(mod, type->version_maj, data); Q_ASSERT(module); - module->d->add(type); + module->add(type); } } -QQmlType registerType(const QQmlPrivate::RegisterType &type) +QQmlType QQmlMetaType::registerType(const QQmlPrivate::RegisterType &type) { - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + QQmlMetaTypeDataPtr data; + QString elementName = QString::fromUtf8(type.elementName); if (!checkRegistration(QQmlType::CppType, data, type.uri, elementName, type.versionMajor)) return QQmlType(); - QQmlType dtype(data, elementName, type); + QQmlTypePrivate *priv = createQQmlType(data, elementName, type); - addTypeToData(dtype.priv(), data); + addTypeToData(priv, data); if (!type.typeId) - data->idToType.insert(dtype.typeId(), dtype.priv()); + data->idToType.insert(priv->typeId, priv); - return dtype; + return QQmlType(priv); } -QQmlType registerSingletonType(const QQmlPrivate::RegisterSingletonType &type) +QQmlType QQmlMetaType::registerSingletonType(const QQmlPrivate::RegisterSingletonType &type) { - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + QQmlMetaTypeDataPtr data; + QString typeName = QString::fromUtf8(type.typeName); if (!checkRegistration(QQmlType::SingletonType, data, type.uri, typeName, type.versionMajor)) return QQmlType(); - QQmlType dtype(data, typeName, type); + QQmlTypePrivate *priv = createQQmlType(data, typeName, type); - addTypeToData(dtype.priv(), data); + addTypeToData(priv, data); - return dtype; + return QQmlType(priv); } QQmlType QQmlMetaType::registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingletonType &type) { // Assumes URL is absolute and valid. Checking of user input should happen before the URL enters type. - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + QQmlMetaTypeDataPtr data; + QString typeName = QString::fromUtf8(type.typeName); bool fileImport = false; if (*(type.uri) == '\0') @@ -1840,21 +480,20 @@ QQmlType QQmlMetaType::registerCompositeSingletonType(const QQmlPrivate::Registe if (!checkRegistration(QQmlType::CompositeSingletonType, data, fileImport ? nullptr : type.uri, typeName)) return QQmlType(); - QQmlType dtype(data, typeName, type); - - addTypeToData(dtype.priv(), data); + QQmlTypePrivate *priv = createQQmlType(data, typeName, type); + addTypeToData(priv, data); QQmlMetaTypeData::Files *files = fileImport ? &(data->urlToType) : &(data->urlToNonFileImportType); - files->insertMulti(QQmlTypeLoader::normalize(type.url), dtype.priv()); + files->insertMulti(QQmlTypeLoader::normalize(type.url), priv); - return dtype; + return QQmlType(priv); } QQmlType QQmlMetaType::registerCompositeType(const QQmlPrivate::RegisterCompositeType &type) { // Assumes URL is absolute and valid. Checking of user input should happen before the URL enters type. - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + QQmlMetaTypeDataPtr data; + QString typeName = QString::fromUtf8(type.typeName); bool fileImport = false; if (*(type.uri) == '\0') @@ -1862,16 +501,16 @@ QQmlType QQmlMetaType::registerCompositeType(const QQmlPrivate::RegisterComposit if (!checkRegistration(QQmlType::CompositeType, data, fileImport?nullptr:type.uri, typeName, type.versionMajor)) return QQmlType(); - QQmlType dtype(data, typeName, type); - addTypeToData(dtype.priv(), data); + QQmlTypePrivate *priv = createQQmlType(data, typeName, type); + addTypeToData(priv, data); QQmlMetaTypeData::Files *files = fileImport ? &(data->urlToType) : &(data->urlToNonFileImportType); - files->insertMulti(QQmlTypeLoader::normalize(type.url), dtype.priv()); + files->insertMulti(QQmlTypeLoader::normalize(type.url), priv); - return dtype; + return QQmlType(priv); } -void QQmlMetaType::registerInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit) +void QQmlMetaType::registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit) { QByteArray name = compilationUnit->rootPropertyCache()->className(); @@ -1894,125 +533,61 @@ void QQmlMetaType::registerInternalCompositeType(QV4::CompiledData::CompilationU compilationUnit->metaTypeId = ptr_type; compilationUnit->listMetaTypeId = lst_type; - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *d = metaTypeData(); - d->qmlLists.insert(lst_type, ptr_type); + QQmlMetaTypeDataPtr data; + data->qmlLists.insert(lst_type, ptr_type); } -void QQmlMetaType::unregisterInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit) +void QQmlMetaType::unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit) { int ptr_type = compilationUnit->metaTypeId; int lst_type = compilationUnit->listMetaTypeId; - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *d = metaTypeData(); - d->qmlLists.remove(lst_type); + QQmlMetaTypeDataPtr data; + data->qmlLists.remove(lst_type); QMetaType::unregisterType(ptr_type); QMetaType::unregisterType(lst_type); } -int registerQmlUnitCacheHook(const QQmlPrivate::RegisterQmlUnitCacheHook &hookRegistration) +int QQmlMetaType::registerUnitCacheHook( + const QQmlPrivate::RegisterQmlUnitCacheHook &hookRegistration) { if (hookRegistration.version > 0) qFatal("qmlRegisterType(): Cannot mix incompatible QML versions."); - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + + QQmlMetaTypeDataPtr data; data->lookupCachedQmlUnit << hookRegistration.lookupCachedQmlUnit; return 0; } -/* -This method is "over generalized" to allow us to (potentially) register more types of things in -the future without adding exported symbols. -*/ -int QQmlPrivate::qmlregister(RegistrationType type, void *data) -{ - if (type == AutoParentRegistration) - return registerAutoParentFunction(*reinterpret_cast<RegisterAutoParent *>(data)); - else if (type == QmlUnitCacheHookRegistration) - return registerQmlUnitCacheHook(*reinterpret_cast<RegisterQmlUnitCacheHook *>(data)); - - QQmlType dtype; - if (type == TypeRegistration) - dtype = registerType(*reinterpret_cast<RegisterType *>(data)); - else if (type == InterfaceRegistration) - dtype = registerInterface(*reinterpret_cast<RegisterInterface *>(data)); - else if (type == SingletonRegistration) - dtype = registerSingletonType(*reinterpret_cast<RegisterSingletonType *>(data)); - else if (type == CompositeRegistration) - dtype = QQmlMetaType::registerCompositeType(*reinterpret_cast<RegisterCompositeType *>(data)); - else if (type == CompositeSingletonRegistration) - dtype = QQmlMetaType::registerCompositeSingletonType(*reinterpret_cast<RegisterCompositeSingletonType *>(data)); - else - return -1; - - if (!dtype.isValid()) - return -1; - - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *typeData = metaTypeData(); - typeData->undeletableTypes.insert(dtype); - - return dtype.index(); -} - -void QQmlPrivate::qmlunregister(RegistrationType type, quintptr data) -{ - switch (type) { - case AutoParentRegistration: - unregisterAutoParentFunction(reinterpret_cast<AutoParentFunction>(data)); - break; - case QmlUnitCacheHookRegistration: - QQmlMetaType::removeCachedUnitLookupFunction( - reinterpret_cast<QmlUnitCacheLookupFunction>(data)); - break; - case TypeRegistration: - case InterfaceRegistration: - case SingletonRegistration: - case CompositeRegistration: - case CompositeSingletonRegistration: - qmlUnregisterType(data); - break; - } -} - -//From qqml.h -bool qmlProtectModule(const char *uri, int majVersion) +bool QQmlMetaType::protectModule(const char *uri, int majVersion) { - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + QQmlMetaTypeDataPtr data; QQmlMetaTypeData::VersionedUri versionedUri; versionedUri.uri = QString::fromUtf8(uri); versionedUri.majorVersion = majVersion; if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0)) { - QQmlTypeModulePrivate::get(qqtm)->locked = true; + qqtm->lock(); return true; } return false; } -//From qqml.h -void qmlRegisterModule(const char *uri, int versionMajor, int versionMinor) +void QQmlMetaType::registerModule(const char *uri, int versionMajor, int versionMinor) { - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + QQmlMetaTypeDataPtr data; QQmlTypeModule *module = getTypeModule(QString::fromUtf8(uri), versionMajor, data); Q_ASSERT(module); - QQmlTypeModulePrivate *p = QQmlTypeModulePrivate::get(module); - p->minMinorVersion = qMin(p->minMinorVersion, versionMinor); - p->maxMinorVersion = qMax(p->maxMinorVersion, versionMinor); + module->addMinorVersion(versionMinor); } -//From qqml.h -int qmlTypeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName) +int QQmlMetaType::typeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName) { - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + QQmlMetaTypeDataPtr data; QQmlTypeModule *module = getTypeModule(QString::fromUtf8(uri), versionMajor, data); if (!module) @@ -2025,34 +600,218 @@ int qmlTypeId(const char *uri, int versionMajor, int versionMinor, const char *q return type.index(); } -bool QQmlMetaType::namespaceContainsRegistrations(const QString &uri, int majorVersion) +void QQmlMetaType::registerUndeletableType(const QQmlType &dtype) { - const QQmlMetaTypeData *data = metaTypeData(); + QQmlMetaTypeDataPtr data; + data->undeletableTypes.insert(dtype); +} +static bool namespaceContainsRegistrations(const QQmlMetaTypeData *data, const QString &uri, + int majorVersion) +{ // Has any type previously been installed to this namespace? QHashedString nameSpace(uri); - for (const QQmlType &type : data->types) + for (const QQmlType &type : data->types) { if (type.module() == nameSpace && type.majorVersion() == majorVersion) return true; + } return false; } -void QQmlMetaType::protectNamespace(const QString &uri) +class QQmlMetaTypeRegistrationFailureRecorder +{ + Q_DISABLE_COPY_MOVE(QQmlMetaTypeRegistrationFailureRecorder) +public: + QQmlMetaTypeRegistrationFailureRecorder(QQmlMetaTypeData *data, QStringList *failures) + : data(data) + { + data->setTypeRegistrationFailures(failures); + } + + ~QQmlMetaTypeRegistrationFailureRecorder() + { + data->setTypeRegistrationFailures(nullptr); + } + + QQmlMetaTypeData *data = nullptr; +}; + + +bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePath, + const QString &uri, const QString &typeNamespace, int vmaj, + QList<QQmlError> *errors) { - QQmlMetaTypeData *data = metaTypeData(); + QQmlTypesExtensionInterface *iface = qobject_cast<QQmlTypesExtensionInterface *>(instance); + if (!iface) { + if (errors) { + QQmlError error; + error.setDescription(QStringLiteral("Module loaded for URI '%1' does not implement " + "QQmlTypesExtensionInterface").arg(typeNamespace)); + errors->prepend(error); + } + return false; + } + + if (!typeNamespace.isEmpty() && typeNamespace != uri) { + // This is an 'identified' module + // The namespace for type registrations must match the URI for locating the module + if (errors) { + QQmlError error; + error.setDescription( + QStringLiteral("Module namespace '%1' does not match import URI '%2'") + .arg(typeNamespace).arg(uri)); + errors->prepend(error); + } + return false; + } + + QStringList failures; + QQmlMetaTypeDataPtr data; + { + QQmlMetaTypeRegistrationFailureRecorder failureRecorder(data, &failures); + if (!typeNamespace.isEmpty()) { + // This is an 'identified' module + if (namespaceContainsRegistrations(data, typeNamespace, vmaj)) { + // Other modules have already installed to this namespace + if (errors) { + QQmlError error; + error.setDescription(QStringLiteral("Namespace '%1' has already been used " + "for type registration") + .arg(typeNamespace)); + errors->prepend(error); + } + return false; + } + + data->protectedNamespaces.insert(uri); + } else { + // This is not an identified module - provide a warning + qWarning().nospace() << qPrintable( + QStringLiteral("Module '%1' does not contain a module identifier directive - " + "it cannot be protected from external registrations.").arg(uri)); + } + + if (auto *plugin = qobject_cast<QQmlExtensionPlugin *>(instance)) { + // basepath should point to the directory of the module, not the plugin file itself: + QQmlExtensionPluginPrivate::get(plugin)->baseUrl + = QQmlImports::urlFromLocalFileOrQrcOrUrl(basePath); + } + + data->typeRegistrationNamespace = typeNamespace; + const QByteArray bytes = uri.toUtf8(); + const char *moduleId = bytes.constData(); + iface->registerTypes(moduleId); + data->typeRegistrationNamespace.clear(); + } + + if (!failures.isEmpty()) { + if (errors) { + for (const QString &failure : qAsConst(failures)) { + QQmlError error; + error.setDescription(failure); + errors->prepend(error); + } + } + return false; + } - data->protectedNamespaces.insert(uri); + return true; } -void QQmlMetaType::setTypeRegistrationNamespace(const QString &uri) +/* + \internal + + Fetches the QQmlType instance registered for \a urlString, creating a + registration for it if it is not already registered, using the associated + \a typeName, \a isCompositeSingleton, \a majorVersion and \a minorVersion + details. + + Errors (if there are any) are placed into \a errors, if it is nonzero. + Otherwise errors are printed as warnings. +*/ +QQmlType QQmlMetaType::typeForUrl(const QString &urlString, + const QHashedStringRef &qualifiedType, + bool isCompositeSingleton, QList<QQmlError> *errors, + int majorVersion, int minorVersion) { - QQmlMetaTypeData *data = metaTypeData(); + // ### unfortunate (costly) conversion + const QUrl url = QQmlTypeLoader::normalize(QUrl(urlString)); - data->typeRegistrationNamespace = uri; + QQmlMetaTypeDataPtr data; + { + QQmlType ret(data->urlToType.value(url)); + if (ret.isValid() && ret.sourceUrl() == url) + return ret; + } + { + QQmlType ret(data->urlToNonFileImportType.value(url)); + if (ret.isValid() && ret.sourceUrl() == url) + return ret; + } + + const int dot = qualifiedType.indexOf(QLatin1Char('.')); + const QString typeName = dot < 0 + ? qualifiedType.toString() + : QString(qualifiedType.constData() + dot + 1, qualifiedType.length() - dot - 1); + + QStringList failures; + QQmlMetaTypeRegistrationFailureRecorder failureRecorder(data, &failures); + + // Register the type. Note that the URI parameters here are empty; for + // file type imports, we do not place them in a URI as we don't + // necessarily have a good and unique one (picture a library import, + // which may be found in multiple plugin locations on disk), but there + // are other reasons for this too. + // + // By not putting them in a URI, we prevent the types from being + // registered on a QQmlTypeModule; this is important, as once types are + // placed on there, they cannot be easily removed, meaning if the + // developer subsequently loads a different import (meaning different + // types) with the same URI (using, say, a different plugin path), it is + // very undesirable that we continue to associate the types from the + // "old" URI with that new module. + // + // Not having URIs also means that the types cannot be found by name + // etc, the only way to look them up is through QQmlImports -- for + // better or worse. + const QQmlType::RegistrationType registrationType = isCompositeSingleton + ? QQmlType::CompositeSingletonType + : QQmlType::CompositeType; + if (checkRegistration(registrationType, data, nullptr, typeName, majorVersion)) { + auto *priv = new QQmlTypePrivate(registrationType); + priv->setName(QString(), typeName); + priv->version_maj = majorVersion; + priv->version_min = minorVersion; + + if (isCompositeSingleton) { + priv->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo; + priv->extraData.sd->singletonInstanceInfo->url = url; + priv->extraData.sd->singletonInstanceInfo->typeName = typeName; + } else { + priv->extraData.fd->url = url; + } + + data->registerType(priv); + addTypeToData(priv, data); + data->urlToType.insertMulti(url, priv); + return QQmlType(priv); + } + + // This means that the type couldn't be found by URL, but could not be + // registered either, meaning we most likely were passed some kind of bad + // data. + if (errors) { + QQmlError error; + error.setDescription(failures.join('\n')); + errors->prepend(error); + } else { + qWarning("%s", failures.join('\n').toLatin1().constData()); + } + return QQmlType(); } -QMutex *QQmlMetaType::typeRegistrationLock() +QRecursiveMutex *QQmlMetaType::typeRegistrationLock() { return metaTypeDataLock(); } @@ -2062,8 +821,7 @@ QMutex *QQmlMetaType::typeRegistrationLock() */ bool QQmlMetaType::isAnyModule(const QString &uri) { - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + QQmlMetaTypeDataPtr data; for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.cbegin(); iter != data->uriToModule.cend(); ++iter) { @@ -2079,14 +837,13 @@ bool QQmlMetaType::isAnyModule(const QString &uri) */ bool QQmlMetaType::isLockedModule(const QString &uri, int majVersion) { - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + QQmlMetaTypeDataPtr data; QQmlMetaTypeData::VersionedUri versionedUri; versionedUri.uri = uri; versionedUri.majorVersion = majVersion; if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0)) - return QQmlTypeModulePrivate::get(qqtm)->locked; + return qqtm->isLocked(); return false; } @@ -2100,9 +857,7 @@ bool QQmlMetaType::isLockedModule(const QString &uri, int majVersion) bool QQmlMetaType::isModule(const QString &module, int versionMajor, int versionMinor) { Q_ASSERT(versionMajor >= 0 && versionMinor >= 0); - QMutexLocker lock(metaTypeDataLock()); - - QQmlMetaTypeData *data = metaTypeData(); + QQmlMetaTypeDataPtr data; // first, check Types QQmlTypeModule *tm = @@ -2115,15 +870,13 @@ bool QQmlMetaType::isModule(const QString &module, int versionMajor, int version QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, int majorVersion) { - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + QQmlMetaTypeDataPtr data; return data->uriToModule.value(QQmlMetaTypeData::VersionedUri(uri, majorVersion)); } QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions() { - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + QQmlMetaTypeDataPtr data; return data->parentFunctions; } @@ -2144,8 +897,7 @@ bool QQmlMetaType::isQObject(int userType) if (userType == QMetaType::QObjectStar) return true; - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + QQmlMetaTypeDataPtr data; return userType >= 0 && userType < data->objects.size() && data->objects.testBit(userType); } @@ -2154,8 +906,7 @@ bool QQmlMetaType::isQObject(int userType) */ int QQmlMetaType::listType(int id) { - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + QQmlMetaTypeDataPtr data; QHash<int, int>::ConstIterator iter = data->qmlLists.constFind(id); if (iter != data->qmlLists.cend()) return *iter; @@ -2166,10 +917,10 @@ int QQmlMetaType::listType(int id) return 0; } +#if QT_DEPRECATED_SINCE(5, 14) int QQmlMetaType::attachedPropertiesFuncId(QQmlEnginePrivate *engine, const QMetaObject *mo) { - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + QQmlMetaTypeDataPtr data; for (auto it = data->metaObjectToType.constFind(mo), end = data->metaObjectToType.constEnd(); it != end && it.key() == mo; ++it) { @@ -2185,16 +936,15 @@ QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(QQmlEnginePr { if (id < 0) return nullptr; - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + QQmlMetaTypeDataPtr data; return data->types.at(id).attachedPropertiesFunction(engine); } +#endif QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFunc(QQmlEnginePrivate *engine, const QMetaObject *mo) { - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + QQmlMetaTypeDataPtr data; QQmlType type(data->metaObjectToType.value(mo)); return type.attachedPropertiesFunction(engine); @@ -2259,8 +1009,7 @@ QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType) if (userType == QMetaType::QObjectStar) return Object; - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + QQmlMetaTypeDataPtr data; if (data->qmlLists.contains(userType)) return List; else if (userType < data->objects.size() && data->objects.testBit(userType)) @@ -2276,17 +1025,20 @@ QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType) */ bool QQmlMetaType::isInterface(int userType) { - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + const QQmlMetaTypeDataPtr data; return userType >= 0 && userType < data->interfaces.size() && data->interfaces.testBit(userType); } const char *QQmlMetaType::interfaceIId(int userType) { - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); - QQmlType type(data->idToType.value(userType)); - lock.unlock(); + + QQmlTypePrivate *typePrivate = nullptr; + { + QQmlMetaTypeDataPtr data; + typePrivate = data->idToType.value(userType); + } + + QQmlType type(typePrivate); if (type.isInterface() && type.typeId() == userType) return type.interfaceIId(); else @@ -2295,8 +1047,7 @@ const char *QQmlMetaType::interfaceIId(int userType) bool QQmlMetaType::isList(int userType) { - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + const QQmlMetaTypeDataPtr data; if (data->qmlLists.contains(userType)) return true; return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType); @@ -2319,9 +1070,7 @@ bool QQmlMetaType::isList(int userType) */ void QQmlMetaType::registerCustomStringConverter(int type, StringConverter converter) { - QMutexLocker lock(metaTypeDataLock()); - - QQmlMetaTypeData *data = metaTypeData(); + QQmlMetaTypeDataPtr data; if (data->stringConverters.contains(type)) return; data->stringConverters.insert(type, converter); @@ -2333,9 +1082,7 @@ void QQmlMetaType::registerCustomStringConverter(int type, StringConverter conve */ QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type) { - QMutexLocker lock(metaTypeDataLock()); - - QQmlMetaTypeData *data = metaTypeData(); + const QQmlMetaTypeDataPtr data; return data->stringConverters.value(type); } @@ -2362,8 +1109,7 @@ QQmlType QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, QQmlType QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int version_major, int version_minor) { Q_ASSERT(version_major >= 0 && version_minor >= 0); - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + const QQmlMetaTypeDataPtr data; QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.constFind(name); while (it != data->nameToType.cend() && it.key() == name) { @@ -2383,9 +1129,7 @@ QQmlType QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedString */ QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject) { - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); - + const QQmlMetaTypeDataPtr data; return QQmlType(data->metaObjectToType.value(metaObject)); } @@ -2397,8 +1141,7 @@ QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject) QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor) { Q_ASSERT(version_major >= 0 && version_minor >= 0); - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + const QQmlMetaTypeDataPtr data; QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.constFind(metaObject); while (it != data->metaObjectToType.cend() && it.key() == metaObject) { @@ -2418,8 +1161,7 @@ QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStrin */ QQmlType QQmlMetaType::qmlType(int typeId, TypeIdCategory category) { - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + const QQmlMetaTypeDataPtr data; if (category == TypeIdCategory::MetaType) { QQmlTypePrivate *type = data->idToType.value(typeId); @@ -2442,8 +1184,7 @@ QQmlType QQmlMetaType::qmlType(int typeId, TypeIdCategory category) QQmlType QQmlMetaType::qmlType(const QUrl &unNormalizedUrl, bool includeNonFileImports /* = false */) { const QUrl url = QQmlTypeLoader::normalize(unNormalizedUrl); - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + const QQmlMetaTypeDataPtr data; QQmlType type(data->urlToType.value(url)); if (!type.isValid() && includeNonFileImports) @@ -2455,221 +1196,87 @@ QQmlType QQmlMetaType::qmlType(const QUrl &unNormalizedUrl, bool includeNonFileI return QQmlType(); } -QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QMetaObject *metaObject, int minorVersion) -{ - if (QQmlPropertyCache *rv = propertyCaches.value(metaObject)) - return rv; - - if (!metaObject->superClass()) { - QQmlPropertyCache *rv = new QQmlPropertyCache(metaObject); - propertyCaches.insert(metaObject, rv); - return rv; - } - QQmlPropertyCache *super = propertyCache(metaObject->superClass(), minorVersion); - QQmlPropertyCache *rv = super->copyAndAppend(metaObject, minorVersion); - propertyCaches.insert(metaObject, rv); - return rv; -} - QQmlPropertyCache *QQmlMetaType::propertyCache(const QMetaObject *metaObject, int minorVersion) { - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + QQmlMetaTypeDataPtr data; // not const: the cache is created on demand return data->propertyCache(metaObject, minorVersion); } -QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, int minorVersion) -{ - Q_ASSERT(type.isValid()); - - if (QQmlPropertyCache *pc = type.key()->propertyCacheForMinorVersion(minorVersion)) - return pc; - - QVector<QQmlType> types; - - int maxMinorVersion = 0; - - const QMetaObject *metaObject = type.metaObject(); - - while (metaObject) { - QQmlType t = QQmlMetaType::qmlType(metaObject, type.module(), type.majorVersion(), minorVersion); - if (t.isValid()) { - maxMinorVersion = qMax(maxMinorVersion, t.minorVersion()); - types << t; - } else { - types << QQmlType(); - } - - metaObject = metaObject->superClass(); - } - - if (QQmlPropertyCache *pc = type.key()->propertyCacheForMinorVersion(maxMinorVersion)) { - const_cast<QQmlTypePrivate*>(type.key())->setPropertyCacheForMinorVersion(minorVersion, pc); - return pc; - } - - QQmlPropertyCache *raw = propertyCache(type.metaObject(), minorVersion); - - bool hasCopied = false; - - for (int ii = 0; ii < types.count(); ++ii) { - QQmlType currentType = types.at(ii); - if (!currentType.isValid()) - continue; - - int rev = currentType.metaObjectRevision(); - int moIndex = types.count() - 1 - ii; - - if (raw->allowedRevisionCache[moIndex] != rev) { - if (!hasCopied) { - raw = raw->copy(); - hasCopied = true; - } - raw->allowedRevisionCache[moIndex] = rev; - } - } - - // Test revision compatibility - the basic rule is: - // * Anything that is excluded, cannot overload something that is not excluded * - - // Signals override: - // * other signals and methods of the same name. - // * properties named on<Signal Name> - // * automatic <property name>Changed notify signals - - // Methods override: - // * other methods of the same name - - // Properties override: - // * other elements of the same name - -#if 0 - bool overloadError = false; - QString overloadName; - - for (QQmlPropertyCache::StringCache::ConstIterator iter = raw->stringCache.begin(); - !overloadError && iter != raw->stringCache.end(); - ++iter) { - - QQmlPropertyData *d = *iter; - if (raw->isAllowedInRevision(d)) - continue; // Not excluded - no problems - - // check that a regular "name" overload isn't happening - QQmlPropertyData *current = d; - while (!overloadError && current) { - current = d->overrideData(current); - if (current && raw->isAllowedInRevision(current)) - overloadError = true; - } - } - - if (overloadError) { - if (hasCopied) raw->release(); - - error.setDescription(QLatin1String("Type ") + type.qmlTypeName() + QLatin1Char(' ') + QString::number(type.majorVersion()) + QLatin1Char('.') + QString::number(minorVersion) + QLatin1String(" contains an illegal property \"") + overloadName + QLatin1String("\". This is an error in the type's implementation.")); - return 0; - } -#endif - - const_cast<QQmlTypePrivate*>(type.key())->setPropertyCacheForMinorVersion(minorVersion, raw); - - if (hasCopied) - raw->release(); - - if (minorVersion != maxMinorVersion) - const_cast<QQmlTypePrivate*>(type.key())->setPropertyCacheForMinorVersion(maxMinorVersion, raw); - - return raw; -} - QQmlPropertyCache *QQmlMetaType::propertyCache(const QQmlType &type, int minorVersion) { - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + QQmlMetaTypeDataPtr data; // not const: the cache is created on demand return data->propertyCache(type, minorVersion); } -void qmlUnregisterType(int typeIndex) +void QQmlMetaType::unregisterType(int typeIndex) { - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); - { - const QQmlType type = data->types.value(typeIndex); - const QQmlTypePrivate *d = type.priv(); - if (d) { - removeQQmlTypePrivate(data->idToType, d); - removeQQmlTypePrivate(data->nameToType, d); - removeQQmlTypePrivate(data->urlToType, d); - removeQQmlTypePrivate(data->urlToNonFileImportType, d); - removeQQmlTypePrivate(data->metaObjectToType, d); - for (QQmlMetaTypeData::TypeModules::Iterator module = data->uriToModule.begin(); module != data->uriToModule.end(); ++module) { - QQmlTypeModulePrivate *modulePrivate = (*module)->priv(); - modulePrivate->remove(d); - } - data->types[typeIndex] = QQmlType(); - data->undeletableTypes.remove(type); - } + QQmlMetaTypeDataPtr data; + const QQmlType type = data->types.value(typeIndex); + if (const QQmlTypePrivate *d = type.priv()) { + removeQQmlTypePrivate(data->idToType, d); + removeQQmlTypePrivate(data->nameToType, d); + removeQQmlTypePrivate(data->urlToType, d); + removeQQmlTypePrivate(data->urlToNonFileImportType, d); + removeQQmlTypePrivate(data->metaObjectToType, d); + for (auto & module : data->uriToModule) + module->remove(d); + data->clearPropertyCachesForMinorVersion(typeIndex); + data->types[typeIndex] = QQmlType(); + data->undeletableTypes.remove(type); } } void QQmlMetaType::freeUnusedTypesAndCaches() { - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + QQmlMetaTypeDataPtr data; // in case this is being called during program exit, `data` might be destructed already - if (!data) + if (!data.isValid()) return; - { - bool deletedAtLeastOneType; - do { - deletedAtLeastOneType = false; - QList<QQmlType>::Iterator it = data->types.begin(); - while (it != data->types.end()) { - const QQmlTypePrivate *d = (*it).priv(); - if (d && d->refCount == 1) { - deletedAtLeastOneType = true; - - removeQQmlTypePrivate(data->idToType, d); - removeQQmlTypePrivate(data->nameToType, d); - removeQQmlTypePrivate(data->urlToType, d); - removeQQmlTypePrivate(data->urlToNonFileImportType, d); - removeQQmlTypePrivate(data->metaObjectToType, d); - - for (QQmlMetaTypeData::TypeModules::Iterator module = data->uriToModule.begin(); module != data->uriToModule.end(); ++module) { - QQmlTypeModulePrivate *modulePrivate = (*module)->priv(); - modulePrivate->remove(d); - } - - *it = QQmlType(); - } else { - ++it; - } + bool deletedAtLeastOneType; + do { + deletedAtLeastOneType = false; + QList<QQmlType>::Iterator it = data->types.begin(); + while (it != data->types.end()) { + const QQmlTypePrivate *d = (*it).priv(); + if (d && d->count() == 1) { + deletedAtLeastOneType = true; + + removeQQmlTypePrivate(data->idToType, d); + removeQQmlTypePrivate(data->nameToType, d); + removeQQmlTypePrivate(data->urlToType, d); + removeQQmlTypePrivate(data->urlToNonFileImportType, d); + removeQQmlTypePrivate(data->metaObjectToType, d); + + for (auto &module : data->uriToModule) + module->remove(d); + + data->clearPropertyCachesForMinorVersion(d->index); + *it = QQmlType(); + } else { + ++it; } - } while (deletedAtLeastOneType); - } - - { - bool deletedAtLeastOneCache; - do { - deletedAtLeastOneCache = false; - QHash<const QMetaObject *, QQmlPropertyCache *>::Iterator it = data->propertyCaches.begin(); - while (it != data->propertyCaches.end()) { - - if ((*it)->count() == 1) { - QQmlPropertyCache *pc = nullptr; - qSwap(pc, *it); - it = data->propertyCaches.erase(it); - pc->release(); - deletedAtLeastOneCache = true; - } else { - ++it; - } + } + } while (deletedAtLeastOneType); + + bool deletedAtLeastOneCache; + do { + deletedAtLeastOneCache = false; + QHash<const QMetaObject *, QQmlPropertyCache *>::Iterator it = data->propertyCaches.begin(); + while (it != data->propertyCaches.end()) { + + if ((*it)->count() == 1) { + QQmlPropertyCache *pc = nullptr; + qSwap(pc, *it); + it = data->propertyCaches.erase(it); + pc->release(); + deletedAtLeastOneCache = true; + } else { + ++it; } - } while (deletedAtLeastOneCache); - } + } + } while (deletedAtLeastOneCache); } /*! @@ -2677,8 +1284,7 @@ void QQmlMetaType::freeUnusedTypesAndCaches() */ QList<QString> QQmlMetaType::qmlTypeNames() { - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + const QQmlMetaTypeDataPtr data; QList<QString> names; names.reserve(data->nameToType.count()); @@ -2697,8 +1303,7 @@ QList<QString> QQmlMetaType::qmlTypeNames() */ QList<QQmlType> QQmlMetaType::qmlTypes() { - QMutexLocker lock(metaTypeDataLock()); - const QQmlMetaTypeData *data = metaTypeData(); + const QQmlMetaTypeDataPtr data; QList<QQmlType> types; for (QQmlTypePrivate *t : data->nameToType) @@ -2712,9 +1317,7 @@ QList<QQmlType> QQmlMetaType::qmlTypes() */ QList<QQmlType> QQmlMetaType::qmlAllTypes() { - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); - + const QQmlMetaTypeDataPtr data; return data->types; } @@ -2723,8 +1326,7 @@ QList<QQmlType> QQmlMetaType::qmlAllTypes() */ QList<QQmlType> QQmlMetaType::qmlSingletonTypes() { - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + const QQmlMetaTypeDataPtr data; QList<QQmlType> retn; for (const auto t : qAsConst(data->nameToType)) { @@ -2737,13 +1339,12 @@ QList<QQmlType> QQmlMetaType::qmlSingletonTypes() const QV4::CompiledData::Unit *QQmlMetaType::findCachedCompilationUnit(const QUrl &uri, CachedUnitLookupError *status) { - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + const QQmlMetaTypeDataPtr data; for (const auto lookup : qAsConst(data->lookupCachedQmlUnit)) { if (const QQmlPrivate::CachedQmlUnit *unit = lookup(uri)) { QString error; - if (!unit->qmlData->verifyHeader(QDateTime(), &error)) { + if (!QV4::ExecutableCompilationUnit::verifyHeader(unit->qmlData, QDateTime(), &error)) { qCDebug(DBG_DISK_CACHE) << "Error loading pre-compiled file " << uri << ":" << error; if (status) *status = CachedUnitLookupError::VersionMismatch; @@ -2763,15 +1364,13 @@ const QV4::CompiledData::Unit *QQmlMetaType::findCachedCompilationUnit(const QUr void QQmlMetaType::prependCachedUnitLookupFunction(QQmlPrivate::QmlUnitCacheLookupFunction handler) { - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + QQmlMetaTypeDataPtr data; data->lookupCachedQmlUnit.prepend(handler); } void QQmlMetaType::removeCachedUnitLookupFunction(QQmlPrivate::QmlUnitCacheLookupFunction handler) { - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + QQmlMetaTypeDataPtr data; data->lookupCachedQmlUnit.removeAll(handler); } @@ -2817,4 +1416,38 @@ QString QQmlMetaType::prettyTypeName(const QObject *object) return typeName; } +QList<QQmlProxyMetaObject::ProxyData> QQmlMetaType::proxyData(const QMetaObject *mo, + const QMetaObject *baseMetaObject, + QMetaObject *lastMetaObject) +{ + QList<QQmlProxyMetaObject::ProxyData> metaObjects; + mo = mo->d.superdata; + + const QQmlMetaTypeDataPtr data; + + while (mo) { + QQmlTypePrivate *t = data->metaObjectToType.value(mo); + if (t) { + if (t->regType == QQmlType::CppType) { + if (t->extraData.cd->extFunc) { + QMetaObjectBuilder builder; + clone(builder, t->extraData.cd->extMetaObject, t->baseMetaObject, baseMetaObject); + builder.setFlags(QMetaObjectBuilder::DynamicMetaObject); + QMetaObject *mmo = builder.toMetaObject(); + mmo->d.superdata = baseMetaObject; + if (!metaObjects.isEmpty()) + metaObjects.constLast().metaObject->d.superdata = mmo; + else if (lastMetaObject) + lastMetaObject->d.superdata = mmo; + QQmlProxyMetaObject::ProxyData data = { mmo, t->extraData.cd->extFunc, 0, 0 }; + metaObjects << data; + } + } + } + mo = mo->d.superdata; + } + + return metaObjects; +} + QT_END_NAMESPACE |