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.cpp405
1 files changed, 246 insertions, 159 deletions
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 8610f48ca2..d969fb9ff0 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -3,11 +3,12 @@
#include "qqmlmetatype_p.h"
+#include <private/qqmlextensionplugin_p.h>
#include <private/qqmlmetatypedata_p.h>
-#include <private/qqmltypemodule_p.h>
+#include <private/qqmlpropertycachecreator_p.h>
#include <private/qqmltype_p_p.h>
#include <private/qqmltypeloader_p.h>
-#include <private/qqmlextensionplugin_p.h>
+#include <private/qqmltypemodule_p.h>
#include <private/qqmlvaluetype_p.h>
#include <private/qv4executablecompilationunit_p.h>
@@ -20,32 +21,6 @@ Q_LOGGING_CATEGORY(lcTypeRegistration, "qt.qml.typeregistration")
QT_BEGIN_NAMESPACE
-CompositeMetaTypeIds CompositeMetaTypeIds::fromCompositeName(const QByteArray &name)
-{
- auto ids = QQmlMetaType::registerInternalCompositeType(name);
- ids.refCount = new int;
- *ids.refCount = 1;
- return ids;
-}
-
-void CompositeMetaTypeIds::deref()
-{
- Q_ASSERT(refCount);
- --*refCount;
- if (!*refCount) {
- delete refCount;
- QQmlMetaType::unregisterInternalCompositeType(*this);
- refCount = nullptr;
- }
-}
-
-CompositeMetaTypeIds::~CompositeMetaTypeIds()
-{
- if (refCount)
- deref();
-}
-
-
struct LockedData : private QQmlMetaTypeData
{
friend class QQmlMetaTypeDataPtr;
@@ -178,6 +153,22 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el
return d;
}
+static void addQQmlMetaTypeInterfaces(QQmlTypePrivate *priv, const QByteArray &className)
+{
+ QByteArray ptr = className + '*';
+ QByteArray lst = "QQmlListProperty<" + className + '>';
+
+ QMetaType ptr_type(new QQmlMetaTypeInterface(ptr));
+ QMetaType lst_type(new QQmlListMetaTypeInterface(lst, ptr_type.iface()));
+
+ // Retrieve the IDs once, so that the types are added to QMetaType's custom type registry.
+ ptr_type.id();
+ lst_type.id();
+
+ priv->typeId = ptr_type;
+ priv->listId = lst_type;
+}
+
static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName,
const QQmlPrivate::RegisterCompositeType &type)
{
@@ -186,7 +177,10 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el
d->setName(QString::fromUtf8(type.uri), elementName);
d->version = type.version;
- d->extraData.fd->url = QQmlTypeLoader::normalize(type.url);
+ const QUrl normalized = QQmlTypeLoader::normalize(type.url);
+ d->extraData.fd->url = normalized;
+ addQQmlMetaTypeInterfaces(
+ d, QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(normalized));
return d;
}
@@ -199,9 +193,12 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el
d->version = type.version;
+ const QUrl normalized = QQmlTypeLoader::normalize(type.url);
d->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo;
- d->extraData.sd->singletonInstanceInfo->url = QQmlTypeLoader::normalize(type.url);
+ d->extraData.sd->singletonInstanceInfo->url = normalized;
d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName);
+ addQQmlMetaTypeInterfaces(
+ d, QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(normalized));
return d;
}
@@ -319,6 +316,10 @@ void QQmlMetaType::clearTypeRegistrations()
data->undeletableTypes.clear();
data->propertyCaches.clear();
data->inlineComponentTypes.clear();
+
+ // Avoid deletion recursion (via QQmlTypePrivate dtor) by moving them out of the way first.
+ QQmlMetaTypeData::CompositeTypes emptyComposites;
+ emptyComposites.swap(data->compositeTypes);
}
void QQmlMetaType::registerTypeAlias(int typeIndex, const QString &name)
@@ -564,26 +565,164 @@ QQmlType QQmlMetaType::registerCompositeType(const QQmlPrivate::RegisterComposit
return QQmlType(priv);
}
-CompositeMetaTypeIds QQmlMetaType::registerInternalCompositeType(const QByteArray &className)
+class QQmlMetaTypeRegistrationFailureRecorder
{
- QByteArray ptr = className + '*';
- QByteArray lst = "QQmlListProperty<" + className + '>';
+ Q_DISABLE_COPY_MOVE(QQmlMetaTypeRegistrationFailureRecorder)
+public:
+ QQmlMetaTypeRegistrationFailureRecorder(QQmlMetaTypeData *data, QStringList *failures)
+ : data(data)
+ {
+ data->setTypeRegistrationFailures(failures);
+ }
- QMetaType ptr_type(new QQmlMetaTypeInterface(ptr));
- QMetaType lst_type(new QQmlListMetaTypeInterface(lst, ptr_type.iface()));
+ ~QQmlMetaTypeRegistrationFailureRecorder()
+ {
+ data->setTypeRegistrationFailures(nullptr);
+ }
- // Retrieve the IDs once, so that the types are added to QMetaType's custom type registry.
- ptr_type.id();
- lst_type.id();
+ QQmlMetaTypeData *data = nullptr;
+};
+
+
+static QQmlType createTypeForUrl(
+ QQmlMetaTypeData *data, const QUrl &url, const QHashedStringRef &qualifiedType,
+ QQmlMetaType::CompositeTypeLookupMode mode, QList<QQmlError> *errors, QTypeRevision version)
+{
+ const int dot = qualifiedType.indexOf(QLatin1Char('.'));
+ const QString typeName = dot < 0
+ ? qualifiedType.toString()
+ : QString(qualifiedType.constData() + dot + 1, qualifiedType.length() - dot - 1);
+
+ QStringList failures;
+ QQmlMetaTypeRegistrationFailureRecorder failureRecorder(data, &failures);
+
+ // Register the type. Note that the URI parameters here are empty; for
+ // file type imports, we do not place them in a URI as we don't
+ // necessarily have a good and unique one (picture a library import,
+ // which may be found in multiple plugin locations on disk), but there
+ // are other reasons for this too.
+ //
+ // By not putting them in a URI, we prevent the types from being
+ // registered on a QQmlTypeModule; this is important, as once types are
+ // placed on there, they cannot be easily removed, meaning if the
+ // developer subsequently loads a different import (meaning different
+ // types) with the same URI (using, say, a different plugin path), it is
+ // very undesirable that we continue to associate the types from the
+ // "old" URI with that new module.
+ //
+ // Not having URIs also means that the types cannot be found by name
+ // etc, the only way to look them up is through QQmlImports -- for
+ // better or worse.
+ const QQmlType::RegistrationType registrationType = mode == QQmlMetaType::Singleton
+ ? QQmlType::CompositeSingletonType
+ : QQmlType::CompositeType;
+ if (checkRegistration(registrationType, data, nullptr, typeName, version, {})) {
+
+ // TODO: Ideally we should defer most of this work using some lazy/atomic mechanism
+ // that creates the details on first use. We must not observably modify
+ // QQmlTypePrivate after it has been created since it is supposed to be immutable
+ // and shared across threads.
+
+ auto *priv = new QQmlTypePrivate(registrationType);
+ addQQmlMetaTypeInterfaces(priv, QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(url));
+
+ priv->setName(QString(), typeName);
+ priv->version = version;
+
+ if (mode == QQmlMetaType::Singleton) {
+ priv->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo;
+ priv->extraData.sd->singletonInstanceInfo->url = url;
+ priv->extraData.sd->singletonInstanceInfo->typeName = typeName;
+ } else {
+ priv->extraData.fd->url = url;
+ }
- return {ptr_type, lst_type};
+ data->registerType(priv);
+ addTypeToData(priv, data);
+ return QQmlType(priv);
+ }
+
+ // This means that the type couldn't be found by URL, but could not be
+ // registered either, meaning we most likely were passed some kind of bad
+ // data.
+ if (errors) {
+ QQmlError error;
+ error.setDescription(failures.join(u'\n'));
+ errors->prepend(error);
+ } else {
+ qWarning("%s", failures.join(u'\n').toLatin1().constData());
+ }
+ return QQmlType();
}
-void QQmlMetaType::unregisterInternalCompositeType(const CompositeMetaTypeIds &typeIds)
+QQmlType QQmlMetaType::findCompositeType(
+ const QUrl &url, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ CompositeTypeLookupMode mode)
{
- QMetaType metaType(typeIds.id);
- QMetaType listMetaType(typeIds.listId);
+ const QUrl normalized = QQmlTypeLoader::normalize(url);
+ QQmlMetaTypeDataPtr data;
+ bool urlExists = true;
+ auto found = data->urlToType.find(normalized);
+ if (found == data->urlToType.end()) {
+ found = data->urlToNonFileImportType.find(normalized);
+ if (found == data->urlToNonFileImportType.end())
+ urlExists = false;
+ }
+
+ if (urlExists) {
+ const auto composite = data->compositeTypes.constFind(found.value()->typeId.iface());
+ if (composite == data->compositeTypes.constEnd() || composite.value() == compilationUnit)
+ return QQmlType(*found);
+ }
+
+ const QQmlType type = createTypeForUrl(
+ data, normalized, QHashedStringRef(), mode, nullptr, QTypeRevision());
+
+ if (!urlExists && type.isValid())
+ data->urlToType.insert(normalized, type.priv());
+
+ return type;
+}
+
+static QQmlType doRegisterInlineComponentType(QQmlMetaTypeData *data, const QUrl &url)
+{
+ QQmlTypePrivate *priv = new QQmlTypePrivate(QQmlType::InlineComponentType);
+ priv->setName(QString(), url.fragment());
+
+ priv->extraData.id->url = url;
+
+ const QByteArray className
+ = QQmlPropertyCacheCreatorBase::createClassNameForInlineComponent(url, url.fragment());
+
+ addQQmlMetaTypeInterfaces(priv, className);
+ const QQmlType result(priv);
+ priv->release();
+
+ data->inlineComponentTypes.insert(url, result);
+
+ return result;
+}
+
+QQmlType QQmlMetaType::findInlineComponentType(
+ const QUrl &url, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit)
+{
+ QQmlMetaTypeDataPtr data;
+
+ // If there is an "unclaimed" inline component type, we can "claim" it now. Otherwise
+ // we have to create a new one.
+ const auto it = data->inlineComponentTypes.constFind(url);
+ if (it != data->inlineComponentTypes.constEnd()) {
+ const auto jt = data->compositeTypes.constFind(it->typeId().iface());
+ if (jt == data->compositeTypes.constEnd() || *jt == compilationUnit)
+ return *it;
+ }
+
+ return doRegisterInlineComponentType(data, url);
+}
+
+void QQmlMetaType::unregisterInternalCompositeType(QMetaType metaType, QMetaType listMetaType)
+{
// This may be called from delayed dtors on shutdown when the data is already gone.
QQmlMetaTypeDataPtr data;
if (data.isValid()) {
@@ -591,6 +730,10 @@ void QQmlMetaType::unregisterInternalCompositeType(const CompositeMetaTypeIds &t
delete vt;
if (QQmlValueType *vt = data->metaTypeToValueType.take(listMetaType.id()))
delete vt;
+
+ auto it = data->compositeTypes.constFind(metaType.iface());
+ if (it != data->compositeTypes.constEnd())
+ data->compositeTypes.erase(it);
}
QMetaType::unregisterMetaType(metaType);
@@ -764,25 +907,6 @@ static bool namespaceContainsRegistrations(const QQmlMetaTypeData *data, const Q
return false;
}
-class QQmlMetaTypeRegistrationFailureRecorder
-{
- Q_DISABLE_COPY_MOVE(QQmlMetaTypeRegistrationFailureRecorder)
-public:
- QQmlMetaTypeRegistrationFailureRecorder(QQmlMetaTypeData *data, QStringList *failures)
- : data(data)
- {
- data->setTypeRegistrationFailures(failures);
- }
-
- ~QQmlMetaTypeRegistrationFailureRecorder()
- {
- data->setTypeRegistrationFailures(nullptr);
- }
-
- QQmlMetaTypeData *data = nullptr;
-};
-
-
QQmlMetaType::RegistrationResult QQmlMetaType::registerPluginTypes(
QObject *instance, const QString &basePath, const QString &uri,
const QString &typeNamespace, QTypeRevision version, QList<QQmlError> *errors)
@@ -883,7 +1007,7 @@ QQmlMetaType::RegistrationResult QQmlMetaType::registerPluginTypes(
*/
QQmlType QQmlMetaType::typeForUrl(const QString &urlString,
const QHashedStringRef &qualifiedType,
- bool isCompositeSingleton, QList<QQmlError> *errors,
+ CompositeTypeLookupMode mode, QList<QQmlError> *errors,
QTypeRevision version)
{
// ### unfortunate (costly) conversion
@@ -901,64 +1025,10 @@ QQmlType QQmlMetaType::typeForUrl(const QString &urlString,
return ret;
}
- const int dot = qualifiedType.indexOf(QLatin1Char('.'));
- const QString typeName = dot < 0
- ? qualifiedType.toString()
- : QString(qualifiedType.constData() + dot + 1, qualifiedType.length() - dot - 1);
-
- QStringList failures;
- QQmlMetaTypeRegistrationFailureRecorder failureRecorder(data, &failures);
-
- // Register the type. Note that the URI parameters here are empty; for
- // file type imports, we do not place them in a URI as we don't
- // necessarily have a good and unique one (picture a library import,
- // which may be found in multiple plugin locations on disk), but there
- // are other reasons for this too.
- //
- // By not putting them in a URI, we prevent the types from being
- // registered on a QQmlTypeModule; this is important, as once types are
- // placed on there, they cannot be easily removed, meaning if the
- // developer subsequently loads a different import (meaning different
- // types) with the same URI (using, say, a different plugin path), it is
- // very undesirable that we continue to associate the types from the
- // "old" URI with that new module.
- //
- // Not having URIs also means that the types cannot be found by name
- // etc, the only way to look them up is through QQmlImports -- for
- // better or worse.
- const QQmlType::RegistrationType registrationType = isCompositeSingleton
- ? QQmlType::CompositeSingletonType
- : QQmlType::CompositeType;
- if (checkRegistration(registrationType, data, nullptr, typeName, version, {})) {
- auto *priv = new QQmlTypePrivate(registrationType);
- priv->setName(QString(), typeName);
- priv->version = version;
-
- if (isCompositeSingleton) {
- priv->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo;
- priv->extraData.sd->singletonInstanceInfo->url = url;
- priv->extraData.sd->singletonInstanceInfo->typeName = typeName;
- } else {
- priv->extraData.fd->url = url;
- }
-
- data->registerType(priv);
- addTypeToData(priv, data);
- data->urlToType.insert(url, priv);
- return QQmlType(priv);
- }
-
- // This means that the type couldn't be found by URL, but could not be
- // registered either, meaning we most likely were passed some kind of bad
- // data.
- if (errors) {
- QQmlError error;
- error.setDescription(failures.join(u'\n'));
- errors->prepend(error);
- } else {
- qWarning("%s", failures.join(u'\n').toLatin1().constData());
- }
- return QQmlType();
+ const QQmlType type = createTypeForUrl(
+ data, url, qualifiedType, mode, errors, version);
+ data->urlToType.insert(url, type.priv());
+ return type;
}
QRecursiveMutex *QQmlMetaType::typeRegistrationLock()
@@ -1285,36 +1355,17 @@ QQmlType QQmlMetaType::qmlType(const QUrl &unNormalizedUrl, bool includeNonFileI
return QQmlType();
}
-QQmlType QQmlMetaType::inlineComponentType(const QQmlType &containingType, const QString &name)
+QQmlType QQmlMetaType::inlineComponentTypeForUrl(const QUrl &url)
{
- const QQmlMetaTypeDataPtr data;
- return data->inlineComponentTypes[InlineComponentKey {containingType.priv(), name}];
-}
-
-void QQmlMetaType::associateInlineComponent(
- const QQmlType &containingType, const QString &name,
- const CompositeMetaTypeIds &metaTypeIds, QQmlType existingType)
-{
- bool const reuseExistingType = existingType.isValid();
- auto priv = reuseExistingType
- ? const_cast<QQmlTypePrivate *>(existingType.priv())
- : new QQmlTypePrivate { QQmlType::RegistrationType::InlineComponentType } ;
- priv->setName( QString::fromUtf8(existingType.typeName()), name);
- QUrl icUrl(existingType.sourceUrl());
- icUrl.setFragment(name);
- priv->extraData.id->url = icUrl;
- priv->extraData.id->containingType = containingType.priv();
- priv->typeId = metaTypeIds.id;
- priv->listId = metaTypeIds.listId;
- QQmlType icType(priv);
-
QQmlMetaTypeDataPtr data;
- data->inlineComponentTypes.insert({containingType.priv(), name}, icType);
+ const auto it = data->inlineComponentTypes.constFind(url);
+ if (it != data->inlineComponentTypes.constEnd())
+ return *it;
- if (!reuseExistingType)
- priv->release();
+ return doRegisterInlineComponentType(data, url);
}
+
/*!
Returns a QQmlPropertyCache for \a obj if one is available.
@@ -1475,7 +1526,7 @@ static bool hasActiveInlineComponents(const QQmlMetaTypeData *data, const QQmlTy
{
for (auto it = data->inlineComponentTypes.begin(), end = data->inlineComponentTypes.end();
it != end; ++it) {
- if (it.key().containingType != d)
+ if (!QQmlMetaType::equalBaseUrls(it.key(), d->sourceUrl()))
continue;
const QQmlTypePrivate *icPriv = it->priv();
@@ -1831,30 +1882,66 @@ QQmlPropertyCache::ConstPtr QQmlMetaType::findPropertyCacheInCompositeTypes(QMet
return data->findPropertyCacheInCompositeTypes(t);
}
-void QQmlMetaType::registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit)
+void QQmlMetaType::registerInternalCompositeType(
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit)
{
- compilationUnit->isRegistered = true;
-
QQmlMetaTypeDataPtr data;
- // The QQmlCompiledData is not referenced here, but it is removed from this
- // hash in the QQmlCompiledData destructor
- data->compositeTypes.insert(compilationUnit->typeIds.id.iface(), compilationUnit);
+ auto doInsert = [&data, &compilationUnit](const QtPrivate::QMetaTypeInterface *iface) {
+ Q_ASSERT(iface);
+ const auto it = data->compositeTypes.constFind(iface);
+ Q_ASSERT(it == data->compositeTypes.constEnd() || *it == compilationUnit);
+ data->compositeTypes.insert(iface, compilationUnit);
+ };
+
+ doInsert(compilationUnit->qmlType.typeId().iface());
for (auto &&inlineData: compilationUnit->inlineComponentData)
- data->compositeTypes.insert(inlineData.typeIds.id.iface(), compilationUnit);
+ doInsert(inlineData.qmlType.typeId().iface());
}
-void QQmlMetaType::unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit)
+void QQmlMetaType::unregisterInternalCompositeType(
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit)
{
- compilationUnit->isRegistered = false;
+ QQmlMetaTypeDataPtr data;
+
+ auto doRemove = [&](const QtPrivate::QMetaTypeInterface *iface) {
+ if (!iface)
+ return;
+ const auto it = data->compositeTypes.constFind(iface);
+ if (it != data->compositeTypes.constEnd() && *it == compilationUnit)
+ data->compositeTypes.erase(it);
+ };
+
+ doRemove(compilationUnit->qmlType.typeId().iface());
+ for (auto &&inlineData: compilationUnit->inlineComponentData)
+ doRemove(inlineData.qmlType.typeId().iface());
+}
+
+int QQmlMetaType::countInternalCompositeTypeSelfReferences(
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit)
+{
QQmlMetaTypeDataPtr data;
- data->compositeTypes.remove(compilationUnit->typeIds.id.iface());
- for (auto&& icDatum: compilationUnit->inlineComponentData)
- data->compositeTypes.remove(icDatum.typeIds.id.iface());
+
+ int result = 0;
+ auto doCheck = [&](const QtPrivate::QMetaTypeInterface *iface) {
+ if (!iface)
+ return;
+
+ const auto it = data->compositeTypes.constFind(iface);
+ if (it != data->compositeTypes.constEnd() && *it == compilationUnit)
+ ++result;
+ };
+
+ doCheck(compilationUnit->qmlType.typeId().iface());
+ for (auto &&inlineData: compilationUnit->inlineComponentData)
+ doCheck(inlineData.qmlType.typeId().iface());
+
+ return result;
}
-QV4::ExecutableCompilationUnit *QQmlMetaType::obtainExecutableCompilationUnit(QMetaType type)
+QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlMetaType::obtainExecutableCompilationUnit(
+ QMetaType type)
{
const QQmlMetaTypeDataPtr data;
return data->compositeTypes.value(type.iface());