diff options
27 files changed, 553 insertions, 519 deletions
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h index 4b37f48ab9..5b9c0fce60 100644 --- a/src/qml/compiler/qqmlirbuilder_p.h +++ b/src/qml/compiler/qqmlirbuilder_p.h @@ -472,6 +472,12 @@ struct Q_QML_COMPILER_PRIVATE_EXPORT Document QV4::CompiledData::CompilationUnit javaScriptCompilationUnit; + bool isSingleton() const { + return std::any_of(pragmas.constBegin(), pragmas.constEnd(), [](const Pragma *pragma) { + return pragma->type == Pragma::Singleton; + }); + } + int registerString(const QString &str) { return jsGenerator.registerString(str); } QString stringAt(int index) const { return jsGenerator.stringForIndex(index); } diff --git a/src/qml/inlinecomponentutils_p.h b/src/qml/inlinecomponentutils_p.h index 92ae719750..ba08bb5c80 100644 --- a/src/qml/inlinecomponentutils_p.h +++ b/src/qml/inlinecomponentutils_p.h @@ -58,6 +58,11 @@ public: using NodeList = std::vector<Node>; using AdjacencyList = std::vector<std::vector<Node*>>; +inline bool containedInSameType(const QQmlType &a, const QQmlType &b) +{ + return QQmlMetaType::equalBaseUrls(a.sourceUrl(), b.sourceUrl()); +} + template<typename ObjectContainer, typename InlineComponent> void fillAdjacencyListForInlineComponents(ObjectContainer *objectContainer, AdjacencyList &adjacencyList, NodeList &nodes, @@ -75,7 +80,7 @@ void fillAdjacencyListForInlineComponents(ObjectContainer *objectContainer, if (targetTypeRef) { const auto targetType = targetTypeRef->type(); if (targetType.isInlineComponentType() - && targetType.containingType() == currentICTypeRef->type().containingType()) { + && containedInSameType(targetType, currentICTypeRef->type())) { auto icIt = std::find_if(allICs.cbegin(), allICs.cend(), [&](const QV4::CompiledData::InlineComponent &icSearched){ return objectContainer->stringAt(icSearched.nameIndex) == targetType.elementName(); diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 6efe2a8597..4849886ff9 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -859,8 +859,9 @@ ExecutionEngine::~ExecutionEngine() delete identifierTable; delete memoryManager; + // Take a temporary reference to the CU so that it doesn't disappear during unlinking. while (!compilationUnits.isEmpty()) - (*compilationUnits.begin())->unlink(); + QQmlRefPointer<ExecutableCompilationUnit>(*compilationUnits.begin())->unlink(); delete bumperPointerAllocator; delete regExpCache; diff --git a/src/qml/jsruntime/qv4executablecompilationunit.cpp b/src/qml/jsruntime/qv4executablecompilationunit.cpp index 0bdf5acba4..9b4b2353c5 100644 --- a/src/qml/jsruntime/qv4executablecompilationunit.cpp +++ b/src/qml/jsruntime/qv4executablecompilationunit.cpp @@ -272,12 +272,11 @@ void ExecutableCompilationUnit::unlink() if (engine) nextCompilationUnit.remove(); - if (isRegistered) { - Q_ASSERT(data && propertyCaches.count() > 0 && propertyCaches.at(/*root object*/0)); - QQmlMetaType::unregisterInternalCompositeType(this); - } - - propertyCaches.clear(); + // Clear the QQmlTypes but not the property caches. + // The property caches may still be necessary to resolve further types. + qmlType = QQmlType(); + for (auto &ic : inlineComponentData) + ic.qmlType = QQmlType(); if (runtimeLookups) { for (uint i = 0; i < data->lookupTableSize; ++i) @@ -382,26 +381,29 @@ void processInlinComponentType( } } -void ExecutableCompilationUnit::finalizeCompositeType(CompositeMetaTypeIds types) +void ExecutableCompilationUnit::finalizeCompositeType(const QQmlType &type) { // Add to type registry of composites if (propertyCaches.needsVMEMetaObject(/*root object*/0)) { - // typeIds is only valid for types that have references to themselves. - if (!types.isValid()) - types = CompositeMetaTypeIds::fromCompositeName(rootPropertyCache()->className()); - typeIds = types; - QQmlMetaType::registerInternalCompositeType(this); + // qmlType is only valid for types that have references to themselves. + if (type.isValid()) { + qmlType = type; + } else { + qmlType = QQmlMetaType::findCompositeType( + finalUrl(), this, (unitData()->flags & CompiledData::Unit::IsSingleton) + ? QQmlMetaType::Singleton + : QQmlMetaType::NonSingleton); + } + QQmlMetaType::registerInternalCompositeType(this); } else { const QV4::CompiledData::Object *obj = objectAt(/*root object*/0); auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex); Q_ASSERT(typeRef); - if (const auto compilationUnit = typeRef->compilationUnit()) { - typeIds = compilationUnit->typeIds; - } else { - const auto type = typeRef->type(); - typeIds = CompositeMetaTypeIds{ type.typeId(), type.qListTypeId() }; - } + if (const auto compilationUnit = typeRef->compilationUnit()) + qmlType = compilationUnit->qmlType; + else + qmlType = typeRef->type(); } // Collect some data for instantiation later. @@ -520,12 +522,11 @@ bool ExecutableCompilationUnit::verifyChecksum(const CompiledData::DependentType sizeof(data->dependencyMD5Checksum)) == 0; } -CompositeMetaTypeIds ExecutableCompilationUnit::typeIdsForComponent( - const QString &inlineComponentName) const +QQmlType ExecutableCompilationUnit::qmlTypeForComponent(const QString &inlineComponentName) const { if (inlineComponentName.isEmpty()) - return typeIds; - return inlineComponentData[inlineComponentName].typeIds; + return qmlType; + return inlineComponentData[inlineComponentName].qmlType; } QStringList ExecutableCompilationUnit::moduleRequests() const diff --git a/src/qml/jsruntime/qv4executablecompilationunit_p.h b/src/qml/jsruntime/qv4executablecompilationunit_p.h index b110ea3fd1..b9ff76eab8 100644 --- a/src/qml/jsruntime/qv4executablecompilationunit_p.h +++ b/src/qml/jsruntime/qv4executablecompilationunit_p.h @@ -34,15 +34,17 @@ class QQmlEnginePrivate; struct InlineComponentData { InlineComponentData() = default; - InlineComponentData(const CompositeMetaTypeIds &typeIds, int objectIndex, int nameIndex, int totalObjectCount, int totalBindingCount, int totalParserStatusCount) - : typeIds(typeIds) - , objectIndex(objectIndex) - , nameIndex(nameIndex) - , totalObjectCount(totalObjectCount) - , totalBindingCount(totalBindingCount) - , totalParserStatusCount(totalParserStatusCount) {} - - CompositeMetaTypeIds typeIds; + InlineComponentData( + const QQmlType &qmlType, int objectIndex, int nameIndex, int totalObjectCount, + int totalBindingCount, int totalParserStatusCount) + : qmlType(qmlType) + , objectIndex(objectIndex) + , nameIndex(nameIndex) + , totalObjectCount(totalObjectCount) + , totalBindingCount(totalBindingCount) + , totalParserStatusCount(totalParserStatusCount) {} + + QQmlType qmlType; int objectIndex = -1; int nameIndex = -1; int totalObjectCount = 0; @@ -126,7 +128,7 @@ public: QHash<int, IdentifierHash> namedObjectsPerComponentCache; inline IdentifierHash namedObjectsPerComponent(int componentObjectIndex); - void finalizeCompositeType(CompositeMetaTypeIds typeIdsForComponent); + void finalizeCompositeType(const QQmlType &type); int m_totalBindingsCount = 0; // Number of bindings used in this type int m_totalParserStatusCount = 0; // Number of instantiated types that are QQmlParserStatus subclasses @@ -143,10 +145,9 @@ public: bool verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) const; - CompositeMetaTypeIds typeIdsForComponent(const QString &inlineComponentName = QString()) const; + QQmlType qmlTypeForComponent(const QString &inlineComponentName = QString()) const; - CompositeMetaTypeIds typeIds; - bool isRegistered = false; + QQmlType qmlType; QHash<QString, InlineComponentData> inlineComponentData; diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index 42f952ff19..860309a4d2 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -163,13 +163,13 @@ Function::Function(ExecutionEngine *engine, ExecutableCompilationUnit *unit, if (!qmltype.isComposite()) { if (!qmltype.isInlineComponentType()) return QMetaType(); - const CompositeMetaTypeIds typeIds = unit->typeIdsForComponent(qmltype.elementName()); - return param.isList() ? typeIds.listId : typeIds.id; + const QQmlType qmlType = unit->qmlTypeForComponent(qmltype.elementName()); + return param.isList() ? qmlType.qListTypeId() : qmlType.typeId(); } - const CompositeMetaTypeIds typeIds = enginePrivate->typeLoader.getType( - qmltype.sourceUrl())->compilationUnit()->typeIds; - return param.isList() ? typeIds.listId : typeIds.id; + const QQmlType qmlType = enginePrivate->typeLoader.getType( + qmltype.sourceUrl())->compilationUnit()->qmlType; + return param.isList() ? qmlType.qListTypeId() : qmlType.typeId(); }; for (quint16 i = 0; i < nFormals; ++i) diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp index bb740962f6..ce73e2461b 100644 --- a/src/qml/qml/qqml.cpp +++ b/src/qml/qml/qqml.cpp @@ -1824,7 +1824,7 @@ bool AOTCompiledContext::loadTypeLookup(uint index, void *target) const QMetaType metaType = typeWrapper->type().typeId(); if (!metaType.isValid()) { metaType = ep->typeLoader.getType(typeWrapper->type().sourceUrl()) - ->compilationUnit()->typeIds.id; + ->compilationUnit()->qmlType.typeId(); } *static_cast<const QMetaObject **>(target) diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index 9c6f3fade4..34830de41e 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -582,38 +582,14 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt bool ret = uri == typeStr; if (ret) { Q_ASSERT(!type_return->isValid()); - auto createICType = [&]() { - auto typePriv = new QQmlTypePrivate {QQmlType::RegistrationType::InlineComponentType}; - const QUrl ownUrl = QUrl(url); - typePriv->elementName = ownUrl.fragment(); - Q_ASSERT(!typePriv->elementName.isEmpty()); - typePriv->extraData.id->url = ownUrl; - auto icType = QQmlType(typePriv); - typePriv->release(); - return icType; - }; - if (containingType.isValid()) { - // we currently cannot reference a Singleton inside itself - // in that case, containingType is still invalid - if (QQmlType ic = QQmlMetaType::inlineComponentType(containingType, typeStr); - ic.isValid()) { - *type_return = ic; - } else { - auto icType = createICType(); - QQmlMetaType::associateInlineComponent( - containingType, typeStr, CompositeMetaTypeIds {}, icType); - *type_return = QQmlType(icType); - } - } else { - *type_return = createICType(); - } + *type_return = QQmlMetaType::inlineComponentTypeForUrl(QUrl(url)); } return ret; } QQmlDirComponents::ConstIterator it = qmlDirComponents.find(typeStr), end = qmlDirComponents.end(); if (it != end) { QString componentUrl; - bool isCompositeSingleton = false; + QQmlMetaType::CompositeTypeLookupMode lookupMode = QQmlMetaType::NonSingleton; QQmlDirComponents::ConstIterator candidate = end; for ( ; it != end && it.key() == typeStr; ++it) { const QQmlDirParser::Component &c = *it; @@ -658,7 +634,7 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt // This is our best candidate so far candidate = it; - isCompositeSingleton = c.singleton; + lookupMode = c.singleton ? QQmlMetaType::Singleton : QQmlMetaType::NonSingleton; } } } @@ -666,7 +642,7 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt if (candidate != end) { if (!base) // ensure we have a componentUrl componentUrl = resolveLocalUrl(QString(url + candidate->typeName + dotqml_string), candidate->fileName); - QQmlType returnType = QQmlMetaType::typeForUrl(componentUrl, type, isCompositeSingleton, + QQmlType returnType = QQmlMetaType::typeForUrl(componentUrl, type, lookupMode, nullptr, candidate->version); if (version_return) *version_return = candidate->version; @@ -715,7 +691,10 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt *typeRecursionDetected = recursion; if (recursionRestriction == QQmlImport::AllowRecursion || !recursion) { QQmlType returnType = QQmlMetaType::typeForUrl( - qmlUrl, type, registrationType == QQmlType::CompositeSingletonType, errors); + qmlUrl, type, registrationType == QQmlType::CompositeSingletonType + ? QQmlMetaType::Singleton + : QQmlMetaType::NonSingleton, + errors); if (type_return) *type_return = returnType; return returnType.isValid(); @@ -747,7 +726,7 @@ bool QQmlImports::resolveType( *type_return = QQmlMetaType::typeForUrl( resolveLocalUrl(nameSpace->imports.at(0)->url, unqualifiedtype.toString() + QLatin1String(".qml")), - type, false, errors); + type, QQmlMetaType::NonSingleton, errors); return type_return->isValid(); } return false; @@ -766,22 +745,8 @@ bool QQmlImports::resolveType( } else { if (resolveTypeInNamespace(splitName.at(0), &m_unqualifiedset, nullptr)) { // either simple type + inline component - const QString icName = splitName.at(1).toString(); - const QQmlType ic = QQmlMetaType::inlineComponentType(*type_return, icName); - if (ic.isValid()) { - *type_return = ic; - } else { - auto icTypePriv = new QQmlTypePrivate(QQmlType::RegistrationType::InlineComponentType); - icTypePriv->setContainingType(type_return); - icTypePriv->extraData.id->url = type_return->sourceUrl(); - icTypePriv->extraData.id->url.setFragment(icName); - auto icType = QQmlType(icTypePriv); - icTypePriv->release(); - QQmlMetaType::associateInlineComponent( - *type_return, icName, CompositeMetaTypeIds {}, icType); - *type_return = icType; - } - Q_ASSERT(type_return->containingType().isValid()); + *type_return = QQmlMetaType::inlineComponentTypeForUrl( + type_return->sourceUrl(), splitName.at(1).toString()); return true; } else { // or a failure @@ -802,21 +767,8 @@ bool QQmlImports::resolveType( error.setDescription(QQmlImportDatabase::tr("- %1 is not a namespace").arg(splitName.at(0).toString())); } else { if (resolveTypeInNamespace(splitName.at(1), s, nullptr)) { - auto const icName = splitName.at(2).toString(); - QQmlType ic = QQmlMetaType::inlineComponentType(*type_return, icName); - if (ic.isValid()) - *type_return = ic; - else { - auto icTypePriv = new QQmlTypePrivate(QQmlType::RegistrationType::InlineComponentType); - icTypePriv->setContainingType(type_return); - icTypePriv->extraData.id->url = type_return->sourceUrl(); - icTypePriv->extraData.id->url.setFragment(icName); - auto icType = QQmlType(icTypePriv); - icTypePriv->release(); - QQmlMetaType::associateInlineComponent( - *type_return, icName, CompositeMetaTypeIds {}, icType); - *type_return = icType; - } + *type_return = QQmlMetaType::inlineComponentTypeForUrl( + type_return->sourceUrl(), splitName.at(2).toString()); return true; } else { error.setDescription(QQmlImportDatabase::tr("- %1 is not a type").arg(splitName.at(1).toString())); @@ -1530,13 +1482,12 @@ QTypeRevision QQmlImports::updateQmldirContent( /*! \internal */ -bool QQmlImports::addInlineComponentImport(QQmlImportInstance *const importInstance, const QString &name, const QUrl importUrl, QQmlType containingType) +bool QQmlImports::addInlineComponentImport(QQmlImportInstance *const importInstance, const QString &name, const QUrl importUrl) { importInstance->url = importUrl.toString(); importInstance->uri = name; importInstance->isInlineComponent = true; importInstance->version = QTypeRevision::zero(); - importInstance->containingType = containingType; m_unqualifiedset.imports.push_back(importInstance); m_unqualifiedset.setNeedsSorting(true); return true; diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h index ae1bd87035..d505531d1f 100644 --- a/src/qml/qml/qqmlimport_p.h +++ b/src/qml/qml/qqmlimport_p.h @@ -56,7 +56,6 @@ struct QQmlImportInstance QString uri; // e.g. QtQuick QString url; // the base path of the import - QQmlType containingType; // points to the containing type for inline components QTypeRevision version; // the version imported bool isLibrary; // true means that this is not a file import @@ -158,8 +157,7 @@ public: } bool addInlineComponentImport( - QQmlImportInstance *const importInstance, const QString &name, const QUrl importUrl, - QQmlType containingType); + QQmlImportInstance *const importInstance, const QString &name, const QUrl importUrl); QTypeRevision addFileImport( QQmlImportDatabase *importDb, const QString &uri, const QString &prefix, diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 8610f48ca2..d969fb9ff0 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; @@ -178,6 +153,22 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el return d; } +static void addQQmlMetaTypeInterfaces(QQmlTypePrivate *priv, const QByteArray &className) +{ + 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) { @@ -186,7 +177,10 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el d->setName(QString::fromUtf8(type.uri), elementName); d->version = type.version; - d->extraData.fd->url = QQmlTypeLoader::normalize(type.url); + const QUrl normalized = QQmlTypeLoader::normalize(type.url); + d->extraData.fd->url = normalized; + addQQmlMetaTypeInterfaces( + d, QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(normalized)); return d; } @@ -199,9 +193,12 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el d->version = type.version; + const QUrl normalized = QQmlTypeLoader::normalize(type.url); d->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo; - d->extraData.sd->singletonInstanceInfo->url = QQmlTypeLoader::normalize(type.url); + d->extraData.sd->singletonInstanceInfo->url = normalized; d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName); + addQQmlMetaTypeInterfaces( + d, QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(normalized)); return d; } @@ -319,6 +316,10 @@ void QQmlMetaType::clearTypeRegistrations() 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) @@ -564,26 +565,164 @@ 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) { + 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; + } - return {ptr_type, lst_type}; + 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(); } -void QQmlMetaType::unregisterInternalCompositeType(const CompositeMetaTypeIds &typeIds) +QQmlType QQmlMetaType::findCompositeType( + const QUrl &url, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, + CompositeTypeLookupMode mode) { - QMetaType metaType(typeIds.id); - QMetaType listMetaType(typeIds.listId); + const QUrl normalized = QQmlTypeLoader::normalize(url); + QQmlMetaTypeDataPtr data; + bool urlExists = true; + auto found = data->urlToType.find(normalized); + if (found == data->urlToType.end()) { + found = data->urlToNonFileImportType.find(normalized); + if (found == data->urlToNonFileImportType.end()) + urlExists = false; + } + + if (urlExists) { + const auto composite = data->compositeTypes.constFind(found.value()->typeId.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.id->url = url; + + const QByteArray className + = QQmlPropertyCacheCreatorBase::createClassNameForInlineComponent(url, url.fragment()); + + addQQmlMetaTypeInterfaces(priv, className); + const QQmlType result(priv); + priv->release(); + + data->inlineComponentTypes.insert(url, result); + + return result; +} + +QQmlType QQmlMetaType::findInlineComponentType( + const QUrl &url, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit) +{ + 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()) { @@ -591,6 +730,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); @@ -764,25 +907,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) @@ -883,7 +1007,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 @@ -901,64 +1025,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(); + const QQmlType type = createTypeForUrl( + data, url, qualifiedType, mode, errors, version); + data->urlToType.insert(url, type.priv()); + return type; } QRecursiveMutex *QQmlMetaType::typeRegistrationLock() @@ -1285,36 +1355,17 @@ QQmlType QQmlMetaType::qmlType(const QUrl &unNormalizedUrl, bool includeNonFileI return QQmlType(); } -QQmlType QQmlMetaType::inlineComponentType(const QQmlType &containingType, const QString &name) +QQmlType QQmlMetaType::inlineComponentTypeForUrl(const QUrl &url) { - const QQmlMetaTypeDataPtr data; - return data->inlineComponentTypes[InlineComponentKey {containingType.priv(), name}]; -} - -void QQmlMetaType::associateInlineComponent( - const QQmlType &containingType, const QString &name, - const CompositeMetaTypeIds &metaTypeIds, QQmlType existingType) -{ - bool const reuseExistingType = existingType.isValid(); - auto priv = reuseExistingType - ? const_cast<QQmlTypePrivate *>(existingType.priv()) - : new QQmlTypePrivate { QQmlType::RegistrationType::InlineComponentType } ; - priv->setName( QString::fromUtf8(existingType.typeName()), name); - QUrl icUrl(existingType.sourceUrl()); - icUrl.setFragment(name); - priv->extraData.id->url = icUrl; - priv->extraData.id->containingType = containingType.priv(); - priv->typeId = metaTypeIds.id; - priv->listId = metaTypeIds.listId; - QQmlType icType(priv); - QQmlMetaTypeDataPtr data; - data->inlineComponentTypes.insert({containingType.priv(), name}, icType); + const auto it = data->inlineComponentTypes.constFind(url); + if (it != data->inlineComponentTypes.constEnd()) + return *it; - if (!reuseExistingType) - priv->release(); + return doRegisterInlineComponentType(data, url); } + /*! Returns a QQmlPropertyCache for \a obj if one is available. @@ -1475,7 +1526,7 @@ static bool hasActiveInlineComponents(const QQmlMetaTypeData *data, const QQmlTy { for (auto it = data->inlineComponentTypes.begin(), end = data->inlineComponentTypes.end(); it != end; ++it) { - if (it.key().containingType != d) + if (!QQmlMetaType::equalBaseUrls(it.key(), d->sourceUrl())) continue; const QQmlTypePrivate *icPriv = it->priv(); @@ -1831,30 +1882,66 @@ QQmlPropertyCache::ConstPtr QQmlMetaType::findPropertyCacheInCompositeTypes(QMet return data->findPropertyCacheInCompositeTypes(t); } -void QQmlMetaType::registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit) +void QQmlMetaType::registerInternalCompositeType( + const QQmlRefPointer<QV4::ExecutableCompilationUnit> &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); + const auto it = data->compositeTypes.constFind(iface); + Q_ASSERT(it == data->compositeTypes.constEnd() || *it == compilationUnit); + data->compositeTypes.insert(iface, compilationUnit); + }; + + doInsert(compilationUnit->qmlType.typeId().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::ExecutableCompilationUnit> &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->qmlType.typeId().iface()); + for (auto &&inlineData: compilationUnit->inlineComponentData) + doRemove(inlineData.qmlType.typeId().iface()); +} + +int QQmlMetaType::countInternalCompositeTypeSelfReferences( + const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit) +{ QQmlMetaTypeDataPtr data; - data->compositeTypes.remove(compilationUnit->typeIds.id.iface()); - for (auto&& icDatum: compilationUnit->inlineComponentData) - data->compositeTypes.remove(icDatum.typeIds.id.iface()); + + 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->qmlType.typeId().iface()); + for (auto &&inlineData: compilationUnit->inlineComponentData) + doCheck(inlineData.qmlType.typeId().iface()); + + return result; } -QV4::ExecutableCompilationUnit *QQmlMetaType::obtainExecutableCompilationUnit(QMetaType type) +QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlMetaType::obtainExecutableCompilationUnit( + QMetaType type) { const QQmlMetaTypeDataPtr data; return data->compositeTypes.value(type.iface()); diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index 8a5776c569..2478f0efc1 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -30,74 +30,55 @@ class QQmlValueType; namespace QV4 { class ExecutableCompilationUnit; } -struct CompositeMetaTypeIds -{ -private: - int *refCount = nullptr; - void deref(); - void ref() - { - Q_ASSERT(refCount); - ++*refCount; - } -public: - CompositeMetaTypeIds() = default; - CompositeMetaTypeIds(QMetaType id, QMetaType listId) : id(id), listId(listId) {} - CompositeMetaTypeIds(const CompositeMetaTypeIds &other) - : refCount(other.refCount), id(other.id), listId(other.listId) - { - if (refCount) - ref(); - } - CompositeMetaTypeIds(CompositeMetaTypeIds &&other) - : refCount(other.refCount), id(other.id), listId(other.listId) - { - other.refCount = nullptr; - } - CompositeMetaTypeIds &operator=(const CompositeMetaTypeIds &other) - { - if (refCount) - deref(); - refCount = other.refCount; - id = other.id; - listId = other.listId; - if (refCount) - ref(); - return *this; - } - CompositeMetaTypeIds &operator=(CompositeMetaTypeIds &&other) - { - if (refCount) - deref(); - refCount = other.refCount; - id = other.id; - listId = other.listId; - other.refCount = nullptr; - return *this; - } - ~CompositeMetaTypeIds(); - static CompositeMetaTypeIds fromCompositeName(const QByteArray &name); -public: - QMetaType id; - QMetaType listId; - bool isValid() const { return id.isValid() && listId.isValid(); } -}; - class Q_QML_PRIVATE_EXPORT QQmlMetaType { - friend struct CompositeMetaTypeIds; friend class QQmlDesignerMetaObject; - static CompositeMetaTypeIds registerInternalCompositeType(const QByteArray &className); - static void unregisterInternalCompositeType(const CompositeMetaTypeIds &typeIds); - public: + enum class RegistrationResult { Success, Failure, NoRegistrationFunction }; + static QUrl inlineComponentUrl(const QUrl &baseUrl, const QString &name) + { + QUrl icUrl = baseUrl; + icUrl.setFragment(name); + return icUrl; + } + + static bool equalBaseUrls(const QUrl &aUrl, const QUrl &bUrl) + { + // Everything but fragment has to match + return aUrl.port() == bUrl.port() + && aUrl.scheme() == bUrl.scheme() + && aUrl.userName() == bUrl.userName() + && aUrl.password() == bUrl.password() + && aUrl.host() == bUrl.host() + && aUrl.path() == bUrl.path() + && aUrl.query() == bUrl.query(); + } + + enum CompositeTypeLookupMode { + NonSingleton, + Singleton, + }; + + static QQmlType findCompositeType( + const QUrl &url, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, + CompositeTypeLookupMode mode = NonSingleton); + static QQmlType findInlineComponentType( + const QUrl &url, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit); + static QQmlType findInlineComponentType( + const QUrl &baseUrl, const QString &name, + const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit) + { + return findInlineComponentType(inlineComponentUrl(baseUrl, name), compilationUnit); + } + + static void unregisterInternalCompositeType(QMetaType metaType, QMetaType listMetaType); static QQmlType registerType(const QQmlPrivate::RegisterType &type); static QQmlType registerInterface(const QQmlPrivate::RegisterInterface &type); static QQmlType registerSingletonType(const QQmlPrivate::RegisterSingletonType &type); @@ -106,9 +87,15 @@ public: static RegistrationResult registerPluginTypes(QObject *instance, const QString &basePath, const QString &uri, const QString &typeNamespace, QTypeRevision version, QList<QQmlError> *errors); + static QQmlType typeForUrl(const QString &urlString, const QHashedStringRef& typeName, - bool isCompositeSingleton, QList<QQmlError> *errors, + CompositeTypeLookupMode mode, QList<QQmlError> *errors, QTypeRevision version = QTypeRevision()); + static QQmlType inlineComponentTypeForUrl(const QUrl &url); + static QQmlType inlineComponentTypeForUrl(const QUrl &baseUrl, const QString &name) + { + return inlineComponentTypeForUrl(inlineComponentUrl(baseUrl, name)); + } static void unregisterType(int type); @@ -143,8 +130,6 @@ public: static QQmlType qmlListType(QMetaType metaType); static QQmlType qmlType(const QUrl &unNormalizedUrl, bool includeNonFileImports = false); - static QQmlType inlineComponentType(const QQmlType &containingType, const QString &name); - static void associateInlineComponent(const QQmlType &containingType, const QString &name, const CompositeMetaTypeIds &metaTypeIds, QQmlType existingType); static QQmlPropertyCache::ConstPtr propertyCache( QObject *object, QTypeRevision version = QTypeRevision()); @@ -219,8 +204,9 @@ public: static void removeFromInlineComponents( InlineComponentContainer &container, const QQmlTypePrivate *reference) { + const QUrl referenceUrl = QQmlType(reference).sourceUrl(); for (auto it = container.begin(), end = container.end(); it != end;) { - if (it.key().containingType == reference) + if (equalBaseUrls(it.key(), referenceUrl)) it = container.erase(it); else ++it; @@ -281,9 +267,14 @@ public: } static QQmlPropertyCache::ConstPtr findPropertyCacheInCompositeTypes(QMetaType t); - static void registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit); - static void unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit); - static QV4::ExecutableCompilationUnit *obtainExecutableCompilationUnit(QMetaType type); + static void registerInternalCompositeType( + const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit); + static void unregisterInternalCompositeType( + const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit); + static int countInternalCompositeTypeSelfReferences( + const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit); + static QQmlRefPointer<QV4::ExecutableCompilationUnit> obtainExecutableCompilationUnit( + QMetaType type); }; Q_DECLARE_TYPEINFO(QQmlMetaType, Q_RELOCATABLE_TYPE); diff --git a/src/qml/qml/qqmlmetatypedata.cpp b/src/qml/qml/qqmlmetatypedata.cpp index a7d546fb1a..aff847c396 100644 --- a/src/qml/qml/qqmlmetatypedata.cpp +++ b/src/qml/qml/qqmlmetatypedata.cpp @@ -15,8 +15,12 @@ QQmlMetaTypeData::QQmlMetaTypeData() QQmlMetaTypeData::~QQmlMetaTypeData() { - for (auto iter = compositeTypes.cbegin(), end = compositeTypes.cend(); iter != end; ++iter) - iter.value()->isRegistered = false; + { + // Unregister all remaining composite types. + // Avoid deletion recursion (via QQmlTypePrivate dtor) by moving them out of the way first. + CompositeTypes emptyComposites; + emptyComposites.swap(compositeTypes); + } propertyCaches.clear(); // Do this before the attached properties disappear. @@ -237,13 +241,11 @@ QQmlPropertyCache::ConstPtr QQmlMetaTypeData::propertyCache( } static QQmlPropertyCache::ConstPtr propertyCacheForPotentialInlineComponentType( - QMetaType t, - const QHash<const QtPrivate::QMetaTypeInterface *, - QV4::ExecutableCompilationUnit *>::const_iterator &iter) { - if (t != (*iter)->typeIds.id) { + QMetaType t, const QQmlMetaTypeData::CompositeTypes::const_iterator &iter) { + if (t != (*iter)->qmlType.typeId()) { // this is an inline component, and what we have in the iterator is currently the parent compilation unit for (auto &&icDatum: (*iter)->inlineComponentData) - if (icDatum.typeIds.id == t) + if (icDatum.qmlType.typeId() == t) return (*iter)->propertyCaches.at(icDatum.objectIndex); } return (*iter)->rootPropertyCache(); diff --git a/src/qml/qml/qqmlmetatypedata_p.h b/src/qml/qml/qqmlmetatypedata_p.h index d50b23f864..4af8818e91 100644 --- a/src/qml/qml/qqmlmetatypedata_p.h +++ b/src/qml/qml/qqmlmetatypedata_p.h @@ -25,23 +25,6 @@ QT_BEGIN_NAMESPACE -struct InlineComponentKey -{ - const QQmlTypePrivate *containingType = nullptr; - QString name; - -private: - friend bool operator==(const InlineComponentKey &a, const InlineComponentKey &b) - { - return a.containingType == b.containingType && a.name == b.name; - } - - friend size_t qHash(const InlineComponentKey &byId, size_t seed = 0) - { - return qHashMulti(seed, byId.containingType, byId.name); - } -}; - class QQmlTypePrivate; struct QQmlMetaTypeData { @@ -56,7 +39,7 @@ struct QQmlMetaTypeData using Names = QMultiHash<QHashedString, const QQmlTypePrivate *>; Names nameToType; - typedef QHash<QUrl, QQmlTypePrivate *> Files; //For file imported composite types only + typedef QHash<QUrl, const 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 @@ -66,8 +49,11 @@ struct QQmlMetaTypeData MetaObjects metaObjectToType; QVector<QHash<QTypeRevision, QQmlPropertyCache::ConstPtr>> typePropertyCaches; QHash<int, QQmlValueType *> metaTypeToValueType; - QHash<const QtPrivate::QMetaTypeInterface *, QV4::ExecutableCompilationUnit *> compositeTypes; - QHash<InlineComponentKey, QQmlType> inlineComponentTypes; + + using CompositeTypes = QHash<const QtPrivate::QMetaTypeInterface *, + QQmlRefPointer<QV4::ExecutableCompilationUnit>>; + CompositeTypes compositeTypes; + QHash<QUrl, QQmlType> inlineComponentTypes; struct VersionedUri { VersionedUri() = default; diff --git a/src/qml/qml/qqmlpropertycachecreator.cpp b/src/qml/qml/qqmlpropertycachecreator.cpp index d71a2d0086..7415d5eb65 100644 --- a/src/qml/qml/qqmlpropertycachecreator.cpp +++ b/src/qml/qml/qqmlpropertycachecreator.cpp @@ -66,29 +66,55 @@ QMetaType QQmlPropertyCacheCreatorBase::listTypeForPropertyType(QV4::CompiledDat return QMetaType {}; } -QByteArray QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(const QUrl &url) +template<typename BaseNameHandler, typename FailHandler> +auto processUrlForClassName( + const QUrl &url, BaseNameHandler &&baseNameHandler, FailHandler &&failHandler) { const QString path = url.path(); - int lastSlash = path.lastIndexOf(QLatin1Char('/')); + // Not a reusable type if we don't have an absolute Url + const qsizetype lastSlash = path.lastIndexOf(QLatin1Char('/')); if (lastSlash <= -1) - return QByteArray(); + return failHandler(); + // ### this might not be correct for .ui.qml files - const QStringView nameBase = QStringView{path}.mid(lastSlash + 1, path.size() - lastSlash - 5); + const QStringView baseName = QStringView{path}.mid(lastSlash + 1, path.size() - lastSlash - 5); + // Not a reusable type if it doesn't start with a upper case letter. - if (nameBase.isEmpty() || !nameBase.at(0).isUpper()) + return (!baseName.isEmpty() && baseName.at(0).isUpper()) + ? baseNameHandler(baseName) + : failHandler(); +} + +bool QQmlPropertyCacheCreatorBase::canCreateClassNameTypeByUrl(const QUrl &url) +{ + return processUrlForClassName(url, [](QStringView) { + return true; + }, []() { + return false; + }); +} + +QByteArray QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(const QUrl &url) +{ + return processUrlForClassName(url, [](QStringView nameBase) { + return QByteArray(nameBase.toUtf8() + "_QMLTYPE_" + + QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1))); + }, []() { return QByteArray(); - return nameBase.toUtf8() + "_QMLTYPE_" + - QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)); + }); } -QByteArray QQmlPropertyCacheCreatorBase::createClassNameForInlineComponent(const QUrl &baseUrl, int icId) +QByteArray QQmlPropertyCacheCreatorBase::createClassNameForInlineComponent( + const QUrl &baseUrl, const QString &name) { - QByteArray baseName = createClassNameTypeByUrl(baseUrl); - if (baseName.isEmpty()) - baseName = QByteArray("ANON_QML_IC_") + QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)); - baseName += "_" + QByteArray::number(icId); - return baseName; + QByteArray baseName = processUrlForClassName(baseUrl, [](QStringView nameBase) { + return QByteArray(nameBase.toUtf8() + "_QMLTYPE_"); + }, []() { + return QByteArray("ANON_QML_IC_"); + }); + return baseName + name.toUtf8() + '_' + + QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)); } QQmlBindingInstantiationContext::QQmlBindingInstantiationContext( diff --git a/src/qml/qml/qqmlpropertycachecreator_p.h b/src/qml/qml/qqmlpropertycachecreator_p.h index 568e5cac0f..f7d27d113b 100644 --- a/src/qml/qml/qqmlpropertycachecreator_p.h +++ b/src/qml/qml/qqmlpropertycachecreator_p.h @@ -69,9 +69,10 @@ public: static QMetaType metaTypeForPropertyType(QV4::CompiledData::CommonType type); static QMetaType listTypeForPropertyType(QV4::CompiledData::CommonType type); + static bool canCreateClassNameTypeByUrl(const QUrl &url); static QByteArray createClassNameTypeByUrl(const QUrl &url); - static QByteArray createClassNameForInlineComponent(const QUrl &baseUrl, int icId); + static QByteArray createClassNameForInlineComponent(const QUrl &baseUrl, const QString &name); struct IncrementalResult { // valid if and only if an error occurred @@ -157,7 +158,7 @@ inline QQmlPropertyCacheCreator<ObjectContainer>::QQmlPropertyCacheCreator(QQmlP , typeClassName(typeClassName) , currentRoot(-1) { - propertyCaches->resize(objectContainer->objectCount()); + propertyCaches->resetAndResize(objectContainer->objectCount()); using namespace icutils; @@ -626,35 +627,29 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject( // inline components are not necessarily valid yet Q_ASSERT(qmltype.isValid() || qmltype.isInlineComponentType()); if (qmltype.isComposite() || qmltype.isInlineComponentType()) { - CompositeMetaTypeIds typeIds; + QQmlType compositeType; if (qmltype.isInlineComponentType()) { const QString icName = qmltype.elementName(); - auto containingType = qmltype.containingType(); - if (containingType.isValid()) { - const QQmlType icType - = QQmlMetaType::inlineComponentType(containingType, icName); - typeIds = {icType.typeId(), icType.qListTypeId()}; - } else { - typeIds = {}; - } - if (!typeIds.isValid()) // type has not been registered yet, we must be in containing type - typeIds = objectContainer->typeIdsForComponent(icName); - Q_ASSERT(typeIds.isValid()); + compositeType = QQmlMetaType::inlineComponentTypeForUrl( + qmltype.sourceUrl(), icName); + if (!compositeType.isValid()) // type has not been registered yet, we must be in containing type + compositeType = objectContainer->qmlTypeForComponent(icName); + Q_ASSERT(compositeType.isValid()); } else if (selfReference) { - typeIds = objectContainer->typeIdsForComponent(); + compositeType = objectContainer->qmlTypeForComponent(); } else { QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl()); Q_ASSERT(tdata); Q_ASSERT(tdata->isComplete()); auto compilationUnit = tdata->compilationUnit(); - typeIds = compilationUnit->typeIdsForComponent(); + compositeType = compilationUnit->qmlTypeForComponent(); } if (p->isList()) { - propertyType = typeIds.listId; + propertyType = compositeType.qListTypeId(); } else { - propertyType = typeIds.id; + propertyType = compositeType.typeId(); } } else { if (p->isList()) @@ -714,16 +709,16 @@ inline QMetaType QQmlPropertyCacheCreator<ObjectContainer>::metaTypeForParameter if (!qmltype.isComposite()) { const QMetaType typeId = param.isList() ? qmltype.qListTypeId() : qmltype.typeId(); if (!typeId.isValid() && qmltype.isInlineComponentType()) { - const auto typeIds = objectContainer->typeIdsForComponent(qmltype.elementName()); - return param.isList() ? typeIds.listId : typeIds.id; + const QQmlType qmlType = objectContainer->qmlTypeForComponent(qmltype.elementName()); + return param.isList() ? qmlType.qListTypeId() : qmlType.typeId(); } else { return typeId; } } if (selfReference) { - const auto typeIds = objectContainer->typeIdsForComponent(); - return param.isList() ? typeIds.listId : typeIds.id; + const QQmlType qmlType = objectContainer->qmlTypeForComponent(); + return param.isList() ? qmlType.qListTypeId() : qmlType.typeId(); } QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl()); @@ -732,7 +727,9 @@ inline QMetaType QQmlPropertyCacheCreator<ObjectContainer>::metaTypeForParameter auto compilationUnit = tdata->compilationUnit(); - return param.isList() ? compilationUnit->typeIds.listId : compilationUnit->typeIds.id; + return param.isList() + ? compilationUnit->qmlType.qListTypeId() + : compilationUnit->qmlType.typeId(); } template <typename ObjectContainer> @@ -825,11 +822,11 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor if (referencedType.isValid()) { *type = referencedType.typeId(); if (!type->isValid() && referencedType.isInlineComponentType()) { - *type = objectContainer->typeIdsForComponent(referencedType.elementName()).id; + *type = objectContainer->qmlTypeForComponent(referencedType.elementName()).typeId(); Q_ASSERT(type->isValid()); } } else { - *type = typeRef->compilationUnit()->typeIds.id; + *type = typeRef->compilationUnit()->qmlType.typeId(); } *version = typeRef->version(); diff --git a/src/qml/qml/qqmlpropertyvalidator.cpp b/src/qml/qml/qqmlpropertyvalidator.cpp index 4f7663b34d..764e8b4938 100644 --- a/src/qml/qml/qqmlpropertyvalidator.cpp +++ b/src/qml/qml/qqmlpropertyvalidator.cpp @@ -643,7 +643,7 @@ bool QQmlPropertyValidator::canCoerce(QMetaType to, QQmlPropertyCache::ConstPtr // only occurs after the whole file has been validated // Therefore we need to check the ICs here for (const auto& icDatum : compilationUnit->inlineComponentData) { - if (icDatum.typeIds.id == to) { + if (icDatum.qmlType.typeId() == to) { toMo = compilationUnit->propertyCaches.at(icDatum.objectIndex); break; } @@ -753,7 +753,7 @@ QQmlError QQmlPropertyValidator::validateObjectBinding(const QQmlPropertyData *p // only occurs after the whole file has been validated // Therefore we need to check the ICs here for (const auto& icDatum: compilationUnit->inlineComponentData) { - if (icDatum.typeIds.id == property->propType()) { + if (icDatum.qmlType.typeId() == property->propType()) { propertyMetaObject = compilationUnit->propertyCaches.at(icDatum.objectIndex); break; } diff --git a/src/qml/qml/qqmltype.cpp b/src/qml/qml/qqmltype.cpp index 46ba0b0829..939522e85e 100644 --- a/src/qml/qml/qqmltype.cpp +++ b/src/qml/qml/qqmltype.cpp @@ -68,6 +68,12 @@ QQmlTypePrivate::~QQmlTypePrivate() qDeleteAll(scopedEnums); for (const auto &metaObject : metaObjects) free(metaObject.metaObject); + + if (const auto &iface = typeId.iface()) { + if (iface->metaObjectFn == &dynamicQmlMetaObject) + QQmlMetaType::unregisterInternalCompositeType(typeId, listId); + } + switch (regType) { case QQmlType::CppType: delete extraData.cd->customParser; @@ -404,12 +410,6 @@ void QQmlTypePrivate::insertEnumsFromPropertyCache( insertEnums(cppMetaObject); } -void QQmlTypePrivate::setContainingType(QQmlType *containingType) -{ - Q_ASSERT(regType == QQmlType::InlineComponentType); - extraData.id->containingType = containingType->d.data(); -} - void QQmlTypePrivate::setName(const QString &uri, const QString &element) { module = uri; @@ -928,14 +928,6 @@ int QQmlType::refCount(const QQmlTypePrivate *priv) return -1; } -QQmlType QQmlType::containingType() const -{ - Q_ASSERT(d && d->regType == QQmlType::RegistrationType::InlineComponentType); - auto ret = QQmlType {d->extraData.id->containingType}; - Q_ASSERT(!ret.isInlineComponentType()); - return ret; -} - void QQmlType::createProxy(QObject *instance) const { if (!d->metaObjects.isEmpty()) diff --git a/src/qml/qml/qqmltype_p.h b/src/qml/qml/qqmltype_p.h index 6adce672b2..2e5a501f64 100644 --- a/src/qml/qml/qqmltype_p.h +++ b/src/qml/qml/qqmltype_p.h @@ -39,7 +39,6 @@ class QQmlPropertyCache; namespace QV4 { struct String; } -struct CompositeMetaTypeIds; class Q_QML_PRIVATE_EXPORT QQmlType { @@ -159,8 +158,6 @@ public: AnyRegistrationType = 255 }; - QQmlType containingType() const; - void createProxy(QObject *instance) const; private: diff --git a/src/qml/qml/qqmltype_p_p.h b/src/qml/qml/qqmltype_p_p.h index 71394e8a7c..f6567b6ed5 100644 --- a/src/qml/qml/qqmltype_p_p.h +++ b/src/qml/qml/qqmltype_p_p.h @@ -36,7 +36,6 @@ public: void initEnums(QQmlEnginePrivate *engine) const; void insertEnums(const QMetaObject *metaObject) const; void insertEnumsFromPropertyCache(const QQmlPropertyCache::ConstPtr &cache) const; - void setContainingType(QQmlType *containingType); QUrl sourceUrl() const { @@ -111,11 +110,6 @@ public: struct QQmlInlineTypeData { QUrl url; - // The containing type stores a pointer to the inline component type - // Using QQmlType here would create a reference cycle - // As the inline component type cannot outlive the containing type - // this should still be fine - QQmlTypePrivate const * containingType = nullptr; }; using QQmlSequenceTypeData = QMetaSequence; diff --git a/src/qml/qml/qqmltypecompiler.cpp b/src/qml/qml/qqmltypecompiler.cpp index 7b9ee544ea..b921463eb6 100644 --- a/src/qml/qml/qqmltypecompiler.cpp +++ b/src/qml/qml/qqmltypecompiler.cpp @@ -259,9 +259,9 @@ void QQmlTypeCompiler::addImport(const QString &module, const QString &qualifier document->imports.append(import); } -CompositeMetaTypeIds QQmlTypeCompiler::typeIdsForComponent(const QString &inlineComponentName) const +QQmlType QQmlTypeCompiler::qmlTypeForComponent(const QString &inlineComponentName) const { - return typeData->typeIds(inlineComponentName); + return typeData->qmlType(inlineComponentName); } QQmlCompilePass::QQmlCompilePass(QQmlTypeCompiler *typeCompiler) diff --git a/src/qml/qml/qqmltypecompiler_p.h b/src/qml/qml/qqmltypecompiler_p.h index 54c5710ecd..a379946664 100644 --- a/src/qml/qml/qqmltypecompiler_p.h +++ b/src/qml/qml/qqmltypecompiler_p.h @@ -108,7 +108,7 @@ public: return resolvedTypes->value(id); } - CompositeMetaTypeIds typeIdsForComponent(const QString &inlineComponentName = QString()) const; + QQmlType qmlTypeForComponent(const QString &inlineComponentName = QString()) const; private: QList<QQmlError> errors; diff --git a/src/qml/qml/qqmltypedata.cpp b/src/qml/qml/qqmltypedata.cpp index b74e24e614..0ed0253a3e 100644 --- a/src/qml/qml/qqmltypedata.cpp +++ b/src/qml/qml/qqmltypedata.cpp @@ -74,11 +74,11 @@ void QQmlTypeData::unregisterCallback(TypeDataCallback *callback) Q_ASSERT(!m_callbacks.contains(callback)); } -CompositeMetaTypeIds QQmlTypeData::typeIds(const QString &inlineComponentName) const +QQmlType QQmlTypeData::qmlType(const QString &inlineComponentName) const { if (inlineComponentName.isEmpty()) - return m_typeIds; - return m_inlineComponentData[inlineComponentName].typeIds; + return m_qmlType; + return m_inlineComponentData[inlineComponentName].qmlType; } bool QQmlTypeData::tryLoadFromDiskCache() @@ -168,7 +168,7 @@ bool QQmlTypeData::tryLoadFromDiskCache() auto importUrl = finalUrl(); importUrl.setFragment(nameString); auto import = new QQmlImportInstance(); - m_importCache->addInlineComponentImport(import, nameString, importUrl, QQmlType()); + m_importCache->addInlineComponentImport(import, nameString, importUrl); } return true; @@ -289,13 +289,18 @@ namespace { template<typename ObjectContainer> void setupICs( const ObjectContainer &container, QHash<QString, InlineComponentData> *icData, - const QUrl &finalUrl) { + const QUrl &baseUrl, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit) { Q_ASSERT(icData->empty()); for (int i = 0; i != container->objectCount(); ++i) { auto root = container->objectAt(i); for (auto it = root->inlineComponentsBegin(); it != root->inlineComponentsEnd(); ++it) { - const QByteArray &className = QQmlPropertyCacheCreatorBase::createClassNameForInlineComponent(finalUrl, it->objectIndex); - InlineComponentData icDatum(CompositeMetaTypeIds::fromCompositeName(className), int(it->objectIndex), int(it->nameIndex), 0, 0, 0); + // We cannot re-use a previously finalized inline component type here. We need our own. + // We can and should re-use speculative type references, though. + InlineComponentData icDatum( + QQmlMetaType::findInlineComponentType( + baseUrl, container->stringAt(it->nameIndex), compilationUnit), + int(it->objectIndex), int(it->nameIndex), 0, 0, 0); + icData->insert(container->stringAt(it->nameIndex), icDatum); } } @@ -370,15 +375,11 @@ void QQmlTypeData::done() ++it) { const TypeReference &type = *it; Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError() || type.type.isInlineComponentType()); - const QQmlType containingType = type.type.isInlineComponentType() - ? type.type.containingType() - : QQmlType(); - if (containingType.isValid()) { - const QQmlType ic = QQmlMetaType::inlineComponentType( - containingType, type.type.elementName()); - - // Only if we create the IC from an actual CU, we have valid metatypes. - if (!ic.typeId().isValid()) { + + if (type.type.isInlineComponentType()) { + const QUrl url = type.type.sourceUrl(); + if (!QQmlMetaType::equalBaseUrls(url, finalUrl()) + && !QQmlMetaType::obtainExecutableCompilationUnit(type.type.typeId())) { const QString &typeName = stringAt(it.key()); int lastDot = typeName.lastIndexOf(u'.'); createError( @@ -407,16 +408,22 @@ void QQmlTypeData::done() } } - m_typeClassName = QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(finalUrl()); - if (!m_typeClassName.isEmpty()) - m_typeIds = CompositeMetaTypeIds::fromCompositeName(m_typeClassName); - - if (m_document) { - setupICs(m_document, &m_inlineComponentData, finalUrl()); - } else { - setupICs(m_compiledData, &m_inlineComponentData, finalUrl()); + if (QQmlPropertyCacheCreatorBase::canCreateClassNameTypeByUrl(finalUrl())) { + const bool isSingleton = m_document + ? m_document.data()->isSingleton() + : (m_compiledData->unitData()->flags & QV4::CompiledData::Unit::IsSingleton); + m_qmlType = QQmlMetaType::findCompositeType( + finalUrl(), m_compiledData, isSingleton + ? QQmlMetaType::Singleton + : QQmlMetaType::NonSingleton); + m_typeClassName = QByteArray(m_qmlType.typeId().name()).chopped(1); } + if (m_document) + setupICs(m_document, &m_inlineComponentData, finalUrl(), m_compiledData); + else + setupICs(m_compiledData, &m_inlineComponentData, finalUrl(), m_compiledData); + QV4::ResolvedTypeReferenceMap resolvedTypeCache; QQmlRefPointer<QQmlTypeNameCache> typeNameCache; { @@ -502,7 +509,7 @@ void QQmlTypeData::done() } } - m_compiledData->finalizeCompositeType(typeIds()); + m_compiledData->finalizeCompositeType(qmlType()); } { @@ -530,34 +537,6 @@ void QQmlTypeData::done() } } - // associate inline components to root component - { - auto fileName = finalUrl().fileName(); - QStringView typeName = [&]() { - // extract base name (QFileInfo::baseName would require constructing a QFileInfo) - auto dotIndex = fileName.indexOf(u'.'); - if (dotIndex < 0) - return QStringView(); - return QStringView(fileName).first(dotIndex); - }(); - // typeName can be empty if a QQmlComponent was constructed with an empty QUrl parameter - if (!typeName.isEmpty() && typeName.at(0).isUpper() && !m_inlineComponentData.isEmpty()) { - QHashedStringRef const hashedStringRef { typeName }; - QList<QQmlError> errors; - auto type = QQmlMetaType::typeForUrl(finalUrlString(), hashedStringRef, false, &errors); - Q_ASSERT(errors.empty()); - if (type.isValid()) { - for (auto const &icDatum : std::as_const(m_inlineComponentData)) { - Q_ASSERT(icDatum.typeIds.isValid()); - const QString icName = m_compiledData->stringAt(icDatum.nameIndex); - QQmlType existingType = QQmlMetaType::inlineComponentType(type, icName); - QQmlMetaType::associateInlineComponent( - type, icName, icDatum.typeIds, existingType); - } - } - } - } - { // Collect imported scripts m_compiledData->dependentScripts.reserve(m_scripts.size()); @@ -706,18 +685,13 @@ void QQmlTypeData::restoreIR(QV4::CompiledData::CompilationUnit &&unit) void QQmlTypeData::continueLoadFromIR() { - QQmlType containingType; - auto containingTypeName = finalUrl().fileName().split(QLatin1Char('.')).first(); - QTypeRevision version; - QQmlImportNamespace *ns = nullptr; - m_importCache->resolveType(containingTypeName, &containingType, &version, &ns); for (auto const& object: m_document->objects) { for (auto it = object->inlineComponentsBegin(); it != object->inlineComponentsEnd(); ++it) { QString const nameString = m_document->stringAt(it->nameIndex); auto importUrl = finalUrl(); importUrl.setFragment(nameString); auto import = new QQmlImportInstance(); // Note: The cache takes ownership of the QQmlImportInstance - m_importCache->addInlineComponentImport(import, nameString, importUrl, containingType); + m_importCache->addInlineComponentImport(import, nameString, importUrl); } } @@ -925,11 +899,11 @@ void QQmlTypeData::resolveTypes() addDependency(ref.typeData.data()); } if (ref.type.isInlineComponentType()) { - auto containingType = ref.type.containingType(); - if (containingType.isValid()) { - auto const url = containingType.sourceUrl(); - if (url.isValid()) { - auto typeData = typeLoader()->getType(url); + QUrl containingTypeUrl = ref.type.sourceUrl(); + containingTypeUrl.setFragment(QString()); + if (!containingTypeUrl.isEmpty()) { + auto typeData = typeLoader()->getType(containingTypeUrl); + if (typeData.data() != this) { ref.typeData = typeData; addDependency(typeData.data()); } @@ -972,11 +946,7 @@ QQmlError QQmlTypeData::buildTypeResolutionCaches( ref->setCompilationUnit(resolvedType->typeData->compilationUnit()); if (resolvedType->type.isInlineComponentType()) { // Inline component which is part of an already resolved type - QString icName; - if (qmlType.containingType().isValid()) - icName = qmlType.elementName(); - else - icName = resolvedType->type.elementName(); + QString icName = qmlType.elementName(); Q_ASSERT(!icName.isEmpty()); const auto compilationUnit = resolvedType->typeData->compilationUnit(); @@ -986,14 +956,17 @@ QQmlError QQmlTypeData::buildTypeResolutionCaches( Q_ASSERT(ref->type().isInlineComponentType()); } } else if (resolvedType->type.isInlineComponentType()) { - // Inline component, defined in the file we are currently compiling ref->setType(qmlType); - if (qmlType.isValid()) { + + // Inline component + // If it's defined in the same file we're currently compiling, we don't want to use it. + // We're going to fill in the property caches later after all. + if (qmlType.isValid() + && !QQmlMetaType::equalBaseUrls(finalUrl(), qmlType.sourceUrl())) { + // this is required for inline components in singletons - const QMetaType type - = QQmlMetaType::inlineComponentType(qmlType, qmlType.elementName()).typeId(); - auto exUnit = QQmlMetaType::obtainExecutableCompilationUnit(type); - if (exUnit) { + const QMetaType type = qmlType.typeId(); + if (auto exUnit = QQmlMetaType::obtainExecutableCompilationUnit(type)) { ref->setCompilationUnit(exUnit); ref->setTypePropertyCache(QQmlMetaType::propertyCacheForType(type)); } diff --git a/src/qml/qml/qqmltypedata_p.h b/src/qml/qml/qqmltypedata_p.h index 2c9058dc26..4803497945 100644 --- a/src/qml/qml/qqmltypedata_p.h +++ b/src/qml/qml/qqmltypedata_p.h @@ -68,7 +68,7 @@ public: void registerCallback(TypeDataCallback *); void unregisterCallback(TypeDataCallback *); - CompositeMetaTypeIds typeIds(const QString &inlineComponentName = QString()) const; + QQmlType qmlType(const QString &inlineComponentName = QString()) const; QByteArray typeClassName() const { return m_typeClassName; } SourceCodeData backupSourceCode() const { return m_backupSourceCode; } @@ -120,8 +120,8 @@ private: QMap<int, TypeReference> m_resolvedTypes; bool m_typesResolved:1; - // Used for self-referencing types, otherwise -1. - CompositeMetaTypeIds m_typeIds; + // Used for self-referencing types, otherwise invalid. + QQmlType m_qmlType; QByteArray m_typeClassName; // used for meta-object later using ExecutableCompilationUnitPtr = QQmlRefPointer<QV4::ExecutableCompilationUnit>; diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 804becccc2..4f84fa6be4 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -1338,15 +1338,29 @@ void QQmlTypeLoader::trimCache() // typeData->m_compiledData may be set early on in the proccess of loading a file, so // it's important to check the general loading status of the typeData before making any // other decisions. - if (typeData->count() == 1 && (typeData->isError() || typeData->isComplete()) - && (!typeData->m_compiledData || typeData->m_compiledData->count() == 1)) { - // There are no live objects of this type - iter.value()->release(); - iter = m_typeCache.erase(iter); - deletedOneType = true; - } else { + if (typeData->count() != 1 || (!typeData->isError() && !typeData->isComplete())) { ++iter; + continue; + } + + const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit + = typeData->m_compiledData; + if (compilationUnit) { + if (compilationUnit->count() + > QQmlMetaType::countInternalCompositeTypeSelfReferences( + compilationUnit) + 1) { + ++iter; + continue; + } + + QQmlMetaType::unregisterInternalCompositeType(compilationUnit); + Q_ASSERT(compilationUnit->count() == 1); } + + // There are no live objects of this type + iter.value()->release(); + iter = m_typeCache.erase(iter); + deletedOneType = true; } if (!deletedOneType) diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index 5c0806e57a..07a9d998aa 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -379,11 +379,13 @@ static ReturnedValue instanceOfQObject(const QV4::QQmlTypeWrapper *typeWrapper, QQmlEnginePrivate *qenginepriv = QQmlEnginePrivate::get(engine->qmlEngine()); QQmlRefPointer<QQmlTypeData> td = qenginepriv->typeLoader.getType(typeWrapper->d()->type().sourceUrl()); if (ExecutableCompilationUnit *cu = td->compilationUnit()) - myQmlType = QQmlMetaType::metaObjectForType(cu->typeIds.id); + myQmlType = QQmlMetaType::metaObjectForType(cu->qmlType.typeId()); else return Encode(false); // It seems myQmlType has some errors, so we could not compile it. } else { myQmlType = QQmlMetaType::metaObjectForType(myTypeId); + if (myQmlType.isNull()) + return Encode(false); } const QMetaObject *theirType = wrapperObject->metaObject(); diff --git a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp index c629651040..db9701d033 100644 --- a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp +++ b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp @@ -2029,6 +2029,10 @@ void tst_QmlCppCodegen::invisibleListElementType() void tst_QmlCppCodegen::invisibleSingleton() { + // We may have seen Style.qml as singleton before, which would make the assignment pass. + // So let's flush the type registry. + qmlClearTypeRegistrations(); + QQmlEngine engine; const QUrl copy(u"qrc:/qt/qml/TestTypes/hidden/Main.qml"_s); QQmlComponent c(&engine, copy); diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 0960a8e64c..93d68dcb84 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -5762,7 +5762,7 @@ void tst_qqmllanguage::selfReference() const QMetaObject *metaObject = o->metaObject(); QMetaProperty selfProperty = metaObject->property(metaObject->indexOfProperty("self")); - QCOMPARE(selfProperty.metaType().id(), compilationUnit->typeIds.id.id()); + QCOMPARE(selfProperty.metaType().id(), compilationUnit->qmlType.typeId().id()); QByteArray typeName = selfProperty.typeName(); QVERIFY(typeName.endsWith('*')); @@ -5771,7 +5771,7 @@ void tst_qqmllanguage::selfReference() QMetaMethod selfFunction = metaObject->method(metaObject->indexOfMethod("returnSelf()")); QVERIFY(selfFunction.isValid()); - QCOMPARE(selfFunction.returnType(), compilationUnit->typeIds.id.id()); + QCOMPARE(selfFunction.returnType(), compilationUnit->qmlType.typeId().id()); QMetaMethod selfSignal; @@ -5785,7 +5785,7 @@ void tst_qqmllanguage::selfReference() QVERIFY(selfSignal.isValid()); QCOMPARE(selfSignal.parameterCount(), 1); - QCOMPARE(selfSignal.parameterType(0), compilationUnit->typeIds.id.id()); + QCOMPARE(selfSignal.parameterType(0), compilationUnit->qmlType.typeId().id()); } void tst_qqmllanguage::selfReferencingSingleton() @@ -6772,11 +6772,17 @@ void tst_qqmllanguage::bareInlineComponent() QVERIFY(type.module().isEmpty()); tab1Found = true; - const QQmlType leftTab = QQmlMetaType::inlineComponentType(type, "LeftTab"); - QCOMPARE(leftTab.containingType(), type); - - const QQmlType rightTab = QQmlMetaType::inlineComponentType(type, "RightTab"); - QCOMPARE(rightTab.containingType(), type); + const QQmlType leftTab = QQmlMetaType::inlineComponentTypeForUrl( + type.sourceUrl(), "LeftTab"); + QUrl leftUrl = leftTab.sourceUrl(); + leftUrl.setFragment(QString()); + QCOMPARE(leftUrl, type.sourceUrl()); + + const QQmlType rightTab = QQmlMetaType::inlineComponentTypeForUrl( + type.sourceUrl(), "RightTab"); + QUrl rightUrl = rightTab.sourceUrl(); + rightUrl.setFragment(QString()); + QCOMPARE(rightUrl, type.sourceUrl()); } } QVERIFY(tab1Found); |