aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h6
-rw-r--r--src/qml/inlinecomponentutils_p.h7
-rw-r--r--src/qml/jsruntime/qv4engine.cpp3
-rw-r--r--src/qml/jsruntime/qv4executablecompilationunit.cpp45
-rw-r--r--src/qml/jsruntime/qv4executablecompilationunit_p.h27
-rw-r--r--src/qml/jsruntime/qv4function.cpp10
-rw-r--r--src/qml/qml/qqml.cpp2
-rw-r--r--src/qml/qml/qqmlimport.cpp77
-rw-r--r--src/qml/qml/qqmlimport_p.h4
-rw-r--r--src/qml/qml/qqmlmetatype.cpp405
-rw-r--r--src/qml/qml/qqmlmetatype_p.h119
-rw-r--r--src/qml/qml/qqmlmetatypedata.cpp16
-rw-r--r--src/qml/qml/qqmlmetatypedata_p.h26
-rw-r--r--src/qml/qml/qqmlpropertycachecreator.cpp52
-rw-r--r--src/qml/qml/qqmlpropertycachecreator_p.h47
-rw-r--r--src/qml/qml/qqmlpropertyvalidator.cpp4
-rw-r--r--src/qml/qml/qqmltype.cpp20
-rw-r--r--src/qml/qml/qqmltype_p.h3
-rw-r--r--src/qml/qml/qqmltype_p_p.h6
-rw-r--r--src/qml/qml/qqmltypecompiler.cpp4
-rw-r--r--src/qml/qml/qqmltypecompiler_p.h2
-rw-r--r--src/qml/qml/qqmltypedata.cpp123
-rw-r--r--src/qml/qml/qqmltypedata_p.h6
-rw-r--r--src/qml/qml/qqmltypeloader.cpp28
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp4
-rw-r--r--tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp4
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp22
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);