diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2019-02-01 14:51:15 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2019-02-08 09:24:43 +0000 |
commit | 56a5103781a17a2ae0369bbd468d7103d8df6d6b (patch) | |
tree | 8c34822bbe2c332c6b6a57e968785a21ec8bbfc2 /src/qml/qml/qqmlimport.cpp | |
parent | 92f2447cf3850303f161271c049a5b8d0a55b9f5 (diff) |
Move registration functions from qqmlimport.cpp to qqmlmetatype.cpp
These functions require the metatype data in multiple interdependent
places. If they are executed concurrently data races are almost
guaranteed.
Move the functions to qqmlmetatype.cpp and keep the metatype mutex
locked for their duration. Access to the internals of the metatype
system also allows us to significantly simplify the logic.
Additionally we can remove methods only used by those functions from the
public interface of QQmlMetaType now.
Task-number: QTBUG-73271
Change-Id: I1279259cca5cb5be63026d5b74f5d013e7a1ac5c
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/qml/qml/qqmlimport.cpp')
-rw-r--r-- | src/qml/qml/qqmlimport.cpp | 167 |
1 files changed, 10 insertions, 157 deletions
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index 5b22d8c6ed..90c2c1fb96 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -55,7 +55,6 @@ #include <private/qqmlengine_p.h> #include <private/qfieldlist_p.h> #include <private/qqmltypemodule_p.h> -#include <private/qqmlmetatyperegistrationfailurerecorder_p.h> #include <QtCore/qjsonobject.h> #include <QtCore/qjsonarray.h> @@ -133,85 +132,6 @@ bool isPathAbsolute(const QString &path) #endif } -/* - \internal - - Fetches the QQmlType instance registered for \a urlString, creating a - registration for it if it is not already registered, using the associated - \a typeName, \a isCompositeSingleton, \a majorVersion and \a minorVersion - details. - - Errors (if there are any) are placed into \a errors, if it is nonzero. Note - that errors are treated as fatal if \a errors is not set. -*/ -QQmlType fetchOrCreateTypeForUrl(const QString &urlString, const QHashedStringRef& typeName, - bool isCompositeSingleton, QList<QQmlError> *errors, - int majorVersion=-1, int minorVersion=-1) -{ - QUrl url(urlString); // ### unfortunate (costly) conversion - QQmlType ret = QQmlMetaType::qmlType(url); - if (ret.isValid()) - return ret; - - int dot = typeName.indexOf(QLatin1Char('.')); - QHashedStringRef unqualifiedtype = dot < 0 ? typeName : QHashedStringRef(typeName.constData() + dot + 1, typeName.length() - dot - 1); - - // We need a pointer, but we were passed a string. Take a copy so we - // can guarentee it will live long enough to reach qmlregister. - QByteArray buf(unqualifiedtype.toString().toUtf8()); - - QQmlMetaTypeRegistrationFailureRecorder failureRecorder; - - // 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. - if (isCompositeSingleton) { - QQmlPrivate::RegisterCompositeSingletonType reg = { - url, - "", // uri - majorVersion, - minorVersion, - buf.constData() - }; - ret = QQmlMetaType::registerCompositeSingletonType(reg); - } else { - QQmlPrivate::RegisterCompositeType reg = { - url, - "", // uri - majorVersion, - minorVersion, - buf.constData() - }; - ret = QQmlMetaType::registerCompositeType(reg); - } - - // 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 (!ret.isValid()) { - if (!errors) // Cannot list errors properly, just quit - qFatal("%s", failureRecorder.failures().join('\n').toLatin1().constData()); - QQmlError error; - error.setDescription(failureRecorder.failures().join('\n')); - errors->prepend(error); - } - return ret; -} - } // namespace struct RegisteredPlugin { @@ -822,9 +742,9 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt if (candidate != end) { if (!base) // ensure we have a componentUrl componentUrl = resolveLocalUrl(QString(url + candidate->typeName + dotqml_string), candidate->fileName); - QQmlType returnType = fetchOrCreateTypeForUrl(componentUrl, type, isCompositeSingleton, - nullptr, candidate->majorVersion, - candidate->minorVersion); + QQmlType returnType = QQmlMetaType::typeForUrl(componentUrl, type, isCompositeSingleton, + nullptr, candidate->majorVersion, + candidate->minorVersion); if (vmajor) *vmajor = candidate->majorVersion; if (vminor) @@ -868,8 +788,8 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt if (typeRecursionDetected) *typeRecursionDetected = true; } else { - QQmlType returnType = fetchOrCreateTypeForUrl( - qmlUrl, type, registrationType == QQmlType::CompositeSingletonType, nullptr); + QQmlType returnType = QQmlMetaType::typeForUrl( + qmlUrl, type, registrationType == QQmlType::CompositeSingletonType, nullptr); if (type_return) *type_return = returnType; return returnType.isValid(); @@ -917,7 +837,10 @@ bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor, return true; if (s->imports.count() == 1 && !s->imports.at(0)->isLibrary && type_return && s != &unqualifiedset) { // qualified, and only 1 url - *type_return = fetchOrCreateTypeForUrl(resolveLocalUrl(s->imports.at(0)->url, unqualifiedtype.toString() + QLatin1String(".qml")), type, false, errors); + *type_return = QQmlMetaType::typeForUrl( + resolveLocalUrl(s->imports.at(0)->url, + unqualifiedtype.toString() + QLatin1String(".qml")), + type, false, errors); return type_return->isValid(); } } @@ -2035,77 +1958,7 @@ bool QQmlImportDatabase::registerPluginTypes(QObject *instance, const QString &b { if (qmlImportTrace()) qDebug().nospace() << "QQmlImportDatabase::registerPluginTypes: " << uri << " from " << basePath; - - QQmlTypesExtensionInterface *iface = qobject_cast<QQmlTypesExtensionInterface *>(instance); - if (!iface) { - if (errors) { - QQmlError error; - error.setDescription(tr("Module loaded for URI '%1' does not implement QQmlTypesExtensionInterface").arg(typeNamespace)); - errors->prepend(error); - } - return false; - } - - const QByteArray bytes = uri.toUtf8(); - const char *moduleId = bytes.constData(); - - QQmlMetaTypeRegistrationFailureRecorder failureRecorder; - { - // Create a scope for QWriteLocker to keep it as narrow as possible, and - // to ensure that we release it before the call to initalizeEngine below - QMutexLocker lock(QQmlMetaType::typeRegistrationLock()); - - if (!typeNamespace.isEmpty()) { - // This is an 'identified' module - if (typeNamespace != uri) { - // The namespace for type registrations must match the URI for locating the module - if (errors) { - QQmlError error; - error.setDescription(tr("Module namespace '%1' does not match import URI '%2'").arg(typeNamespace).arg(uri)); - errors->prepend(error); - } - return false; - } - - if (QQmlMetaType::namespaceContainsRegistrations(typeNamespace, vmaj)) { - // Other modules have already installed to this namespace - if (errors) { - QQmlError error; - error.setDescription(tr("Namespace '%1' has already been used for type registration").arg(typeNamespace)); - errors->prepend(error); - } - return false; - } else { - QQmlMetaType::protectNamespace(typeNamespace); - } - } else { - // This is not an identified module - provide a warning - qWarning().nospace() << qPrintable(tr("Module '%1' does not contain a module identifier directive - it cannot be protected from external registrations.").arg(uri)); - } - - QQmlMetaType::setTypeRegistrationNamespace(typeNamespace); - - if (QQmlExtensionPlugin *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); - } - - iface->registerTypes(moduleId); - QQmlMetaType::setTypeRegistrationNamespace(QString()); - } // QWriteLocker lock(QQmlMetaType::typeRegistrationLock()) - - if (!failureRecorder.failures().isEmpty()) { - if (errors) { - for (const QString &failure : failureRecorder.failures()) { - QQmlError error; - error.setDescription(failure); - errors->prepend(error); - } - } - return false; - } - - return true; + return QQmlMetaType::registerPluginTypes(instance, basePath, uri, typeNamespace, vmaj, errors); } /*! |