aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2023-05-24 13:00:20 +0200
committerUlf Hermann <ulf.hermann@qt.io>2023-06-22 20:49:20 +0200
commitb48bb41681f561b59a4ce9c9d0ac95b23d5ccb1e (patch)
treefd7ab379417d79e9190544723e462813c6a3db9f /src/qml/qml
parent4a1e5d8e74e59da3191c27a732ca1a50bd2f0045 (diff)
QML: Use QQmlType as container for composite types (inline or not)
This gives us a unified interface to all kinds of QML types at run time and reduces the effort of finding corresponding type attributes. QQmlType is much larger than CompositeMetaTypeIds. Most composite types, however, are initially referenced by URL, and we call typeForUrl anyway. typeForUrl already creates a mostly functional QQmlType; we only need to add the dynamic metatypes. The same type can be retrieved later and associated with the actual CU using the compositeTypes hash. That way, we don't need any extra type. We do, however, incur the cost of creating the QMetaTypePrivate instances when first referencing a type. This could be optimized, like many things in this area, by using thread safe lazy initialization. Now some QQmlTypes implicitly depend on the CUs they were created for. This creates problems if the CUs are removed but the types still persist. Such a situation can arise if you create and delete engines. In order to avoid it, we: 1. Make the compositeTypes hold a strong reference to the CUs 2. When unlinking, avoid dropping the property caches (as those are used to hold the metaobjects) Now, however we got a cyclic reference between the CU and its QQmlType(s). To resolve this, we clear the QQmlTypes on unlinking. Finally, to avoid deletion recursion when clearing the last CUs on destruction of the QQmlMetaTypeData, we move the compilation units out of the way first. All of this still doesn't work if multiple CUs hold the same QQmlType, since compositeTypes can only hold one CU per type and that may be the one that gets removed first. Therefore, we cannot allow such a situation to happen and have to create a new QQmlType if it arises. It can only arise if you have multiple engines loading the same QML components, which should be fairly rare. For inline components, we apply a similar trick: You can either find an inline component by Url, and receive any type that matches, no matter what CU it belongs to. Or you can request an inline component type that belongs to a specific CU. It turns out we don't have to store the containing type of an IC at all. Also, we slightly change the naming of internal components' "class names" since we want to use the inline components' element names for them. Change-Id: I0ef89bd4b0a02cc927aed2525e72f6bff56df626 Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
Diffstat (limited to 'src/qml/qml')
-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
19 files changed, 479 insertions, 469 deletions
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();