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