diff options
Diffstat (limited to 'src/qml/qml/qqmlmetatype.cpp')
-rw-r--r-- | src/qml/qml/qqmlmetatype.cpp | 621 |
1 files changed, 414 insertions, 207 deletions
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 054ad48617..1175bde3db 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -3,11 +3,12 @@ #include "qqmlmetatype_p.h" +#include <private/qqmlextensionplugin_p.h> #include <private/qqmlmetatypedata_p.h> -#include <private/qqmltypemodule_p.h> +#include <private/qqmlpropertycachecreator_p.h> #include <private/qqmltype_p_p.h> #include <private/qqmltypeloader_p.h> -#include <private/qqmlextensionplugin_p.h> +#include <private/qqmltypemodule_p.h> #include <private/qqmlvaluetype_p.h> #include <private/qv4executablecompilationunit_p.h> @@ -20,32 +21,6 @@ Q_LOGGING_CATEGORY(lcTypeRegistration, "qt.qml.typeregistration") QT_BEGIN_NAMESPACE -CompositeMetaTypeIds CompositeMetaTypeIds::fromCompositeName(const QByteArray &name) -{ - auto ids = QQmlMetaType::registerInternalCompositeType(name); - ids.refCount = new int; - *ids.refCount = 1; - return ids; -} - -void CompositeMetaTypeIds::deref() -{ - Q_ASSERT(refCount); - --*refCount; - if (!*refCount) { - delete refCount; - QQmlMetaType::unregisterInternalCompositeType(*this); - refCount = nullptr; - } -} - -CompositeMetaTypeIds::~CompositeMetaTypeIds() -{ - if (refCount) - deref(); -} - - struct LockedData : private QQmlMetaTypeData { friend class QQmlMetaTypeDataPtr; @@ -86,18 +61,19 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QQmlPrivate::RegisterInterface &type) { auto *d = new QQmlTypePrivate(QQmlType::InterfaceType); - d->iid = type.iid; + d->extraData.interfaceTypeData = type.iid; d->typeId = type.typeId; d->listId = type.listId; - d->isSetup.storeRelease(true); d->module = QString::fromUtf8(type.uri); d->version = type.version; data->registerType(d); return d; } -static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName, - const QQmlPrivate::RegisterSingletonType &type) +static QQmlTypePrivate *createQQmlType( + QQmlMetaTypeData *data, const QString &elementName, + const QQmlPrivate::RegisterSingletonType &type, + const QQmlType::SingletonInstanceInfo::ConstPtr &siinfo) { auto *d = new QQmlTypePrivate(QQmlType::SingletonType); data->registerType(d); @@ -111,14 +87,9 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el d->revision = type.revision; } - d->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo; - d->extraData.sd->singletonInstanceInfo->scriptCallback = type.scriptApi; - d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.qObjectApi; - d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName); - d->extraData.sd->singletonInstanceInfo->instanceMetaObject - = type.qObjectApi ? type.instanceMetaObject : nullptr; - d->extraData.sd->extFunc = type.extensionObjectCreate; - d->extraData.sd->extMetaObject = type.extensionMetaObject; + d->extraData.singletonTypeData->singletonInstanceInfo = siinfo; + d->extraData.singletonTypeData->extFunc = type.extensionObjectCreate; + d->extraData.singletonTypeData->extMetaObject = type.extensionMetaObject; return d; } @@ -134,74 +105,98 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el d->revision = type.revision; d->typeId = type.typeId; d->listId = type.listId; - d->extraData.cd->allocationSize = type.objectSize; - d->extraData.cd->userdata = type.userdata; - d->extraData.cd->newFunc = type.create; - d->extraData.cd->noCreationReason = type.noCreationReason; - d->extraData.cd->createValueTypeFunc = type.createValueType; + d->extraData.cppTypeData->allocationSize = type.objectSize; + d->extraData.cppTypeData->userdata = type.userdata; + d->extraData.cppTypeData->newFunc = type.create; + d->extraData.cppTypeData->noCreationReason = type.noCreationReason; + d->extraData.cppTypeData->createValueTypeFunc = type.createValueType; d->baseMetaObject = type.metaObject; - d->extraData.cd->attachedPropertiesFunc = type.attachedPropertiesFunction; - d->extraData.cd->attachedPropertiesType = type.attachedPropertiesMetaObject; - d->extraData.cd->parserStatusCast = type.parserStatusCast; - d->extraData.cd->propertyValueSourceCast = type.valueSourceCast; - d->extraData.cd->propertyValueInterceptorCast = type.valueInterceptorCast; - d->extraData.cd->finalizerCast = type.has(QQmlPrivate::RegisterType::FinalizerCast) + d->extraData.cppTypeData->attachedPropertiesFunc = type.attachedPropertiesFunction; + d->extraData.cppTypeData->attachedPropertiesType = type.attachedPropertiesMetaObject; + d->extraData.cppTypeData->parserStatusCast = type.parserStatusCast; + d->extraData.cppTypeData->propertyValueSourceCast = type.valueSourceCast; + d->extraData.cppTypeData->propertyValueInterceptorCast = type.valueInterceptorCast; + d->extraData.cppTypeData->finalizerCast = type.has(QQmlPrivate::RegisterType::FinalizerCast) ? type.finalizerCast : -1; - d->extraData.cd->extFunc = type.extensionObjectCreate; - d->extraData.cd->customParser = reinterpret_cast<QQmlCustomParser *>(type.customParser); - d->extraData.cd->registerEnumClassesUnscoped = true; - d->extraData.cd->registerEnumsFromRelatedTypes = true; - d->extraData.cd->constructValueType = type.has(QQmlPrivate::RegisterType::CreationMethod) + d->extraData.cppTypeData->extFunc = type.extensionObjectCreate; + d->extraData.cppTypeData->customParser = reinterpret_cast<QQmlCustomParser *>(type.customParser); + d->extraData.cppTypeData->registerEnumClassesUnscoped = true; + d->extraData.cppTypeData->registerEnumsFromRelatedTypes = true; + d->extraData.cppTypeData->constructValueType = type.has(QQmlPrivate::RegisterType::CreationMethod) && type.creationMethod != QQmlPrivate::ValueTypeCreationMethod::None; - d->extraData.cd->populateValueType = type.has(QQmlPrivate::RegisterType::CreationMethod) + d->extraData.cppTypeData->populateValueType = type.has(QQmlPrivate::RegisterType::CreationMethod) && type.creationMethod == QQmlPrivate::ValueTypeCreationMethod::Structured; if (type.extensionMetaObject) - d->extraData.cd->extMetaObject = type.extensionMetaObject; + d->extraData.cppTypeData->extMetaObject = type.extensionMetaObject; // Check if the user wants only scoped enum classes if (d->baseMetaObject) { auto indexOfUnscoped = d->baseMetaObject->indexOfClassInfo("RegisterEnumClassesUnscoped"); if (indexOfUnscoped != -1 && qstrcmp(d->baseMetaObject->classInfo(indexOfUnscoped).value(), "false") == 0) { - d->extraData.cd->registerEnumClassesUnscoped = false; + d->extraData.cppTypeData->registerEnumClassesUnscoped = false; } auto indexOfRelated = d->baseMetaObject->indexOfClassInfo("RegisterEnumsFromRelatedTypes"); if (indexOfRelated != -1 && qstrcmp(d->baseMetaObject->classInfo(indexOfRelated).value(), "false") == 0) { - d->extraData.cd->registerEnumsFromRelatedTypes = false; + d->extraData.cppTypeData->registerEnumsFromRelatedTypes = false; } } return d; } +static void addQQmlMetaTypeInterfaces(QQmlTypePrivate *priv, const QByteArray &className) +{ + Q_ASSERT(!className.isEmpty()); + QByteArray ptr = className + '*'; + QByteArray lst = "QQmlListProperty<" + className + '>'; + + QMetaType ptr_type(new QQmlMetaTypeInterface(ptr)); + QMetaType lst_type(new QQmlListMetaTypeInterface(lst, ptr_type.iface())); + + // Retrieve the IDs once, so that the types are added to QMetaType's custom type registry. + ptr_type.id(); + lst_type.id(); + + priv->typeId = ptr_type; + priv->listId = lst_type; +} + static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName, const QQmlPrivate::RegisterCompositeType &type) { + // This is a procedurally registered composite type. It's evil. It doesn't get any metatypes + // because we never want to find it in the compositeTypes. Otherwise we might mix it up with an + // actually compiled version of the same type. + auto *d = new QQmlTypePrivate(QQmlType::CompositeType); data->registerType(d); d->setName(QString::fromUtf8(type.uri), elementName); d->version = type.version; - - d->extraData.fd->url = QQmlTypeLoader::normalize(type.url); + d->extraData.compositeTypeData = QQmlTypeLoader::normalize(type.url); return d; } -static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName, - const QQmlPrivate::RegisterCompositeSingletonType &type) +static QQmlTypePrivate *createQQmlType( + QQmlMetaTypeData *data, const QString &elementName, + const QQmlPrivate::RegisterCompositeSingletonType &type, + const QQmlType::SingletonInstanceInfo::ConstPtr &siinfo) { + // This is a procedurally registered composite singleton. It's evil. It doesn't get any + // metatypes because we never want to find it in the compositeTypes. Otherwise we might mix it + // up with an actually compiled version of the same type. + auto *d = new QQmlTypePrivate(QQmlType::CompositeSingletonType); data->registerType(d); d->setName(QString::fromUtf8(type.uri), elementName); d->version = type.version; - 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); + d->extraData.singletonTypeData->singletonInstanceInfo = siinfo; return d; } @@ -262,7 +257,7 @@ void QQmlMetaType::clone(QMetaObjectBuilder &builder, const QMetaObject *mo, } } - // Clone Q_ENUMS + // Clone enums registered with the metatype system for (int ii = mo->enumeratorOffset(); ii < mo->enumeratorCount(); ++ii) { QMetaEnum enumerator = mo->enumerator(ii); @@ -317,6 +312,20 @@ void QQmlMetaType::clearTypeRegistrations() data->urlToNonFileImportType.clear(); data->metaObjectToType.clear(); data->undeletableTypes.clear(); + data->propertyCaches.clear(); + data->inlineComponentTypes.clear(); + + // Avoid deletion recursion (via QQmlTypePrivate dtor) by moving them out of the way first. + QQmlMetaTypeData::CompositeTypes emptyComposites; + emptyComposites.swap(data->compositeTypes); +} + +void QQmlMetaType::registerTypeAlias(int typeIndex, const QString &name) +{ + QQmlMetaTypeDataPtr data; + const QQmlType type = data->types.value(typeIndex); + const QQmlTypePrivate *priv = type.priv(); + data->nameToType.insert(name, priv); } int QQmlMetaType::registerAutoParentFunction(const QQmlPrivate::RegisterAutoParent &function) @@ -482,7 +491,9 @@ QQmlType QQmlMetaType::registerType(const QQmlPrivate::RegisterType &type) return QQmlType(priv); } -QQmlType QQmlMetaType::registerSingletonType(const QQmlPrivate::RegisterSingletonType &type) +QQmlType QQmlMetaType::registerSingletonType( + const QQmlPrivate::RegisterSingletonType &type, + const QQmlType::SingletonInstanceInfo::ConstPtr &siinfo) { if (type.structVersion > 1) qFatal("qmlRegisterType(): Cannot mix incompatible QML versions."); @@ -495,14 +506,16 @@ QQmlType QQmlMetaType::registerSingletonType(const QQmlPrivate::RegisterSingleto return QQmlType(); } - QQmlTypePrivate *priv = createQQmlType(data, typeName, type); + QQmlTypePrivate *priv = createQQmlType(data, typeName, type, siinfo); addTypeToData(priv, data); return QQmlType(priv); } -QQmlType QQmlMetaType::registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingletonType &type) +QQmlType QQmlMetaType::registerCompositeSingletonType( + const QQmlPrivate::RegisterCompositeSingletonType &type, + const QQmlType::SingletonInstanceInfo::ConstPtr &siinfo) { if (type.structVersion > 1) qFatal("qmlRegisterType(): Cannot mix incompatible QML versions."); @@ -519,11 +532,11 @@ QQmlType QQmlMetaType::registerCompositeSingletonType(const QQmlPrivate::Registe return QQmlType(); } - QQmlTypePrivate *priv = createQQmlType(data, typeName, type); + QQmlTypePrivate *priv = createQQmlType(data, typeName, type, siinfo); addTypeToData(priv, data); QQmlMetaTypeData::Files *files = fileImport ? &(data->urlToType) : &(data->urlToNonFileImportType); - files->insert(QQmlTypeLoader::normalize(type.url), priv); + files->insert(siinfo->url, priv); return QQmlType(priv); } @@ -554,26 +567,172 @@ QQmlType QQmlMetaType::registerCompositeType(const QQmlPrivate::RegisterComposit return QQmlType(priv); } -CompositeMetaTypeIds QQmlMetaType::registerInternalCompositeType(const QByteArray &className) +class QQmlMetaTypeRegistrationFailureRecorder { - QByteArray ptr = className + '*'; - QByteArray lst = "QQmlListProperty<" + className + '>'; + Q_DISABLE_COPY_MOVE(QQmlMetaTypeRegistrationFailureRecorder) +public: + QQmlMetaTypeRegistrationFailureRecorder(QQmlMetaTypeData *data, QStringList *failures) + : data(data) + { + data->setTypeRegistrationFailures(failures); + } - QMetaType ptr_type(new QQmlMetaTypeInterface(ptr)); - QMetaType lst_type(new QQmlListMetaTypeInterface(lst, ptr_type.iface())); + ~QQmlMetaTypeRegistrationFailureRecorder() + { + data->setTypeRegistrationFailures(nullptr); + } - // Retrieve the IDs once, so that the types are added to QMetaType's custom type registry. - ptr_type.id(); - lst_type.id(); + QQmlMetaTypeData *data = nullptr; +}; + + +static QQmlType createTypeForUrl( + QQmlMetaTypeData *data, const QUrl &url, const QHashedStringRef &qualifiedType, + QQmlMetaType::CompositeTypeLookupMode mode, QList<QQmlError> *errors, QTypeRevision version) +{ + 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 = mode == QQmlMetaType::Singleton + ? QQmlType::CompositeSingletonType + : QQmlType::CompositeType; + if (checkRegistration(registrationType, data, nullptr, typeName, version, {})) { + + // TODO: Ideally we should defer most of this work using some lazy/atomic mechanism + // that creates the details on first use. We must not observably modify + // QQmlTypePrivate after it has been created since it is supposed to be immutable + // and shared across threads. + + auto *priv = new QQmlTypePrivate(registrationType); + addQQmlMetaTypeInterfaces(priv, QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(url)); + + priv->setName(QString(), typeName); + priv->version = version; + + if (mode == QQmlMetaType::Singleton) { + QQmlType::SingletonInstanceInfo::Ptr siinfo = QQmlType::SingletonInstanceInfo::create(); + siinfo->url = url; + siinfo->typeName = typeName.toUtf8(); + priv->extraData.singletonTypeData->singletonInstanceInfo = + QQmlType::SingletonInstanceInfo::ConstPtr( + siinfo.take(), QQmlType::SingletonInstanceInfo::ConstPtr::Adopt); + } else { + priv->extraData.compositeTypeData = url; + } + + data->registerType(priv); + addTypeToData(priv, data); + 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(u'\n')); + errors->prepend(error); + } else { + qWarning("%s", failures.join(u'\n').toLatin1().constData()); + } + return QQmlType(); +} + +QQmlType QQmlMetaType::findCompositeType( + const QUrl &url, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, + CompositeTypeLookupMode mode) +{ + const QUrl normalized = QQmlTypeLoader::normalize(url); + QQmlMetaTypeDataPtr data; + + bool urlExists = true; + auto found = data->urlToType.constFind(normalized); + if (found == data->urlToType.cend()) { + found = data->urlToNonFileImportType.constFind(normalized); + if (found == data->urlToNonFileImportType.cend()) + urlExists = false; + } + + if (const QtPrivate::QMetaTypeInterface *iface = urlExists + ? found.value()->typeId.iface() + : nullptr) { + if (compilationUnit.isNull()) + return QQmlType(*found); + + const auto composite = data->compositeTypes.constFind(iface); + if (composite == data->compositeTypes.constEnd() || composite.value() == compilationUnit) + return QQmlType(*found); + } + + const QQmlType type = createTypeForUrl( + data, normalized, QHashedStringRef(), mode, nullptr, QTypeRevision()); + + if (!urlExists && type.isValid()) + data->urlToType.insert(normalized, type.priv()); + + return type; +} + +static QQmlType doRegisterInlineComponentType(QQmlMetaTypeData *data, const QUrl &url) +{ + QQmlTypePrivate *priv = new QQmlTypePrivate(QQmlType::InlineComponentType); + priv->setName(QString(), url.fragment()); + + priv->extraData.inlineComponentTypeData = url; + + const QByteArray className + = QQmlPropertyCacheCreatorBase::createClassNameForInlineComponent(url, url.fragment()); + + addQQmlMetaTypeInterfaces(priv, className); + const QQmlType result(priv); + priv->release(); + + data->inlineComponentTypes.insert(url, result); - return {ptr_type, lst_type}; + return result; } -void QQmlMetaType::unregisterInternalCompositeType(const CompositeMetaTypeIds &typeIds) +QQmlType QQmlMetaType::findInlineComponentType( + const QUrl &url, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit) { - QMetaType metaType(typeIds.id); - QMetaType listMetaType(typeIds.listId); + QQmlMetaTypeDataPtr data; + // If there is an "unclaimed" inline component type, we can "claim" it now. Otherwise + // we have to create a new one. + const auto it = data->inlineComponentTypes.constFind(url); + if (it != data->inlineComponentTypes.constEnd()) { + const auto jt = data->compositeTypes.constFind(it->typeId().iface()); + if (jt == data->compositeTypes.constEnd() || *jt == compilationUnit) + return *it; + } + + return doRegisterInlineComponentType(data, url); +} + +void QQmlMetaType::unregisterInternalCompositeType(QMetaType metaType, QMetaType listMetaType) +{ // This may be called from delayed dtors on shutdown when the data is already gone. QQmlMetaTypeDataPtr data; if (data.isValid()) { @@ -581,6 +740,10 @@ void QQmlMetaType::unregisterInternalCompositeType(const CompositeMetaTypeIds &t delete vt; if (QQmlValueType *vt = data->metaTypeToValueType.take(listMetaType.id())) delete vt; + + auto it = data->compositeTypes.constFind(metaType.iface()); + if (it != data->compositeTypes.constEnd()) + data->compositeTypes.erase(it); } QMetaType::unregisterMetaType(metaType); @@ -621,7 +784,7 @@ QQmlType QQmlMetaType::registerSequentialContainer( priv->revision = container.revision; priv->typeId = container.metaSequence.valueMetaType(); priv->listId = container.typeId; - *priv->extraData.ld = container.metaSequence; + priv->extraData.sequentialContainerTypeData = container.metaSequence; addTypeToData(priv, data); @@ -754,25 +917,6 @@ static bool namespaceContainsRegistrations(const QQmlMetaTypeData *data, const Q return false; } -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; -}; - - QQmlMetaType::RegistrationResult QQmlMetaType::registerPluginTypes( QObject *instance, const QString &basePath, const QString &uri, const QString &typeNamespace, QTypeRevision version, QList<QQmlError> *errors) @@ -873,7 +1017,7 @@ QQmlMetaType::RegistrationResult QQmlMetaType::registerPluginTypes( */ QQmlType QQmlMetaType::typeForUrl(const QString &urlString, const QHashedStringRef &qualifiedType, - bool isCompositeSingleton, QList<QQmlError> *errors, + CompositeTypeLookupMode mode, QList<QQmlError> *errors, QTypeRevision version) { // ### unfortunate (costly) conversion @@ -891,69 +1035,10 @@ QQmlType QQmlMetaType::typeForUrl(const QString &urlString, 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, version, {})) { - auto *priv = new QQmlTypePrivate(registrationType); - priv->setName(QString(), typeName); - priv->version = version; - - 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.insert(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(u'\n')); - errors->prepend(error); - } else { - qWarning("%s", failures.join(u'\n').toLatin1().constData()); - } - return QQmlType(); -} - -QRecursiveMutex *QQmlMetaType::typeRegistrationLock() -{ - return metaTypeDataLock(); + const QQmlType type = createTypeForUrl( + data, url, qualifiedType, mode, errors, version); + data->urlToType.insert(url, type.priv()); + return type; } /* @@ -1275,6 +1360,16 @@ QQmlType QQmlMetaType::qmlType(const QUrl &unNormalizedUrl, bool includeNonFileI return QQmlType(); } +QQmlType QQmlMetaType::fetchOrCreateInlineComponentTypeForUrl(const QUrl &url) +{ + QQmlMetaTypeDataPtr data; + const auto it = data->inlineComponentTypes.constFind(url); + if (it != data->inlineComponentTypes.constEnd()) + return *it; + + return doRegisterInlineComponentType(data, url); +} + /*! Returns a QQmlPropertyCache for \a obj if one is available. @@ -1346,9 +1441,12 @@ QQmlPropertyCache::ConstPtr QQmlMetaType::propertyCacheForType(QMetaType metaTyp return composite; const QQmlTypePrivate *type = data->idToType.value(metaType.id()); - return (type && type->typeId == metaType) - ? data->propertyCache(QQmlType(type).metaObject(), type->version) - : QQmlPropertyCache::ConstPtr(); + if (type && type->typeId == metaType) { + if (const QMetaObject *mo = QQmlType(type).metaObject()) + return data->propertyCache(mo, type->version); + } + + return QQmlPropertyCache::ConstPtr(); } /*! @@ -1365,8 +1463,15 @@ QQmlPropertyCache::ConstPtr QQmlMetaType::rawPropertyCacheForType(QMetaType meta return composite; const QQmlTypePrivate *type = data->idToType.value(metaType.id()); - return (type && type->typeId == metaType) - ? data->propertyCache(type->baseMetaObject, QTypeRevision()) + if (!type || type->typeId != metaType) + return QQmlPropertyCache::ConstPtr(); + + const QMetaObject *metaObject = type->isValueType() + ? type->metaObjectForValueType() + : type->baseMetaObject; + + return metaObject + ? data->propertyCache(metaObject, QTypeRevision()) : QQmlPropertyCache::ConstPtr(); } @@ -1388,8 +1493,11 @@ QQmlPropertyCache::ConstPtr QQmlMetaType::rawPropertyCacheForType( return QQmlPropertyCache::ConstPtr(); const QQmlType type(typePriv); - if (type.containsRevisionedAttributes()) + if (type.containsRevisionedAttributes()) { + // It can only have (revisioned) properties or methods if it has a metaobject + Q_ASSERT(type.metaObject()); return data->propertyCache(type, version); + } if (const QMetaObject *metaObject = type.metaObject()) return data->propertyCache(metaObject, version); @@ -1402,6 +1510,8 @@ void QQmlMetaType::unregisterType(int typeIndex) QQmlMetaTypeDataPtr data; const QQmlType type = data->types.value(typeIndex); if (const QQmlTypePrivate *d = type.priv()) { + if (d->regType == QQmlType::CompositeType || d->regType == QQmlType::CompositeSingletonType) + removeFromInlineComponents(data->inlineComponentTypes, d); removeQQmlTypePrivate(data->idToType, d); removeQQmlTypePrivate(data->nameToType, d); removeQQmlTypePrivate(data->urlToType, d); @@ -1423,16 +1533,41 @@ void QQmlMetaType::registerMetaObjectForType(const QMetaObject *metaobject, QQml data->metaObjectToType.insert(metaobject, type); } -static bool hasActiveInlineComponents(const QQmlTypePrivate *d) +static bool hasActiveInlineComponents(const QQmlMetaTypeData *data, const QQmlTypePrivate *d) { - for (const QQmlType &ic : std::as_const(d->objectIdToICType)) { - const QQmlTypePrivate *icPriv = ic.priv(); + for (auto it = data->inlineComponentTypes.begin(), end = data->inlineComponentTypes.end(); + it != end; ++it) { + if (!QQmlMetaType::equalBaseUrls(it.key(), d->sourceUrl())) + continue; + + const QQmlTypePrivate *icPriv = it->priv(); if (icPriv && icPriv->count() > 1) return true; } return false; } +static int doCountInternalCompositeTypeSelfReferences( + QQmlMetaTypeData *data, + const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit) +{ + int result = 0; + auto doCheck = [&](const QtPrivate::QMetaTypeInterface *iface) { + if (!iface) + return; + + const auto it = data->compositeTypes.constFind(iface); + if (it != data->compositeTypes.constEnd() && *it == compilationUnit) + ++result; + }; + + doCheck(compilationUnit->metaType().iface()); + for (auto &&inlineData: compilationUnit->inlineComponentData) + doCheck(inlineData.qmlType.typeId().iface()); + + return result; +} + void QQmlMetaType::freeUnusedTypesAndCaches() { QQmlMetaTypeDataPtr data; @@ -1441,15 +1576,33 @@ void QQmlMetaType::freeUnusedTypesAndCaches() if (!data.isValid()) return; + bool droppedAtLeastOneComposite; + do { + droppedAtLeastOneComposite = false; + auto it = data->compositeTypes.begin(); + while (it != data->compositeTypes.end()) { + if ((*it)->count() <= doCountInternalCompositeTypeSelfReferences(data, *it)) { + it = data->compositeTypes.erase(it); + droppedAtLeastOneComposite = true; + } else { + ++it; + } + } + } while (droppedAtLeastOneComposite); + 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 && !hasActiveInlineComponents(d)) { + if (d && d->count() == 1 && !hasActiveInlineComponents(data, d)) { deletedAtLeastOneType = true; + if (d->regType == QQmlType::CompositeType + || d->regType == QQmlType::CompositeSingletonType) { + removeFromInlineComponents(data->inlineComponentTypes, d); + } removeQQmlTypePrivate(data->idToType, d); removeQQmlTypePrivate(data->nameToType, d); removeQQmlTypePrivate(data->urlToType, d); @@ -1509,7 +1662,7 @@ QList<QQmlType> QQmlMetaType::qmlTypes() const QQmlMetaTypeDataPtr data; QList<QQmlType> types; - for (QQmlTypePrivate *t : data->nameToType) + for (const QQmlTypePrivate *t : data->nameToType) types.append(QQmlType(t)); return types; @@ -1543,7 +1696,7 @@ QList<QQmlType> QQmlMetaType::qmlSingletonTypes() static bool isFullyTyped(const QQmlPrivate::CachedQmlUnit *unit) { quint32 numTypedFunctions = 0; - for (const QQmlPrivate::TypedFunction *function = unit->aotCompiledFunctions; + for (const QQmlPrivate::AOTCompiledFunction *function = unit->aotCompiledFunctions; function; ++function) { if (function->functionPtr) ++numTypedFunctions; @@ -1562,7 +1715,7 @@ const QQmlPrivate::CachedQmlUnit *QQmlMetaType::findCachedCompilationUnit( for (const auto lookup : std::as_const(data->lookupCachedQmlUnit)) { if (const QQmlPrivate::CachedQmlUnit *unit = lookup(uri)) { QString error; - if (!QV4::ExecutableCompilationUnit::verifyHeader(unit->qmlData, QDateTime(), &error)) { + if (!unit->qmlData->verifyHeader(QDateTime(), &error)) { qCDebug(DBG_DISK_CACHE) << "Error loading pre-compiled file " << uri << ":" << error; if (status) *status = CachedUnitLookupError::VersionMismatch; @@ -1651,7 +1804,8 @@ QList<QQmlProxyMetaObject::ProxyData> QQmlMetaType::proxyData(const QMetaObject QList<QQmlProxyMetaObject::ProxyData> metaObjects; mo = mo->d.superdata; - const QQmlMetaTypeDataPtr data; + if (!mo) + return metaObjects; auto createProxyMetaObject = [&](QQmlTypePrivate *This, const QMetaObject *superdataBaseMetaObject, @@ -1674,19 +1828,25 @@ QList<QQmlProxyMetaObject::ProxyData> QQmlMetaType::proxyData(const QMetaObject registerMetaObjectForType(mmo, This); }; - while (mo) { - QQmlTypePrivate *t = data->metaObjectToType.value(mo); - if (t) { + for (const QQmlMetaTypeDataPtr data; mo; mo = mo->d.superdata) { + // TODO: There can in fact be multiple QQmlTypePrivate* for a single QMetaObject*. + // This algorithm only accounts for the most recently inserted one. That's pretty + // random. However, the availability of types depends on what documents you have + // loaded before. Just adding all possible extensions would also be pretty random. + // The right way to do this would be to take the relations between the QML modules + // into account. For this we would need proper module dependency information. + if (QQmlTypePrivate *t = data->metaObjectToType.value(mo)) { if (t->regType == QQmlType::CppType) { - createProxyMetaObject(t, t->baseMetaObject, t->extraData.cd->extMetaObject, - t->extraData.cd->extFunc); + createProxyMetaObject( + t, t->baseMetaObject, t->extraData.cppTypeData->extMetaObject, + t->extraData.cppTypeData->extFunc); } else if (t->regType == QQmlType::SingletonType) { - createProxyMetaObject(t, t->baseMetaObject, t->extraData.sd->extMetaObject, - t->extraData.sd->extFunc); + createProxyMetaObject( + t, t->baseMetaObject, t->extraData.singletonTypeData->extMetaObject, + t->extraData.singletonTypeData->extFunc); } } - mo = mo->d.superdata; - } + }; return metaObjects; } @@ -1745,8 +1905,12 @@ const QMetaObject *QQmlMetaType::metaObjectForValueType(QMetaType metaType) // call QObject pointers value types. Explicitly registered types also override // the implicit use of gadgets. if (!(metaType.flags() & QMetaType::PointerToQObject)) { - if (const QMetaObject *mo = metaObjectForValueType(QQmlMetaType::qmlType(metaType))) - return mo; + const QQmlMetaTypeDataPtr data; + const QQmlTypePrivate *type = data->idToType.value(metaType.id()); + if (type && type->regType == QQmlType::CppType && type->typeId == metaType) { + if (const QMetaObject *mo = type->metaObjectForValueType()) + return mo; + } } // If it _is_ a gadget, we can just use it. @@ -1775,33 +1939,76 @@ QQmlPropertyCache::ConstPtr QQmlMetaType::findPropertyCacheInCompositeTypes(QMet return data->findPropertyCacheInCompositeTypes(t); } -void QQmlMetaType::registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit) +void QQmlMetaType::registerInternalCompositeType( + const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit) { - compilationUnit->isRegistered = true; - QQmlMetaTypeDataPtr data; - // The QQmlCompiledData is not referenced here, but it is removed from this - // hash in the QQmlCompiledData destructor - data->compositeTypes.insert(compilationUnit->typeIds.id.iface(), compilationUnit); + auto doInsert = [&data, &compilationUnit](const QtPrivate::QMetaTypeInterface *iface) { + Q_ASSERT(iface); + Q_ASSERT(compilationUnit); + + // We can't assert on anything else here. We may get a completely new type as exposed + // by the qmldiskcache test that changes a QML file in place during the execution + // of the test. + data->compositeTypes.insert(iface, compilationUnit); + }; + + doInsert(compilationUnit->metaType().iface()); for (auto &&inlineData: compilationUnit->inlineComponentData) - data->compositeTypes.insert(inlineData.typeIds.id.iface(), compilationUnit); + doInsert(inlineData.qmlType.typeId().iface()); } -void QQmlMetaType::unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit) +void QQmlMetaType::unregisterInternalCompositeType( + const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit) { - compilationUnit->isRegistered = false; + QQmlMetaTypeDataPtr data; + + auto doRemove = [&](const QtPrivate::QMetaTypeInterface *iface) { + if (!iface) + return; + + const auto it = data->compositeTypes.constFind(iface); + if (it != data->compositeTypes.constEnd() && *it == compilationUnit) + data->compositeTypes.erase(it); + }; + + doRemove(compilationUnit->metaType().iface()); + for (auto &&inlineData: compilationUnit->inlineComponentData) + doRemove(inlineData.qmlType.typeId().iface()); +} +int QQmlMetaType::countInternalCompositeTypeSelfReferences( + const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit) +{ QQmlMetaTypeDataPtr data; - data->compositeTypes.remove(compilationUnit->typeIds.id.iface()); - for (auto&& icDatum: compilationUnit->inlineComponentData) - data->compositeTypes.remove(icDatum.typeIds.id.iface()); + return doCountInternalCompositeTypeSelfReferences(data, compilationUnit); } -QV4::ExecutableCompilationUnit *QQmlMetaType::obtainExecutableCompilationUnit(QMetaType type) +QQmlRefPointer<QV4::CompiledData::CompilationUnit> QQmlMetaType::obtainCompilationUnit( + QMetaType type) { const QQmlMetaTypeDataPtr data; return data->compositeTypes.value(type.iface()); } +QQmlRefPointer<QV4::CompiledData::CompilationUnit> QQmlMetaType::obtainCompilationUnit( + const QUrl &url) +{ + const QUrl normalized = QQmlTypeLoader::normalize(url); + QQmlMetaTypeDataPtr data; + + auto found = data->urlToType.constFind(normalized); + if (found == data->urlToType.constEnd()) { + found = data->urlToNonFileImportType.constFind(normalized); + if (found == data->urlToNonFileImportType.constEnd()) + return QQmlRefPointer<QV4::CompiledData::CompilationUnit>(); + } + + const auto composite = data->compositeTypes.constFind(found.value()->typeId.iface()); + return composite == data->compositeTypes.constEnd() + ? QQmlRefPointer<QV4::CompiledData::CompilationUnit>() + : composite.value(); +} + QT_END_NAMESPACE |