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.cpp1674
1 files changed, 1113 insertions, 561 deletions
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index c21247bb95..1175bde3db 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -1,49 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlmetatype_p.h"
+#include <private/qqmlextensionplugin_p.h>
#include <private/qqmlmetatypedata_p.h>
-#include <private/qqmltypemodule_p_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>
#include <QtCore/qcoreapplication.h>
@@ -51,6 +17,7 @@
#include <QtCore/qloggingcategory.h>
Q_DECLARE_LOGGING_CATEGORY(DBG_DISK_CACHE)
+Q_LOGGING_CATEGORY(lcTypeRegistration, "qt.qml.typeregistration")
QT_BEGIN_NAMESPACE
@@ -62,6 +29,12 @@ struct LockedData : private QQmlMetaTypeData
Q_GLOBAL_STATIC(LockedData, metaTypeData)
Q_GLOBAL_STATIC(QRecursiveMutex, metaTypeDataLock)
+struct ModuleUri : public QString
+{
+ ModuleUri(const QString &string) : QString(string) {}
+ ModuleUri(const std::unique_ptr<QQmlTypeModule> &module) : QString(module->module()) {}
+};
+
class QQmlMetaTypeDataPtr
{
Q_DISABLE_COPY_MOVE(QQmlMetaTypeDataPtr)
@@ -80,7 +53,7 @@ public:
bool isValid() const { return data != nullptr; }
private:
- QMutexLocker locker;
+ QMutexLocker<QRecursiveMutex> locker;
LockedData *data = nullptr;
};
@@ -88,45 +61,35 @@ 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 = true;
- d->version_maj = 0;
- d->version_min = 0;
+ 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);
d->setName(QString::fromUtf8(type.uri), elementName);
- d->version_maj = type.versionMajor;
- d->version_min = type.versionMinor;
-
- if (type.qobjectApi || (type.version >= 3 && type.generalizedQobjectApi)) {
- if (type.version >= 1) // static metaobject added in version 1
- d->baseMetaObject = type.instanceMetaObject;
- if (type.version >= 2) // typeId added in version 2
- d->typeId = type.typeId;
- if (type.version >= 2) // revisions added in version 2
- d->revision = type.revision;
- }
+ d->version = type.version;
- d->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo;
- d->extraData.sd->singletonInstanceInfo->scriptCallback = type.scriptApi;
- if (type.version >= 3) {
- d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.generalizedQobjectApi;
- } else {
- d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.qobjectApi;
+ if (type.qObjectApi) {
+ d->baseMetaObject = type.instanceMetaObject;
+ d->typeId = type.typeId;
+ d->revision = type.revision;
}
- d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName);
- d->extraData.sd->singletonInstanceInfo->instanceMetaObject
- = ((type.qobjectApi || (type.version >= 3 && type.generalizedQobjectApi) ) && type.version >= 1) ? type.instanceMetaObject : nullptr;
+
+ d->extraData.singletonTypeData->singletonInstanceInfo = siinfo;
+ d->extraData.singletonTypeData->extFunc = type.extensionObjectCreate;
+ d->extraData.singletonTypeData->extMetaObject = type.extensionMetaObject;
return d;
}
@@ -138,72 +101,111 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el
data->registerType(d);
d->setName(QString::fromUtf8(type.uri), elementName);
- d->version_maj = type.versionMajor;
- d->version_min = type.versionMinor;
- if (type.version >= 1) // revisions added in version 1
- d->revision = type.revision;
+ d->version = type.version;
+ d->revision = type.revision;
d->typeId = type.typeId;
d->listId = type.listId;
- d->extraData.cd->allocationSize = type.objectSize;
- d->extraData.cd->newFunc = type.create;
- d->extraData.cd->noCreationReason = type.noCreationReason;
+ 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->extFunc = type.extensionObjectCreate;
- d->extraData.cd->customParser = reinterpret_cast<QQmlCustomParser *>(type.customParser);
- d->extraData.cd->registerEnumClassesUnscoped = true;
+ 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.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.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 indexOfClassInfo = d->baseMetaObject->indexOfClassInfo("RegisterEnumClassesUnscoped");
- if (indexOfClassInfo != -1 && QString::fromUtf8(d->baseMetaObject->classInfo(indexOfClassInfo).value()) == QLatin1String("false"))
- d->extraData.cd->registerEnumClassesUnscoped = false;
+ auto indexOfUnscoped = d->baseMetaObject->indexOfClassInfo("RegisterEnumClassesUnscoped");
+ if (indexOfUnscoped != -1
+ && qstrcmp(d->baseMetaObject->classInfo(indexOfUnscoped).value(), "false") == 0) {
+ d->extraData.cppTypeData->registerEnumClassesUnscoped = false;
+ }
+
+ auto indexOfRelated = d->baseMetaObject->indexOfClassInfo("RegisterEnumsFromRelatedTypes");
+ if (indexOfRelated != -1
+ && qstrcmp(d->baseMetaObject->classInfo(indexOfRelated).value(), "false") == 0) {
+ 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_maj = type.versionMajor;
- d->version_min = type.versionMinor;
-
- d->extraData.fd->url = QQmlTypeLoader::normalize(type.url);
+ d->version = type.version;
+ 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_maj = type.versionMajor;
- d->version_min = type.versionMinor;
+ 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;
}
void QQmlMetaType::clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
- const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd)
+ const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd,
+ QQmlMetaType::ClonePolicy policy)
{
// Set classname
- builder.setClassName(ignoreEnd->className());
+ builder.setClassName(mo->className());
// Clone Q_CLASSINFO
for (int ii = mo->classInfoOffset(); ii < mo->classInfoCount(); ++ii) {
@@ -217,44 +219,45 @@ void QQmlMetaType::clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
}
}
- // Clone Q_PROPERTY
- for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) {
- QMetaProperty property = mo->property(ii);
+ if (policy != QQmlMetaType::CloneEnumsOnly) {
+ // Clone Q_METHODS - do this first to avoid duplicating the notify signals.
+ for (int ii = mo->methodOffset(); ii < mo->methodCount(); ++ii) {
+ QMetaMethod method = mo->method(ii);
- int otherIndex = ignoreEnd->indexOfProperty(property.name());
- if (otherIndex >= ignoreStart->propertyOffset() + ignoreStart->propertyCount()) {
- builder.addProperty(QByteArray("__qml_ignore__") + property.name(), QByteArray("void"));
- // Skip
- } else {
- builder.addProperty(property);
- }
- }
+ // More complex - need to search name
+ QByteArray name = method.name();
- // Clone Q_METHODS
- for (int ii = mo->methodOffset(); ii < mo->methodCount(); ++ii) {
- QMetaMethod method = mo->method(ii);
+ bool found = false;
- // More complex - need to search name
- QByteArray name = method.name();
+ for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount();
+ !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount(); ++ii) {
+ QMetaMethod other = ignoreEnd->method(ii);
- bool found = false;
+ found = name == other.name();
+ }
- for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount();
- !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount();
- ++ii) {
+ QMetaMethodBuilder m = builder.addMethod(method);
+ if (found) // SKIP
+ m.setAccess(QMetaMethod::Private);
+ }
- QMetaMethod other = ignoreEnd->method(ii);
+ // Clone Q_PROPERTY
+ for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) {
+ QMetaProperty property = mo->property(ii);
- found = name == other.name();
+ int otherIndex = ignoreEnd->indexOfProperty(property.name());
+ if (otherIndex >= ignoreStart->propertyOffset() + ignoreStart->propertyCount()) {
+ builder.addProperty(QByteArray("__qml_ignore__") + property.name(),
+ QByteArray("void"));
+ // Skip
+ } else {
+ builder.addProperty(property);
+ }
}
-
- QMetaMethodBuilder m = builder.addMethod(method);
- if (found) // SKIP
- m.setAccess(QMetaMethod::Private);
}
- // Clone Q_ENUMS
+ // Clone enums registered with the metatype system
for (int ii = mo->enumeratorOffset(); ii < mo->enumeratorCount(); ++ii) {
QMetaEnum enumerator = mo->enumerator(ii);
@@ -267,21 +270,32 @@ void QQmlMetaType::clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
}
}
-void QQmlMetaType::qmlInsertModuleRegistration(const QString &uri, int majorVersion,
- void (*registerFunction)())
+void QQmlMetaType::qmlInsertModuleRegistration(const QString &uri, void (*registerFunction)())
{
- const QQmlMetaTypeData::VersionedUri versionedUri(uri, majorVersion);
QQmlMetaTypeDataPtr data;
- if (data->moduleTypeRegistrationFunctions.contains(versionedUri))
- qFatal("Canot add multiple registrations for %s %d", qPrintable(uri), majorVersion);
+ if (data->moduleTypeRegistrationFunctions.contains(uri))
+ qFatal("Cannot add multiple registrations for %s", qPrintable(uri));
else
- data->moduleTypeRegistrationFunctions.insert(versionedUri, registerFunction);
+ data->moduleTypeRegistrationFunctions.insert(uri, registerFunction);
}
-void QQmlMetaType::qmlRegisterModuleTypes(const QString &uri, int majorVersion)
+void QQmlMetaType::qmlRemoveModuleRegistration(const QString &uri)
{
QQmlMetaTypeDataPtr data;
- data->registerModuleTypes(QQmlMetaTypeData::VersionedUri(uri, majorVersion));
+
+ if (!data.isValid())
+ return; // shutdown/deletion race. Not a problem.
+
+ if (!data->moduleTypeRegistrationFunctions.contains(uri))
+ qFatal("Cannot remove multiple registrations for %s", qPrintable(uri));
+ else
+ data->moduleTypeRegistrationFunctions.remove(uri);
+}
+
+bool QQmlMetaType::qmlRegisterModuleTypes(const QString &uri)
+{
+ QQmlMetaTypeDataPtr data;
+ return data->registerModuleTypes(uri);
}
void QQmlMetaType::clearTypeRegistrations()
@@ -289,9 +303,7 @@ void QQmlMetaType::clearTypeRegistrations()
//Only cleans global static, assumed no running engine
QQmlMetaTypeDataPtr data;
- for (QQmlMetaTypeData::TypeModules::const_iterator i = data->uriToModule.constBegin(), cend = data->uriToModule.constEnd(); i != cend; ++i)
- delete *i;
-
+ data->uriToModule.clear();
data->types.clear();
data->idToType.clear();
data->nameToType.clear();
@@ -299,17 +311,33 @@ void QQmlMetaType::clearTypeRegistrations()
data->typePropertyCaches.clear();
data->urlToNonFileImportType.clear();
data->metaObjectToType.clear();
- data->uriToModule.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 &autoparent)
+int QQmlMetaType::registerAutoParentFunction(const QQmlPrivate::RegisterAutoParent &function)
{
+ if (function.structVersion > 1)
+ qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
+
QQmlMetaTypeDataPtr data;
- data->parentFunctions.append(autoparent.function);
+ data->parentFunctions.append(function.function);
- return data->parentFunctions.count() - 1;
+ return data->parentFunctions.size() - 1;
}
void QQmlMetaType::unregisterAutoParentFunction(const QQmlPrivate::AutoParentFunction &function)
@@ -320,30 +348,23 @@ void QQmlMetaType::unregisterAutoParentFunction(const QQmlPrivate::AutoParentFun
QQmlType QQmlMetaType::registerInterface(const QQmlPrivate::RegisterInterface &type)
{
- if (type.version > 0)
+ if (type.structVersion > 1)
qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
QQmlMetaTypeDataPtr data;
QQmlTypePrivate *priv = createQQmlType(data, type);
Q_ASSERT(priv);
- data->idToType.insert(priv->typeId, priv);
- data->idToType.insert(priv->listId, priv);
- // XXX No insertMulti, so no multi-version interfaces?
- if (!priv->elementName.isEmpty())
- data->nameToType.insert(priv->elementName, priv);
- if (data->interfaces.size() <= type.typeId)
- data->interfaces.resize(type.typeId + 16);
- if (data->lists.size() <= type.listId)
- data->lists.resize(type.listId + 16);
- data->interfaces.setBit(type.typeId, true);
- data->lists.setBit(type.listId, true);
+ data->idToType.insert(priv->typeId.id(), priv);
+ data->idToType.insert(priv->listId.id(), priv);
+
+ data->interfaces.insert(type.typeId.id());
return QQmlType(priv);
}
-QString registrationTypeString(QQmlType::RegistrationType typeType)
+static QString registrationTypeString(QQmlType::RegistrationType typeType)
{
QString typeStr;
if (typeType == QQmlType::CppType)
@@ -352,27 +373,43 @@ QString registrationTypeString(QQmlType::RegistrationType typeType)
typeStr = QStringLiteral("singleton type");
else if (typeType == QQmlType::CompositeSingletonType)
typeStr = QStringLiteral("composite singleton type");
+ else if (typeType == QQmlType::SequentialContainerType)
+ typeStr = QStringLiteral("sequential container type");
else
typeStr = QStringLiteral("type");
return typeStr;
}
// NOTE: caller must hold a QMutexLocker on "data"
-bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *data,
- const char *uri, const QString &typeName, int majorVersion)
+static bool checkRegistration(
+ QQmlType::RegistrationType typeType, QQmlMetaTypeData *data, const char *uri,
+ const QString &typeName, QTypeRevision version, QMetaType::TypeFlags flags)
{
if (!typeName.isEmpty()) {
- if (typeName.at(0).isLower()) {
+ if (typeName.at(0).isLower() && (flags & QMetaType::PointerToQObject)) {
QString failure(QCoreApplication::translate("qmlRegisterType", "Invalid QML %1 name \"%2\"; type names must begin with an uppercase letter"));
- data->recordTypeRegFailure(failure.arg(registrationTypeString(typeType)).arg(typeName));
+ data->recordTypeRegFailure(failure.arg(registrationTypeString(typeType), typeName));
return false;
}
- int typeNameLen = typeName.length();
+ if (typeName.at(0).isUpper()
+ && (flags & (QMetaType::IsGadget | QMetaType::PointerToGadget))) {
+ qCWarning(lcTypeRegistration).noquote()
+ << QCoreApplication::translate(
+ "qmlRegisterType",
+ "Invalid QML %1 name \"%2\"; "
+ "value type names should begin with a lowercase letter")
+ .arg(registrationTypeString(typeType), typeName);
+ }
+
+ // There can also be types that aren't even gadgets, and there can be types for namespaces.
+ // We cannot check those, but namespaces should be uppercase.
+
+ int typeNameLen = typeName.size();
for (int ii = 0; ii < typeNameLen; ++ii) {
- if (!(typeName.at(ii).isLetterOrNumber() || typeName.at(ii) == '_')) {
+ if (!(typeName.at(ii).isLetterOrNumber() || typeName.at(ii) == u'_')) {
QString failure(QCoreApplication::translate("qmlRegisterType", "Invalid QML %1 name \"%2\""));
- data->recordTypeRegFailure(failure.arg(registrationTypeString(typeType)).arg(typeName));
+ data->recordTypeRegFailure(failure.arg(registrationTypeString(typeType), typeName));
return false;
}
}
@@ -380,16 +417,15 @@ bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *da
if (uri && !typeName.isEmpty()) {
QString nameSpace = QString::fromUtf8(uri);
- QQmlMetaTypeData::VersionedUri versionedUri;
- versionedUri.uri = nameSpace;
- versionedUri.majorVersion = majorVersion;
- if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0)){
- if (qqtm->isLocked()){
- QString failure(QCoreApplication::translate("qmlRegisterType",
- "Cannot install %1 '%2' into protected module '%3' version '%4'"));
- data->recordTypeRegFailure(failure.arg(registrationTypeString(typeType)).arg(typeName).arg(nameSpace).arg(majorVersion));
- return false;
- }
+ QQmlTypeModule *qqtm = data->findTypeModule(nameSpace, version);
+ if (qqtm && qqtm->lockLevel() != QQmlTypeModule::LockLevel::Open) {
+ QString failure(QCoreApplication::translate(
+ "qmlRegisterType",
+ "Cannot install %1 '%2' into protected module '%3' version '%4'"));
+ data->recordTypeRegFailure(failure
+ .arg(registrationTypeString(typeType), typeName, nameSpace)
+ .arg(version.majorVersion()));
+ return false;
}
}
@@ -397,46 +433,40 @@ bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *da
}
// NOTE: caller must hold a QMutexLocker on "data"
-QQmlTypeModule *getTypeModule(const QHashedString &uri, int majorVersion, QQmlMetaTypeData *data)
+static QQmlTypeModule *getTypeModule(
+ const QHashedString &uri, QTypeRevision version, QQmlMetaTypeData *data)
{
- QQmlMetaTypeData::VersionedUri versionedUri(uri, majorVersion);
- QQmlTypeModule *module = data->uriToModule.value(versionedUri);
- if (!module) {
- module = new QQmlTypeModule(versionedUri.uri, versionedUri.majorVersion);
- data->uriToModule.insert(versionedUri, module);
- }
- return module;
+ if (QQmlTypeModule *module = data->findTypeModule(uri, version))
+ return module;
+ return data->addTypeModule(std::make_unique<QQmlTypeModule>(uri, version.majorVersion()));
}
// NOTE: caller must hold a QMutexLocker on "data"
-void addTypeToData(QQmlTypePrivate *type, QQmlMetaTypeData *data)
+static void addTypeToData(QQmlTypePrivate *type, QQmlMetaTypeData *data)
{
Q_ASSERT(type);
if (!type->elementName.isEmpty())
- data->nameToType.insertMulti(type->elementName, type);
+ data->nameToType.insert(type->elementName, type);
if (type->baseMetaObject)
- data->metaObjectToType.insertMulti(type->baseMetaObject, type);
+ data->metaObjectToType.insert(type->baseMetaObject, type);
- if (type->typeId) {
- data->idToType.insert(type->typeId, type);
- if (data->objects.size() <= type->typeId)
- data->objects.resize(type->typeId + 16);
- data->objects.setBit(type->typeId, true);
- }
+ if (type->regType == QQmlType::SequentialContainerType) {
+ if (type->listId.isValid())
+ data->idToType.insert(type->listId.id(), type);
+ } else {
+ if (type->typeId.isValid())
+ data->idToType.insert(type->typeId.id(), type);
- if (type->listId) {
- if (data->lists.size() <= type->listId)
- data->lists.resize(type->listId + 16);
- data->lists.setBit(type->listId, true);
- data->idToType.insert(type->listId, type);
+ if (type->listId.flags().testFlag(QMetaType::IsQmlList))
+ data->idToType.insert(type->listId.id(), type);
}
if (!type->module.isEmpty()) {
const QHashedString &mod = type->module;
- QQmlTypeModule *module = getTypeModule(mod, type->version_maj, data);
+ QQmlTypeModule *module = getTypeModule(mod, type->version, data);
Q_ASSERT(module);
module->add(type);
}
@@ -444,38 +474,52 @@ void addTypeToData(QQmlTypePrivate *type, QQmlMetaTypeData *data)
QQmlType QQmlMetaType::registerType(const QQmlPrivate::RegisterType &type)
{
+ if (type.structVersion > int(QQmlPrivate::RegisterType::CurrentVersion))
+ qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
+
QQmlMetaTypeDataPtr data;
QString elementName = QString::fromUtf8(type.elementName);
- if (!checkRegistration(QQmlType::CppType, data, type.uri, elementName, type.versionMajor))
+ if (!checkRegistration(QQmlType::CppType, data, type.uri, elementName, type.version,
+ QMetaType(type.typeId).flags())) {
return QQmlType();
+ }
QQmlTypePrivate *priv = createQQmlType(data, elementName, type);
-
addTypeToData(priv, data);
- if (!type.typeId)
- data->idToType.insert(priv->typeId, priv);
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.");
+
QQmlMetaTypeDataPtr data;
QString typeName = QString::fromUtf8(type.typeName);
- if (!checkRegistration(QQmlType::SingletonType, data, type.uri, typeName, type.versionMajor))
+ if (!checkRegistration(QQmlType::SingletonType, data, type.uri, typeName, type.version,
+ QMetaType(type.typeId).flags())) {
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.");
+
// Assumes URL is absolute and valid. Checking of user input should happen before the URL enters type.
QQmlMetaTypeDataPtr data;
@@ -484,21 +528,24 @@ QQmlType QQmlMetaType::registerCompositeSingletonType(const QQmlPrivate::Registe
if (*(type.uri) == '\0')
fileImport = true;
if (!checkRegistration(QQmlType::CompositeSingletonType, data, fileImport ? nullptr : type.uri,
- typeName, type.versionMajor)) {
+ typeName, type.version, {})) {
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->insertMulti(QQmlTypeLoader::normalize(type.url), priv);
+ files->insert(siinfo->url, priv);
return QQmlType(priv);
}
QQmlType QQmlMetaType::registerCompositeType(const QQmlPrivate::RegisterCompositeType &type)
{
+ if (type.structVersion > 1)
+ qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
+
// Assumes URL is absolute and valid. Checking of user input should happen before the URL enters type.
QQmlMetaTypeDataPtr data;
@@ -506,61 +553,209 @@ QQmlType QQmlMetaType::registerCompositeType(const QQmlPrivate::RegisterComposit
bool fileImport = false;
if (*(type.uri) == '\0')
fileImport = true;
- if (!checkRegistration(QQmlType::CompositeType, data, fileImport?nullptr:type.uri, typeName, type.versionMajor))
+ if (!checkRegistration(QQmlType::CompositeType, data, fileImport?nullptr:type.uri, typeName,
+ type.version, {})) {
return QQmlType();
+ }
QQmlTypePrivate *priv = createQQmlType(data, typeName, type);
addTypeToData(priv, data);
QQmlMetaTypeData::Files *files = fileImport ? &(data->urlToType) : &(data->urlToNonFileImportType);
- files->insertMulti(QQmlTypeLoader::normalize(type.url), priv);
+ files->insert(QQmlTypeLoader::normalize(type.url), priv);
return QQmlType(priv);
}
-void QQmlMetaType::registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit)
+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;
+};
+
+
+static QQmlType createTypeForUrl(
+ QQmlMetaTypeData *data, const QUrl &url, const QHashedStringRef &qualifiedType,
+ QQmlMetaType::CompositeTypeLookupMode mode, QList<QQmlError> *errors, QTypeRevision version)
{
- QByteArray name = compilationUnit->rootPropertyCache()->className();
+ 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.
- QByteArray ptr = name + '*';
- QByteArray lst = "QQmlListProperty<" + name + '>';
+ 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;
+ }
- int ptr_type = QMetaType::registerNormalizedType(ptr,
- QtMetaTypePrivate::QMetaTypeFunctionHelper<QObject*>::Destruct,
- QtMetaTypePrivate::QMetaTypeFunctionHelper<QObject*>::Construct,
- sizeof(QObject*),
- static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QObject*>::Flags),
- nullptr);
- int lst_type = QMetaType::registerNormalizedType(lst,
- QtMetaTypePrivate::QMetaTypeFunctionHelper<QQmlListProperty<QObject> >::Destruct,
- QtMetaTypePrivate::QMetaTypeFunctionHelper<QQmlListProperty<QObject> >::Construct,
- sizeof(QQmlListProperty<QObject>),
- static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QQmlListProperty<QObject> >::Flags),
- static_cast<QMetaObject*>(nullptr));
+ data->registerType(priv);
+ addTypeToData(priv, data);
+ return QQmlType(priv);
+ }
- compilationUnit->metaTypeId = ptr_type;
- compilationUnit->listMetaTypeId = lst_type;
+ // 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;
- data->qmlLists.insert(lst_type, ptr_type);
+
+ 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;
}
-void QQmlMetaType::unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit)
+static QQmlType doRegisterInlineComponentType(QQmlMetaTypeData *data, const QUrl &url)
{
- int ptr_type = compilationUnit->metaTypeId;
- int lst_type = compilationUnit->listMetaTypeId;
+ 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 result;
+}
+QQmlType QQmlMetaType::findInlineComponentType(
+ const QUrl &url, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
+{
QQmlMetaTypeDataPtr data;
- data->qmlLists.remove(lst_type);
- QMetaType::unregisterType(ptr_type);
- QMetaType::unregisterType(lst_type);
+ // 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()) {
+ if (QQmlValueType *vt = data->metaTypeToValueType.take(metaType.id()))
+ 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);
+ QMetaType::unregisterMetaType(listMetaType);
+ delete static_cast<const QQmlMetaTypeInterface *>(metaType.iface());
+ delete static_cast<const QQmlListMetaTypeInterface *>(listMetaType.iface());
}
int QQmlMetaType::registerUnitCacheHook(
const QQmlPrivate::RegisterQmlUnitCacheHook &hookRegistration)
{
- if (hookRegistration.version > 0)
+ if (hookRegistration.structVersion > 1)
qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
QQmlMetaTypeDataPtr data;
@@ -568,40 +763,135 @@ int QQmlMetaType::registerUnitCacheHook(
return 0;
}
-bool QQmlMetaType::protectModule(const QString &uri, int majVersion)
+QQmlType QQmlMetaType::registerSequentialContainer(
+ const QQmlPrivate::RegisterSequentialContainer &container)
{
+ if (container.structVersion > 1)
+ qFatal("qmlRegisterSequenceContainer(): Cannot mix incompatible QML versions.");
+
QQmlMetaTypeDataPtr data;
- QQmlMetaTypeData::VersionedUri versionedUri;
- versionedUri.uri = uri;
- versionedUri.majorVersion = majVersion;
+ if (!checkRegistration(QQmlType::SequentialContainerType, data, container.uri, QString(),
+ container.version, {})) {
+ return QQmlType();
+ }
+
+ QQmlTypePrivate *priv = new QQmlTypePrivate(QQmlType::SequentialContainerType);
- if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0)) {
- qqtm->lock();
- return true;
+ data->registerType(priv);
+ priv->setName(QString::fromUtf8(container.uri), QString());
+ priv->version = container.version;
+ priv->revision = container.revision;
+ priv->typeId = container.metaSequence.valueMetaType();
+ priv->listId = container.typeId;
+ priv->extraData.sequentialContainerTypeData = container.metaSequence;
+
+ addTypeToData(priv, data);
+
+ return QQmlType(priv);
+}
+
+void QQmlMetaType::unregisterSequentialContainer(int id)
+{
+ unregisterType(id);
+}
+
+bool QQmlMetaType::protectModule(const QString &uri, QTypeRevision version,
+ bool weakProtectAllVersions)
+{
+ QQmlMetaTypeDataPtr data;
+ if (version.hasMajorVersion()) {
+ if (QQmlTypeModule *module = data->findTypeModule(uri, version)) {
+ if (!weakProtectAllVersions) {
+ module->setLockLevel(QQmlTypeModule::LockLevel::Strong);
+ return true;
+ }
+ } else {
+ return false;
+ }
}
- return false;
+
+ const auto range = std::equal_range(
+ data->uriToModule.begin(), data->uriToModule.end(), uri,
+ std::less<ModuleUri>());
+
+ for (auto it = range.first; it != range.second; ++it)
+ (*it)->setLockLevel(QQmlTypeModule::LockLevel::Weak);
+
+ return range.first != range.second;
+}
+
+void QQmlMetaType::registerModuleImport(const QString &uri, QTypeRevision moduleVersion,
+ const QQmlDirParser::Import &import)
+{
+ QQmlMetaTypeDataPtr data;
+
+ data->moduleImports.insert(QQmlMetaTypeData::VersionedUri(uri, moduleVersion), import);
}
-void QQmlMetaType::registerModule(const char *uri, int versionMajor, int versionMinor)
+void QQmlMetaType::unregisterModuleImport(const QString &uri, QTypeRevision moduleVersion,
+ const QQmlDirParser::Import &import)
{
QQmlMetaTypeDataPtr data;
+ data->moduleImports.remove(QQmlMetaTypeData::VersionedUri(uri, moduleVersion), import);
+}
- QQmlTypeModule *module = getTypeModule(QString::fromUtf8(uri), versionMajor, data);
+QList<QQmlDirParser::Import> QQmlMetaType::moduleImports(
+ const QString &uri, QTypeRevision version)
+{
+ QQmlMetaTypeDataPtr data;
+ QList<QQmlDirParser::Import> result;
+
+ const auto unrevisioned = data->moduleImports.equal_range(
+ QQmlMetaTypeData::VersionedUri(uri, QTypeRevision()));
+ for (auto it = unrevisioned.second; it != unrevisioned.first;)
+ result.append(*(--it));
+
+ if (version.hasMajorVersion()) {
+ const auto revisioned = data->moduleImports.equal_range(
+ QQmlMetaTypeData::VersionedUri(uri, version));
+ for (auto it = revisioned.second; it != revisioned.first;)
+ result.append(*(--it));
+ return result;
+ }
+
+ // Use latest module available with that URI.
+ const auto begin = data->moduleImports.begin();
+ auto it = unrevisioned.first;
+ if (it == begin)
+ return result;
+
+ const QQmlMetaTypeData::VersionedUri latestVersion = (--it).key();
+ if (latestVersion.uri != uri)
+ return result;
+
+ do {
+ result += *it;
+ } while (it != begin && (--it).key() == latestVersion);
+
+ return result;
+}
+
+void QQmlMetaType::registerModule(const char *uri, QTypeRevision version)
+{
+ QQmlMetaTypeDataPtr data;
+
+ QQmlTypeModule *module = getTypeModule(QString::fromUtf8(uri), version, data);
Q_ASSERT(module);
- module->addMinorVersion(versionMinor);
+ if (version.hasMinorVersion())
+ module->addMinorVersion(version.minorVersion());
}
-int QQmlMetaType::typeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
+int QQmlMetaType::typeId(const char *uri, QTypeRevision version, const char *qmlName)
{
QQmlMetaTypeDataPtr data;
- QQmlTypeModule *module = getTypeModule(QString::fromUtf8(uri), versionMajor, data);
+ QQmlTypeModule *module = getTypeModule(QString::fromUtf8(uri), version, data);
if (!module)
return -1;
- QQmlType type = module->type(QHashedStringRef(QString::fromUtf8(qmlName)), versionMinor);
+ QQmlType type = module->type(QHashedStringRef(QString::fromUtf8(qmlName)), version);
if (!type.isValid())
return -1;
@@ -615,40 +905,21 @@ void QQmlMetaType::registerUndeletableType(const QQmlType &dtype)
}
static bool namespaceContainsRegistrations(const QQmlMetaTypeData *data, const QString &uri,
- int majorVersion)
+ QTypeRevision version)
{
// Has any type previously been installed to this namespace?
QHashedString nameSpace(uri);
for (const QQmlType &type : data->types) {
- if (type.module() == nameSpace && type.majorVersion() == majorVersion)
+ if (type.module() == nameSpace && type.version().majorVersion() == version.majorVersion())
return true;
}
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;
-};
-
-
-bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePath,
- const QString &uri, const QString &typeNamespace, int vmaj,
- QList<QQmlError> *errors)
+QQmlMetaType::RegistrationResult QQmlMetaType::registerPluginTypes(
+ QObject *instance, const QString &basePath, const QString &uri,
+ const QString &typeNamespace, QTypeRevision version, QList<QQmlError> *errors)
{
if (!typeNamespace.isEmpty() && typeNamespace != uri) {
// This is an 'identified' module
@@ -657,10 +928,10 @@ bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePat
QQmlError error;
error.setDescription(
QStringLiteral("Module namespace '%1' does not match import URI '%2'")
- .arg(typeNamespace).arg(uri));
+ .arg(typeNamespace, uri));
errors->prepend(error);
}
- return false;
+ return RegistrationResult::Failure;
}
QStringList failures;
@@ -669,7 +940,7 @@ bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePat
QQmlMetaTypeRegistrationFailureRecorder failureRecorder(data, &failures);
if (!typeNamespace.isEmpty()) {
// This is an 'identified' module
- if (namespaceContainsRegistrations(data, typeNamespace, vmaj)) {
+ if (namespaceContainsRegistrations(data, typeNamespace, version)) {
// Other modules have already installed to this namespace
if (errors) {
QQmlError error;
@@ -678,7 +949,7 @@ bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePat
.arg(typeNamespace));
errors->prepend(error);
}
- return false;
+ return RegistrationResult::Failure;
}
} else {
// This is not an identified module - provide a warning
@@ -687,7 +958,7 @@ bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePat
"it cannot be protected from external registrations.").arg(uri));
}
- if (!qobject_cast<QQmlEngineExtensionInterface *>(instance)) {
+ if (instance && !qobject_cast<QQmlEngineExtensionInterface *>(instance)) {
QQmlTypesExtensionInterface *iface = qobject_cast<QQmlTypesExtensionInterface *>(instance);
if (!iface) {
if (errors) {
@@ -697,35 +968,40 @@ bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePat
"QQmlEngineExtensionInterface").arg(typeNamespace));
errors->prepend(error);
}
- return false;
+ return RegistrationResult::Failure;
}
+#if QT_DEPRECATED_SINCE(6, 3)
if (auto *plugin = qobject_cast<QQmlExtensionPlugin *>(instance)) {
// basepath should point to the directory of the module, not the plugin file itself:
QQmlExtensionPluginPrivate::get(plugin)->baseUrl
= QQmlImports::urlFromLocalFileOrQrcOrUrl(basePath);
}
+#else
+ Q_UNUSED(basePath)
+#endif
const QByteArray bytes = uri.toUtf8();
const char *moduleId = bytes.constData();
iface->registerTypes(moduleId);
}
- data->registerModuleTypes(QQmlMetaTypeData::VersionedUri(uri, vmaj));
+ if (failures.isEmpty() && !data->registerModuleTypes(uri))
+ return RegistrationResult::NoRegistrationFunction;
if (!failures.isEmpty()) {
if (errors) {
- for (const QString &failure : qAsConst(failures)) {
+ for (const QString &failure : std::as_const(failures)) {
QQmlError error;
error.setDescription(failure);
errors->prepend(error);
}
}
- return false;
+ return RegistrationResult::Failure;
}
}
- return true;
+ return RegistrationResult::Success;
}
/*
@@ -741,8 +1017,8 @@ bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePat
*/
QQmlType QQmlMetaType::typeForUrl(const QString &urlString,
const QHashedStringRef &qualifiedType,
- bool isCompositeSingleton, QList<QQmlError> *errors,
- int majorVersion, int minorVersion)
+ CompositeTypeLookupMode mode, QList<QQmlError> *errors,
+ QTypeRevision version)
{
// ### unfortunate (costly) conversion
const QUrl url = QQmlTypeLoader::normalize(QUrl(urlString));
@@ -759,128 +1035,80 @@ 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, majorVersion)) {
- auto *priv = new QQmlTypePrivate(registrationType);
- priv->setName(QString(), typeName);
- priv->version_maj = majorVersion;
- priv->version_min = minorVersion;
-
- 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.insertMulti(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('\n'));
- errors->prepend(error);
- } else {
- qWarning("%s", failures.join('\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;
}
/*
- Returns true if a module \a uri of any version is installed.
+ Returns the latest version of \a uri installed, or an in valid QTypeRevision().
*/
-bool QQmlMetaType::isAnyModule(const QString &uri)
+QTypeRevision QQmlMetaType::latestModuleVersion(const QString &uri)
{
QQmlMetaTypeDataPtr data;
+ auto upper = std::upper_bound(data->uriToModule.begin(), data->uriToModule.end(), uri,
+ std::less<ModuleUri>());
+ if (upper == data->uriToModule.begin())
+ return QTypeRevision();
- for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.cbegin();
- iter != data->uriToModule.cend(); ++iter) {
- if ((*iter)->module() == uri)
- return true;
- }
-
- return false;
+ const auto module = (--upper)->get();
+ return (module->module() == uri)
+ ? QTypeRevision::fromVersion(module->majorVersion(), module->maximumMinorVersion())
+ : QTypeRevision();
}
/*
Returns true if a module \a uri of this version is installed and locked;
*/
-bool QQmlMetaType::isLockedModule(const QString &uri, int majVersion)
+bool QQmlMetaType::isStronglyLockedModule(const QString &uri, QTypeRevision version)
{
QQmlMetaTypeDataPtr data;
- QQmlMetaTypeData::VersionedUri versionedUri;
- versionedUri.uri = uri;
- versionedUri.majorVersion = majVersion;
- if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0))
- return qqtm->isLocked();
+ if (QQmlTypeModule* qqtm = data->findTypeModule(uri, version))
+ return qqtm->lockLevel() == QQmlTypeModule::LockLevel::Strong;
return false;
}
/*
- Returns true if any type or API has been registered for the given \a module with at least
- versionMajor.versionMinor, or if types have been registered for \a module with at most
- versionMajor.versionMinor.
-
- So if only 4.7 and 4.9 have been registered, 4.7,4.8, and 4.9 are valid, but not 4.6 nor 4.10.
+ Returns the best matching registered version for the given \a module. If \a version is
+ the does not have a major version, returns the latest registered version. Otherwise
+ chooses the same major version and checks if the minor version is within the range
+ of registered minor versions. If so, retuens the original version, otherwise returns
+ an invalid version. If \a version does not have a minor version, chooses the latest one.
*/
-bool QQmlMetaType::isModule(const QString &module, int versionMajor, int versionMinor)
+QTypeRevision QQmlMetaType::matchingModuleVersion(const QString &module, QTypeRevision version)
{
- Q_ASSERT(versionMajor >= 0 && versionMinor >= 0);
+ if (!version.hasMajorVersion())
+ return latestModuleVersion(module);
+
QQmlMetaTypeDataPtr data;
// first, check Types
- QQmlTypeModule *tm =
- data->uriToModule.value(QQmlMetaTypeData::VersionedUri(module, versionMajor));
- if (tm && tm->minimumMinorVersion() <= versionMinor && tm->maximumMinorVersion() >= versionMinor)
- return true;
+ if (QQmlTypeModule *tm = data->findTypeModule(module, version)) {
+ if (!version.hasMinorVersion())
+ return QTypeRevision::fromVersion(version.majorVersion(), tm->maximumMinorVersion());
- return false;
+ if (tm->minimumMinorVersion() <= version.minorVersion()
+ && tm->maximumMinorVersion() >= version.minorVersion()) {
+ return version;
+ }
+ }
+
+ return QTypeRevision();
}
-QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, int majorVersion)
+QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, QTypeRevision version)
{
QQmlMetaTypeDataPtr data;
- return data->uriToModule.value(QQmlMetaTypeData::VersionedUri(uri, majorVersion));
+
+ if (version.hasMajorVersion())
+ return data->findTypeModule(uri, version);
+
+ auto range = std::equal_range(data->uriToModule.begin(), data->uriToModule.end(),
+ uri, std::less<ModuleUri>());
+
+ return range.first == range.second ? nullptr : (--range.second)->get();
}
QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions()
@@ -891,7 +1119,7 @@ QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions()
QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok)
{
- if (!isQObject(v.userType())) {
+ if (!v.metaType().flags().testFlag(QMetaType::PointerToQObject)) {
if (ok) *ok = false;
return nullptr;
}
@@ -901,54 +1129,28 @@ QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok)
return *(QObject *const *)v.constData();
}
-bool QQmlMetaType::isQObject(int userType)
-{
- if (userType == QMetaType::QObjectStar)
- return true;
-
- QQmlMetaTypeDataPtr data;
- return userType >= 0 && userType < data->objects.size() && data->objects.testBit(userType);
-}
-
/*
Returns the item type for a list of type \a id.
*/
-int QQmlMetaType::listType(int id)
-{
- QQmlMetaTypeDataPtr data;
- QHash<int, int>::ConstIterator iter = data->qmlLists.constFind(id);
- if (iter != data->qmlLists.cend())
- return *iter;
- QQmlTypePrivate *type = data->idToType.value(id);
- if (type && type->listId == id)
- return type->typeId;
- else
- return 0;
-}
-
-#if QT_DEPRECATED_SINCE(5, 14)
-int QQmlMetaType::attachedPropertiesFuncId(QQmlEnginePrivate *engine, const QMetaObject *mo)
-{
- QQmlMetaTypeDataPtr data;
-
- for (auto it = data->metaObjectToType.constFind(mo), end = data->metaObjectToType.constEnd();
- it != end && it.key() == mo; ++it) {
- const QQmlType type(it.value());
- if (type.attachedPropertiesFunction(engine))
- return type.attachedPropertiesId(engine);
+QMetaType QQmlMetaType::listValueType(QMetaType metaType)
+{
+ if (isList(metaType)) {
+ const auto iface = metaType.iface();
+ if (iface && iface->metaObjectFn == &dynamicQmlListMarker)
+ return QMetaType(static_cast<const QQmlListMetaTypeInterface *>(iface)->valueType);
+ } else if (metaType.flags() & QMetaType::PointerToQObject) {
+ return QMetaType();
}
- return -1;
-}
-
-QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(QQmlEnginePrivate *engine, int id)
-{
- if (id < 0)
- return nullptr;
QQmlMetaTypeDataPtr data;
- return data->types.at(id).attachedPropertiesFunction(engine);
+ Q_ASSERT(data);
+ QQmlTypePrivate *type = data->idToType.value(metaType.id());
+
+ if (type && type->listId == metaType)
+ return type->typeId;
+ else
+ return QMetaType {};
}
-#endif
QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFunc(QQmlEnginePrivate *engine,
const QMetaObject *mo)
@@ -1011,120 +1213,64 @@ QMetaMethod QQmlMetaType::defaultMethod(QObject *obj)
return defaultMethod(metaObject);
}
-QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType)
-{
- if (userType < 0)
- return Unknown;
- if (userType == QMetaType::QObjectStar)
- return Object;
-
- QQmlMetaTypeDataPtr data;
- if (data->qmlLists.contains(userType))
- return List;
- else if (userType < data->objects.size() && data->objects.testBit(userType))
- return Object;
- else if (userType < data->lists.size() && data->lists.testBit(userType))
- return List;
- else
- return Unknown;
-}
-
/*!
See qmlRegisterInterface() for information about when this will return true.
*/
-bool QQmlMetaType::isInterface(int userType)
+bool QQmlMetaType::isInterface(QMetaType type)
{
const QQmlMetaTypeDataPtr data;
- return userType >= 0 && userType < data->interfaces.size() && data->interfaces.testBit(userType);
+ return data->interfaces.contains(type.id());
}
-const char *QQmlMetaType::interfaceIId(int userType)
-{
-
- QQmlTypePrivate *typePrivate = nullptr;
- {
- QQmlMetaTypeDataPtr data;
- typePrivate = data->idToType.value(userType);
- }
-
- QQmlType type(typePrivate);
- if (type.isInterface() && type.typeId() == userType)
- return type.interfaceIId();
- else
- return nullptr;
-}
-
-bool QQmlMetaType::isList(int userType)
+const char *QQmlMetaType::interfaceIId(QMetaType metaType)
{
const QQmlMetaTypeDataPtr data;
- if (data->qmlLists.contains(userType))
- return true;
- return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType);
-}
-
-/*!
- A custom string convertor allows you to specify a function pointer that
- returns a variant of \a type. For example, if you have written your own icon
- class that you want to support as an object property assignable in QML:
-
- \code
- int type = qRegisterMetaType<SuperIcon>("SuperIcon");
- QML::addCustomStringConvertor(type, &SuperIcon::pixmapFromString);
- \endcode
-
- The function pointer must be of the form:
- \code
- QVariant (*StringConverter)(const QString &);
- \endcode
- */
-void QQmlMetaType::registerCustomStringConverter(int type, StringConverter converter)
-{
- QQmlMetaTypeDataPtr data;
- if (data->stringConverters.contains(type))
- return;
- data->stringConverters.insert(type, converter);
+ const QQmlType type(data->idToType.value(metaType.id()));
+ return (type.isInterface() && type.typeId() == metaType) ? type.interfaceIId() : nullptr;
}
-/*!
- Return the custom string converter for \a type, previously installed through
- registerCustomStringConverter()
- */
-QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type)
+bool QQmlMetaType::isList(QMetaType type)
{
- const QQmlMetaTypeDataPtr data;
- return data->stringConverters.value(type);
+ if (type.flags().testFlag(QMetaType::IsQmlList))
+ return true;
+ else
+ return false;
}
/*!
Returns the type (if any) of URI-qualified named \a qualifiedName and version specified
by \a version_major and \a version_minor.
*/
-QQmlType QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, int version_minor)
+QQmlType QQmlMetaType::qmlType(const QString &qualifiedName, QTypeRevision version)
{
int slash = qualifiedName.indexOf(QLatin1Char('/'));
if (slash <= 0)
return QQmlType();
QHashedStringRef module(qualifiedName.constData(), slash);
- QHashedStringRef name(qualifiedName.constData() + slash + 1, qualifiedName.length() - slash - 1);
+ QHashedStringRef name(qualifiedName.constData() + slash + 1, qualifiedName.size() - slash - 1);
- return qmlType(name, module, version_major, version_minor);
+ return qmlType(name, module, version);
}
/*!
- Returns the type (if any) of \a name in \a module and version specified
- by \a version_major and \a version_minor.
+ \internal
+ Returns the type (if any) of \a name in \a module and the specified \a version.
+
+ If \a version has no major version, accept any version.
+ If \a version has no minor version, accept any minor version.
+ If \a module is empty, search in all modules and accept any version.
*/
-QQmlType QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int version_major, int version_minor)
+QQmlType QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module,
+ QTypeRevision version)
{
- Q_ASSERT(version_major >= 0 && version_minor >= 0);
const QQmlMetaTypeDataPtr data;
- QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.constFind(name);
+ const QHashedString key(QString::fromRawData(name.constData(), name.length()), name.hash());
+ QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.constFind(key);
while (it != data->nameToType.cend() && it.key() == name) {
QQmlType t(*it);
- // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty
- if (version_major < 0 || module.isEmpty() || t.availableInVersion(module, version_major,version_minor))
+ if (module.isEmpty() || t.availableInVersion(module, version))
return t;
++it;
}
@@ -1133,8 +1279,8 @@ QQmlType QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedString
}
/*!
- Returns the type (if any) that corresponds to the \a metaObject. Returns null if no
- type is registered.
+ Returns the type (if any) that corresponds to the \a metaObject. Returns an invalid type if no
+ such type is registered.
*/
QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject)
{
@@ -1147,44 +1293,53 @@ QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject)
by \a version_major and \a version_minor in module specified by \a uri. Returns null if no
type is registered.
*/
-QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor)
+QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module,
+ QTypeRevision version)
{
- Q_ASSERT(version_major >= 0 && version_minor >= 0);
const QQmlMetaTypeDataPtr data;
- QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.constFind(metaObject);
- while (it != data->metaObjectToType.cend() && it.key() == metaObject) {
+ const auto range = data->metaObjectToType.equal_range(metaObject);
+ for (auto it = range.first; it != range.second; ++it) {
QQmlType t(*it);
- if (version_major < 0 || module.isEmpty() || t.availableInVersion(module, version_major,version_minor))
+ if (module.isEmpty() || t.availableInVersion(module, version))
return t;
- ++it;
}
return QQmlType();
}
/*!
- Returns the type (if any) that corresponds to \a typeId. Depending on \a category, the
- \a typeId is interpreted either as QVariant::Type or as QML type id returned by one of the
- qml type registration functions. Returns null if no type is registered.
+ Returns the type (if any) that corresponds to \a qmlTypeId.
+ Returns an invalid QQmlType if no such type is registered.
*/
-QQmlType QQmlMetaType::qmlType(int typeId, TypeIdCategory category)
+QQmlType QQmlMetaType::qmlTypeById(int qmlTypeId)
{
const QQmlMetaTypeDataPtr data;
-
- if (category == TypeIdCategory::MetaType) {
- QQmlTypePrivate *type = data->idToType.value(typeId);
- if (type && type->typeId == typeId)
- return QQmlType(type);
- } else if (category == TypeIdCategory::QmlType) {
- QQmlType type = data->types.value(typeId);
- if (type.isValid())
- return type;
- }
+ QQmlType type = data->types.value(qmlTypeId);
+ if (type.isValid())
+ return type;
return QQmlType();
}
/*!
+ Returns the type (if any) that corresponds to \a metaType.
+ Returns an invalid QQmlType if no such type is registered.
+*/
+QQmlType QQmlMetaType::qmlType(QMetaType metaType)
+{
+ const QQmlMetaTypeDataPtr data;
+ QQmlTypePrivate *type = data->idToType.value(metaType.id());
+ return (type && type->typeId == metaType) ? QQmlType(type) : QQmlType();
+}
+
+QQmlType QQmlMetaType::qmlListType(QMetaType metaType)
+{
+ const QQmlMetaTypeDataPtr data;
+ QQmlTypePrivate *type = data->idToType.value(metaType.id());
+ return (type && type->listId == metaType) ? QQmlType(type) : QQmlType();
+}
+
+/*!
Returns the type (if any) that corresponds to the given \a url in the set of
composite types added through file imports.
@@ -1205,16 +1360,149 @@ QQmlType QQmlMetaType::qmlType(const QUrl &unNormalizedUrl, bool includeNonFileI
return QQmlType();
}
-QQmlPropertyCache *QQmlMetaType::propertyCache(const QMetaObject *metaObject, int minorVersion)
+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.
+
+If \a obj is null, being deleted or contains a dynamic meta object,
+nullptr is returned.
+*/
+QQmlPropertyCache::ConstPtr QQmlMetaType::propertyCache(QObject *obj, QTypeRevision version)
+{
+ if (!obj || QObjectPrivate::get(obj)->metaObject || QObjectPrivate::get(obj)->wasDeleted)
+ return QQmlPropertyCache::ConstPtr();
+ return QQmlMetaType::propertyCache(obj->metaObject(), version);
+}
+
+QQmlPropertyCache::ConstPtr QQmlMetaType::propertyCache(
+ const QMetaObject *metaObject, QTypeRevision version)
{
QQmlMetaTypeDataPtr data; // not const: the cache is created on demand
- return data->propertyCache(metaObject, minorVersion);
+ return data->propertyCache(metaObject, version);
}
-QQmlPropertyCache *QQmlMetaType::propertyCache(const QQmlType &type, int minorVersion)
+QQmlPropertyCache::ConstPtr QQmlMetaType::propertyCache(
+ const QQmlType &type, QTypeRevision version)
{
QQmlMetaTypeDataPtr data; // not const: the cache is created on demand
- return data->propertyCache(type, minorVersion);
+ return data->propertyCache(type, version);
+}
+
+/*!
+ * \internal
+ *
+ * Look up by type's baseMetaObject.
+ */
+QQmlMetaObject QQmlMetaType::rawMetaObjectForType(QMetaType metaType)
+{
+ const QQmlMetaTypeDataPtr data;
+ if (auto composite = data->findPropertyCacheInCompositeTypes(metaType))
+ return QQmlMetaObject(composite);
+
+ const QQmlTypePrivate *type = data->idToType.value(metaType.id());
+ return (type && type->typeId == metaType) ? type->baseMetaObject : nullptr;
+}
+
+/*!
+ * \internal
+ *
+ * Look up by type's metaObject.
+ */
+QQmlMetaObject QQmlMetaType::metaObjectForType(QMetaType metaType)
+{
+ const QQmlMetaTypeDataPtr data;
+ if (auto composite = data->findPropertyCacheInCompositeTypes(metaType))
+ return QQmlMetaObject(composite);
+
+ const QQmlTypePrivate *type = data->idToType.value(metaType.id());
+ return (type && type->typeId == metaType)
+ ? QQmlType(type).metaObject()
+ : nullptr;
+}
+
+/*!
+ * \internal
+ *
+ * Look up by type's metaObject and version.
+ */
+QQmlPropertyCache::ConstPtr QQmlMetaType::propertyCacheForType(QMetaType metaType)
+{
+ QQmlMetaTypeDataPtr data;
+ if (auto composite = data->findPropertyCacheInCompositeTypes(metaType))
+ return composite;
+
+ const QQmlTypePrivate *type = data->idToType.value(metaType.id());
+ if (type && type->typeId == metaType) {
+ if (const QMetaObject *mo = QQmlType(type).metaObject())
+ return data->propertyCache(mo, type->version);
+ }
+
+ return QQmlPropertyCache::ConstPtr();
+}
+
+/*!
+ * \internal
+ *
+ * Look up by type's baseMetaObject and unspecified/any version.
+ * TODO: Is this correct? Passing a plain QTypeRevision() rather than QTypeRevision::zero() or
+ * the actual type's version seems strange. The behavior has been in place for a while.
+ */
+QQmlPropertyCache::ConstPtr QQmlMetaType::rawPropertyCacheForType(QMetaType metaType)
+{
+ QQmlMetaTypeDataPtr data;
+ if (auto composite = QQmlMetaType::findPropertyCacheInCompositeTypes(metaType))
+ return composite;
+
+ const QQmlTypePrivate *type = data->idToType.value(metaType.id());
+ 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();
+}
+
+/*!
+ * \internal
+ *
+ * Look up by QQmlType and version. We only fall back to lookup by metaobject if the type
+ * has no revisiononed attributes here. Unspecified versions are interpreted as "any".
+ */
+QQmlPropertyCache::ConstPtr QQmlMetaType::rawPropertyCacheForType(
+ QMetaType metaType, QTypeRevision version)
+{
+ QQmlMetaTypeDataPtr data;
+ if (auto composite = data->findPropertyCacheInCompositeTypes(metaType))
+ return composite;
+
+ const QQmlTypePrivate *typePriv = data->idToType.value(metaType.id());
+ if (!typePriv || typePriv->typeId != metaType)
+ return QQmlPropertyCache::ConstPtr();
+
+ const QQmlType type(typePriv);
+ 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);
+
+ return QQmlPropertyCache::ConstPtr();
}
void QQmlMetaType::unregisterType(int typeIndex)
@@ -1222,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);
@@ -1229,12 +1519,55 @@ void QQmlMetaType::unregisterType(int typeIndex)
removeQQmlTypePrivate(data->metaObjectToType, d);
for (auto & module : data->uriToModule)
module->remove(d);
- data->clearPropertyCachesForMinorVersion(typeIndex);
+ data->clearPropertyCachesForVersion(typeIndex);
data->types[typeIndex] = QQmlType();
data->undeletableTypes.remove(type);
}
}
+void QQmlMetaType::registerMetaObjectForType(const QMetaObject *metaobject, QQmlTypePrivate *type)
+{
+ Q_ASSERT(type);
+
+ QQmlMetaTypeDataPtr data;
+ data->metaObjectToType.insert(metaobject, type);
+}
+
+static bool hasActiveInlineComponents(const QQmlMetaTypeData *data, const QQmlTypePrivate *d)
+{
+ 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;
@@ -1243,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) {
+ 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);
@@ -1261,7 +1612,7 @@ void QQmlMetaType::freeUnusedTypesAndCaches()
for (auto &module : data->uriToModule)
module->remove(d);
- data->clearPropertyCachesForMinorVersion(d->index);
+ data->clearPropertyCachesForVersion(d->index);
*it = QQmlType();
} else {
++it;
@@ -1272,14 +1623,10 @@ void QQmlMetaType::freeUnusedTypesAndCaches()
bool deletedAtLeastOneCache;
do {
deletedAtLeastOneCache = false;
- QHash<const QMetaObject *, QQmlPropertyCache *>::Iterator it = data->propertyCaches.begin();
+ auto it = data->propertyCaches.begin();
while (it != data->propertyCaches.end()) {
-
if ((*it)->count() == 1) {
- QQmlPropertyCache *pc = nullptr;
- qSwap(pc, *it);
it = data->propertyCaches.erase(it);
- pc->release();
deletedAtLeastOneCache = true;
} else {
++it;
@@ -1296,7 +1643,7 @@ QList<QString> QQmlMetaType::qmlTypeNames()
const QQmlMetaTypeDataPtr data;
QList<QString> names;
- names.reserve(data->nameToType.count());
+ names.reserve(data->nameToType.size());
QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.cbegin();
while (it != data->nameToType.cend()) {
QQmlType t(*it);
@@ -1315,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;
@@ -1338,7 +1685,7 @@ QList<QQmlType> QQmlMetaType::qmlSingletonTypes()
const QQmlMetaTypeDataPtr data;
QList<QQmlType> retn;
- for (const auto t : qAsConst(data->nameToType)) {
+ for (const auto t : std::as_const(data->nameToType)) {
QQmlType type(t);
if (type.isSingleton())
retn.append(type);
@@ -1346,22 +1693,47 @@ QList<QQmlType> QQmlMetaType::qmlSingletonTypes()
return retn;
}
-const QV4::CompiledData::Unit *QQmlMetaType::findCachedCompilationUnit(const QUrl &uri, CachedUnitLookupError *status)
+static bool isFullyTyped(const QQmlPrivate::CachedQmlUnit *unit)
{
+ quint32 numTypedFunctions = 0;
+ for (const QQmlPrivate::AOTCompiledFunction *function = unit->aotCompiledFunctions;
+ function; ++function) {
+ if (function->functionPtr)
+ ++numTypedFunctions;
+ else
+ return false;
+ }
+ return numTypedFunctions == unit->qmlData->functionTableSize;
+}
+
+const QQmlPrivate::CachedQmlUnit *QQmlMetaType::findCachedCompilationUnit(
+ const QUrl &uri, QQmlMetaType::CacheMode mode, CachedUnitLookupError *status)
+{
+ Q_ASSERT(mode != RejectAll);
const QQmlMetaTypeDataPtr data;
- for (const auto lookup : qAsConst(data->lookupCachedQmlUnit)) {
+ 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;
return nullptr;
}
+
+ if (mode == RequireFullyTyped && !isFullyTyped(unit)) {
+ qCDebug(DBG_DISK_CACHE)
+ << "Error loading pre-compiled file " << uri
+ << ": compilation unit contains functions not compiled to native code.";
+ if (status)
+ *status = CachedUnitLookupError::NotFullyTyped;
+ return nullptr;
+ }
+
if (status)
*status = CachedUnitLookupError::NoError;
- return unit->qmlData;
+ return unit;
}
}
@@ -1409,8 +1781,8 @@ QString QQmlMetaType::prettyTypeName(const QObject *object)
marker = typeName.indexOf(QLatin1String("_QML_"));
if (marker != -1) {
- typeName = typeName.leftRef(marker) + QLatin1Char('*');
- type = QQmlMetaType::qmlType(QMetaType::type(typeName.toLatin1()));
+ typeName = QStringView{typeName}.left(marker) + QLatin1Char('*');
+ type = QQmlMetaType::qmlType(QMetaType::fromName(typeName.toUtf8()));
if (type.isValid()) {
QString qmlTypeName = type.qmlTypeName();
const int lastSlash = qmlTypeName.lastIndexOf(QLatin1Char('/'));
@@ -1432,31 +1804,211 @@ QList<QQmlProxyMetaObject::ProxyData> QQmlMetaType::proxyData(const QMetaObject
QList<QQmlProxyMetaObject::ProxyData> metaObjects;
mo = mo->d.superdata;
- const QQmlMetaTypeDataPtr data;
-
- while (mo) {
- QQmlTypePrivate *t = data->metaObjectToType.value(mo);
- if (t) {
+ if (!mo)
+ return metaObjects;
+
+ auto createProxyMetaObject = [&](QQmlTypePrivate *This,
+ const QMetaObject *superdataBaseMetaObject,
+ const QMetaObject *extMetaObject,
+ QObject *(*extFunc)(QObject *)) {
+ if (!extMetaObject)
+ return;
+
+ QMetaObjectBuilder builder;
+ clone(builder, extMetaObject, superdataBaseMetaObject, baseMetaObject,
+ extFunc ? QQmlMetaType::CloneAll : QQmlMetaType::CloneEnumsOnly);
+ QMetaObject *mmo = builder.toMetaObject();
+ mmo->d.superdata = baseMetaObject;
+ if (!metaObjects.isEmpty())
+ metaObjects.constLast().metaObject->d.superdata = mmo;
+ else if (lastMetaObject)
+ lastMetaObject->d.superdata = mmo;
+ QQmlProxyMetaObject::ProxyData data = { mmo, extFunc, 0, 0 };
+ metaObjects << data;
+ registerMetaObjectForType(mmo, This);
+ };
+
+ 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) {
- if (t->extraData.cd->extFunc) {
- QMetaObjectBuilder builder;
- clone(builder, t->extraData.cd->extMetaObject, t->baseMetaObject, baseMetaObject);
- builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
- QMetaObject *mmo = builder.toMetaObject();
- mmo->d.superdata = baseMetaObject;
- if (!metaObjects.isEmpty())
- metaObjects.constLast().metaObject->d.superdata = mmo;
- else if (lastMetaObject)
- lastMetaObject->d.superdata = mmo;
- QQmlProxyMetaObject::ProxyData data = { mmo, t->extraData.cd->extFunc, 0, 0 };
- metaObjects << data;
- }
+ createProxyMetaObject(
+ t, t->baseMetaObject, t->extraData.cppTypeData->extMetaObject,
+ t->extraData.cppTypeData->extFunc);
+ } else if (t->regType == QQmlType::SingletonType) {
+ createProxyMetaObject(
+ t, t->baseMetaObject, t->extraData.singletonTypeData->extMetaObject,
+ t->extraData.singletonTypeData->extFunc);
}
}
- mo = mo->d.superdata;
- }
+ };
return metaObjects;
}
+static bool isInternalType(int idx)
+{
+ // Qt internal types
+ switch (idx) {
+ case QMetaType::UnknownType:
+ case QMetaType::QStringList:
+ case QMetaType::QObjectStar:
+ case QMetaType::VoidStar:
+ case QMetaType::Nullptr:
+ case QMetaType::QVariant:
+ case QMetaType::QLocale:
+ case QMetaType::QImage: // scarce type, keep as QVariant
+ case QMetaType::QPixmap: // scarce type, keep as QVariant
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool QQmlMetaType::isValueType(QMetaType type)
+{
+ if (!type.isValid() || isInternalType(type.id()))
+ return false;
+
+ return valueType(type) != nullptr;
+}
+
+const QMetaObject *QQmlMetaType::metaObjectForValueType(QMetaType metaType)
+{
+ switch (metaType.id()) {
+ case QMetaType::QPoint:
+ return &QQmlPointValueType::staticMetaObject;
+ case QMetaType::QPointF:
+ return &QQmlPointFValueType::staticMetaObject;
+ case QMetaType::QSize:
+ return &QQmlSizeValueType::staticMetaObject;
+ case QMetaType::QSizeF:
+ return &QQmlSizeFValueType::staticMetaObject;
+ case QMetaType::QRect:
+ return &QQmlRectValueType::staticMetaObject;
+ case QMetaType::QRectF:
+ return &QQmlRectFValueType::staticMetaObject;
+#if QT_CONFIG(easingcurve)
+ case QMetaType::QEasingCurve:
+ return &QQmlEasingValueType::staticMetaObject;
+#endif
+ default:
+ break;
+ }
+
+ // It doesn't have to be a gadget for a QML type to exist, but we don't want to
+ // call QObject pointers value types. Explicitly registered types also override
+ // the implicit use of gadgets.
+ if (!(metaType.flags() & QMetaType::PointerToQObject)) {
+ 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.
+ if (metaType.flags() & QMetaType::IsGadget)
+ return metaType.metaObject();
+
+ return nullptr;
+}
+
+QQmlValueType *QQmlMetaType::valueType(QMetaType type)
+{
+ QQmlMetaTypeDataPtr data;
+
+ const auto it = data->metaTypeToValueType.constFind(type.id());
+ if (it != data->metaTypeToValueType.constEnd())
+ return *it;
+
+ if (const QMetaObject *mo = metaObjectForValueType(type))
+ return *data->metaTypeToValueType.insert(type.id(), new QQmlValueType(type, mo));
+ return *data->metaTypeToValueType.insert(type.id(), nullptr);
+}
+
+QQmlPropertyCache::ConstPtr QQmlMetaType::findPropertyCacheInCompositeTypes(QMetaType t)
+{
+ const QQmlMetaTypeDataPtr data;
+ return data->findPropertyCacheInCompositeTypes(t);
+}
+
+void QQmlMetaType::registerInternalCompositeType(
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
+{
+ QQmlMetaTypeDataPtr data;
+
+ 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)
+ doInsert(inlineData.qmlType.typeId().iface());
+}
+
+void QQmlMetaType::unregisterInternalCompositeType(
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
+{
+ 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;
+ return doCountInternalCompositeTypeSelfReferences(data, compilationUnit);
+}
+
+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