aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlimport_p.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml/qqmlimport_p.h')
-rw-r--r--src/qml/qml/qqmlimport_p.h383
1 files changed, 275 insertions, 108 deletions
diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h
index 7a8e1f9dd4..ef9b4b3422 100644
--- a/src/qml/qml/qqmlimport_p.h
+++ b/src/qml/qml/qqmlimport_p.h
@@ -1,53 +1,21 @@
-/****************************************************************************
-**
-** 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
#ifndef QQMLIMPORT_P_H
#define QQMLIMPORT_P_H
#include <QtCore/qurl.h>
#include <QtCore/qcoreapplication.h>
+#include <QtCore/qloggingcategory.h>
#include <QtCore/qset.h>
#include <QtCore/qstringlist.h>
+#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlerror.h>
+#include <QtQml/qqmlfile.h>
#include <private/qqmldirparser_p.h>
#include <private/qqmltype_p.h>
#include <private/qstringhash_p.h>
+#include <private/qfieldlist_p.h>
//
// W A R N I N G
@@ -66,10 +34,12 @@ class QQmlTypeNameCache;
class QQmlEngine;
class QDir;
class QQmlImportNamespace;
-class QQmlImportsPrivate;
class QQmlImportDatabase;
class QQmlTypeLoader;
class QQmlTypeLoaderQmldirContent;
+class QTypeRevision;
+
+const QLoggingCategory &lcQmlImport();
namespace QQmlImport {
enum RecursionRestriction { PreventRecursion, AllowRecursion };
@@ -77,13 +47,24 @@ namespace QQmlImport {
struct QQmlImportInstance
{
+ enum Precedence {
+ Lowest = std::numeric_limits<quint8>::max(),
+ Implicit = Lowest / 2,
+ Highest = 0,
+ };
+
QString uri; // e.g. QtQuick
QString url; // the base path of the import
- QQmlType containingType; // points to the containing type for inline components
QTypeRevision version; // the version imported
+
bool isLibrary; // true means that this is not a file import
+
+ // not covered by precedence. You can set a component as implicitly imported after the fact.
bool implicitlyImported = false;
bool isInlineComponent = false;
+
+ quint8 precedence = 0;
+
QQmlDirComponents qmlDirComponents; // a copy of the components listed in the qmldir
QQmlDirScripts qmlDirScripts; // a copy of the scripts in the qmldir
@@ -95,7 +76,7 @@ struct QQmlImportInstance
bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type,
QTypeRevision *version_return, QQmlType* type_return,
- QString *base = nullptr, bool *typeRecursionDetected = nullptr,
+ const QString *base = nullptr, bool *typeRecursionDetected = nullptr,
QQmlType::RegistrationType = QQmlType::AnyRegistrationType,
QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion,
QList<QQmlError> *errors = nullptr) const;
@@ -113,77 +94,85 @@ public:
bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef& type,
QTypeRevision *version_return, QQmlType* type_return,
- QString *base = nullptr, QList<QQmlError> *errors = nullptr,
+ const QString *base = nullptr, QList<QQmlError> *errors = nullptr,
QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType,
bool *typeRecursionDeteced = nullptr);
// Prefix when used as a qualified import. Otherwise empty.
QHashedString prefix;
- // Used by QQmlImportsPrivate::qualifiedSets
+ // Used by QQmlImports::m_qualifiedSets
// set to this in unqualifiedSet to indicate that the lists of imports needs
// to be sorted when an inline component import was added
// We can't use flag pointer, as that does not work with QFieldList
- QQmlImportNamespace *nextNamespace;
- bool needsSorting() const;
- void setNeedsSorting(bool needsSorting);
+ QQmlImportNamespace *nextNamespace = nullptr;
+ bool needsSorting() const { return nextNamespace == this; }
+ void setNeedsSorting(bool needsSorting)
+ {
+ Q_ASSERT(nextNamespace == this || nextNamespace == nullptr);
+ nextNamespace = needsSorting ? this : nullptr;
+ }
};
-class Q_QML_PRIVATE_EXPORT QQmlImports
+class Q_QML_EXPORT QQmlImports final : public QQmlRefCounted<QQmlImports>
{
+ Q_DISABLE_COPY_MOVE(QQmlImports)
public:
enum ImportVersion { FullyVersioned, PartiallyVersioned, Unversioned };
- enum ImportFlag { ImportIncomplete = 0x1, ImportLowPrecedence = 0x2, ImportImplicit = 0x4 };
- QQmlImports(QQmlTypeLoader *);
- QQmlImports(const QQmlImports &);
- ~QQmlImports();
- QQmlImports &operator=(const QQmlImports &);
+ enum ImportFlag : quint8 {
+ ImportNoFlag = 0x0,
+ ImportIncomplete = 0x1,
+ };
+ Q_DECLARE_FLAGS(ImportFlags, ImportFlag)
+
+ QQmlImports() = default;
+ ~QQmlImports()
+ {
+ while (QQmlImportNamespace *ns = m_qualifiedSets.takeFirst())
+ delete ns;
+ }
void setBaseUrl(const QUrl &url, const QString &urlString = QString());
- QUrl baseUrl() const;
+ QUrl baseUrl() const { return m_baseUrl; }
- bool resolveType(const QHashedStringRef &type,
- QQmlType *type_return,
- QTypeRevision *version_return,
- QQmlImportNamespace **ns_return,
- QList<QQmlError> *errors = nullptr,
- QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType,
- bool *typeRecursionDetected = nullptr) const;
- bool resolveType(QQmlImportNamespace *,
- const QHashedStringRef& type,
- QQmlType *type_return, QTypeRevision *version_return,
- QQmlType::RegistrationType registrationType
- = QQmlType::AnyRegistrationType) const;
+ bool resolveType(
+ QQmlTypeLoader *typeLoader, const QHashedStringRef &type, QQmlType *type_return,
+ QTypeRevision *version_return, QQmlImportNamespace **ns_return,
+ QList<QQmlError> *errors = nullptr,
+ QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType,
+ bool *typeRecursionDetected = nullptr) const;
QTypeRevision addImplicitImport(
- QQmlImportDatabase *importDb, QList<QQmlError> *errors);
+ QQmlTypeLoader *typeLoader, QString *localQmldir, QList<QQmlError> *errors)
+ {
+ Q_ASSERT(errors);
+ qCDebug(lcQmlImport) << "addImplicitImport:" << qPrintable(baseUrl().toString());
+
+ const ImportFlags flags =
+ ImportFlags(!isLocal(baseUrl()) ? ImportIncomplete : ImportNoFlag);
+ return addFileImport(
+ typeLoader, QLatin1String("."), QString(), QTypeRevision(), flags,
+ QQmlImportInstance::Implicit, localQmldir, errors);
+ }
- bool addInlineComponentImport(QQmlImportInstance *const importInstance, const QString &name, const QUrl importUrl, QQmlType containingType);
+ bool addInlineComponentImport(
+ QQmlImportInstance *const importInstance, const QString &name, const QUrl importUrl);
QTypeRevision addFileImport(
- QQmlImportDatabase *, const QString& uri, const QString& prefix, QTypeRevision version,
- uint flags, QList<QQmlError> *errors);
+ QQmlTypeLoader *typeLoader, const QString &uri, const QString &prefix,
+ QTypeRevision version, ImportFlags flags, quint16 precedence, QString *localQmldir,
+ QList<QQmlError> *errors);
QTypeRevision addLibraryImport(
- QQmlImportDatabase *importDb, const QString &uri, const QString &prefix,
+ QQmlTypeLoader *typeLoader, const QString &uri, const QString &prefix,
QTypeRevision version, const QString &qmldirIdentifier, const QString &qmldirUrl,
- uint flags, QList<QQmlError> *errors);
+ ImportFlags flags, quint16 precedence, QList<QQmlError> *errors);
QTypeRevision updateQmldirContent(
- QQmlImportDatabase *importDb, const QString &uri, const QString &prefix,
+ QQmlTypeLoader *typeLoader, const QString &uri, const QString &prefix,
const QString &qmldirIdentifier, const QString &qmldirUrl, QList<QQmlError> *errors);
- enum LocalQmldirResult {
- QmldirFound,
- QmldirNotFound,
- QmldirInterceptedToRemote
- };
-
- LocalQmldirResult locateLocalQmldir(
- QQmlImportDatabase *, const QString &uri, QTypeRevision version,
- QString *qmldirFilePath, QString *url);
-
void populateCache(QQmlTypeNameCache *cache) const;
struct ScriptReference
@@ -204,58 +193,118 @@ public:
QList<CompositeSingletonReference> resolvedCompositeSingletons() const;
- static QStringList completeQmldirPaths(const QString &uri, const QStringList &basePaths,
- QTypeRevision version);
+ static QStringList completeQmldirPaths(
+ const QString &uri, const QStringList &basePaths, QTypeRevision version);
+
static QString versionString(QTypeRevision version, ImportVersion importVersion);
- static bool isLocal(const QString &url);
- static bool isLocal(const QUrl &url);
+ static bool isLocal(const QString &url)
+ {
+ return !QQmlFile::urlToLocalFileOrQrc(url).isEmpty();
+ }
+
+ static bool isLocal(const QUrl &url)
+ {
+ return !QQmlFile::urlToLocalFileOrQrc(url).isEmpty();
+ }
+
static QUrl urlFromLocalFileOrQrcOrUrl(const QString &);
static void setDesignerSupportRequired(bool b);
+ static QTypeRevision validVersion(QTypeRevision version = QTypeRevision());
+
private:
friend class QQmlImportDatabase;
- QQmlImportsPrivate *d;
+
+ QQmlImportNamespace *importNamespace(const QString &prefix);
+
+ bool resolveType(
+ QQmlTypeLoader *typeLoader, const QHashedStringRef &type, QTypeRevision *version_return,
+ QQmlType *type_return, QList<QQmlError> *errors,
+ QQmlType::RegistrationType registrationType,
+ bool *typeRecursionDetected = nullptr) const;
+
+ QQmlImportNamespace *findQualifiedNamespace(const QHashedStringRef &) const;
+
+ static QTypeRevision matchingQmldirVersion(
+ const QQmlTypeLoaderQmldirContent &qmldir, const QString &uri,
+ QTypeRevision version, QList<QQmlError> *errors);
+
+ QTypeRevision importExtension(
+ QQmlTypeLoader *typeLoader, const QString &uri, QTypeRevision version,
+ const QQmlTypeLoaderQmldirContent *qmldir, QList<QQmlError> *errors);
+
+ QString redirectQmldirContent(QQmlTypeLoader *typeLoader, QQmlTypeLoaderQmldirContent *qmldir);
+
+ bool getQmldirContent(
+ QQmlTypeLoader *typeLoader, const QString &qmldirIdentifier, const QString &uri,
+ QQmlTypeLoaderQmldirContent *qmldir, QList<QQmlError> *errors);
+
+ QString resolvedUri(const QString &dir_arg, QQmlImportDatabase *database);
+
+ QUrl m_baseUrl;
+ QString m_base;
+
+ // storage of data related to imports without a namespace
+ // TODO: This needs to be mutable because QQmlImportNamespace likes to sort itself on
+ // resolveType(). Therefore, QQmlImportNamespace::resolveType() is not const.
+ // There should be a better way to do this.
+ mutable QQmlImportNamespace m_unqualifiedset;
+
+ // storage of data related to imports with a namespace
+ QFieldList<QQmlImportNamespace, &QQmlImportNamespace::nextNamespace> m_qualifiedSets;
};
-class Q_QML_PRIVATE_EXPORT QQmlImportDatabase
+Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlImports::ImportFlags)
+
+class Q_QML_EXPORT QQmlImportDatabase
{
Q_DECLARE_TR_FUNCTIONS(QQmlImportDatabase)
public:
enum PathType { Local, Remote, LocalOrRemote };
+ enum LocalQmldirSearchLocation {
+ QmldirFileAndCache,
+ QmldirCacheOnly,
+ };
+
+ enum LocalQmldirResult {
+ QmldirFound,
+ QmldirNotFound,
+ QmldirInterceptedToRemote,
+ QmldirRejected
+ };
+
QQmlImportDatabase(QQmlEngine *);
- ~QQmlImportDatabase();
+ ~QQmlImportDatabase() { clearDirCache(); }
- QTypeRevision importDynamicPlugin(
- const QString &filePath, const QString &uri, const QString &importNamespace,
- QTypeRevision version, bool isOptional, QList<QQmlError> *errors);
- bool removeDynamicPlugin(const QString &filePath);
+ bool removeDynamicPlugin(const QString &pluginId);
QStringList dynamicPlugins() const;
QStringList importPathList(PathType type = LocalOrRemote) const;
void setImportPathList(const QStringList &paths);
void addImportPath(const QString& dir);
- QStringList pluginPathList() const;
+ QStringList pluginPathList() const { return filePluginPath; }
void setPluginPathList(const QStringList &paths);
+
void addPluginPath(const QString& path);
- QString resolvePlugin(QQmlTypeLoader *typeLoader,
- const QString &qmldirPath, const QString &qmldirPluginPath,
- const QString &baseName) const;
+ template<typename Callback>
+ LocalQmldirResult locateLocalQmldir(
+ const QString &uri, QTypeRevision version, LocalQmldirSearchLocation location,
+ const Callback &callback);
+
+ static QTypeRevision lockModule(const QString &uri, const QString &typeNamespace,
+ QTypeRevision version, QList<QQmlError> *errors);
+
private:
- friend class QQmlImportsPrivate;
- QString resolvePlugin(QQmlTypeLoader *typeLoader,
- const QString &qmldirPath, const QString &qmldirPluginPath,
- const QString &baseName, const QStringList &suffixes,
- const QString &prefix = QString()) const;
- QTypeRevision importStaticPlugin(
- QObject *instance, const QString &basePath, const QString &uri,
- const QString &typeNamespace, QTypeRevision version, QList<QQmlError> *errors);
+ friend class QQmlImports;
+ friend class QQmlPluginImporter;
+
+ QString absoluteFilePath(const QString &path) const;
void clearDirCache();
- void finalizePlugin(QObject *instance, const QString &path, const QString &uri);
struct QmldirCache {
QTypeRevision version;
@@ -264,18 +313,136 @@ private:
QmldirCache *next;
};
// Maps from an import to a linked list of qmldir info.
- // Used in QQmlImportsPrivate::locateQmldir()
+ // Used in QQmlImports::locateQmldir()
QStringHash<QmldirCache *> qmldirCache;
// XXX thread
QStringList filePluginPath;
QStringList fileImportPath;
- QSet<QString> qmlDirFilesForWhichPluginsHaveBeenLoaded;
+ QSet<QString> modulesForWhichPluginsHaveBeenLoaded;
QSet<QString> initializedPlugins;
QQmlEngine *engine;
};
+template<typename Callback>
+QQmlImportDatabase::LocalQmldirResult QQmlImportDatabase::locateLocalQmldir(
+ const QString &uri, QTypeRevision version,
+ QQmlImportDatabase::LocalQmldirSearchLocation location, const Callback &callback)
+{
+ // Check cache first
+
+ LocalQmldirResult result = QmldirNotFound;
+ QmldirCache *cacheTail = nullptr;
+
+ QmldirCache **cachePtr = qmldirCache.value(uri);
+ QmldirCache *cacheHead = cachePtr ? *cachePtr : nullptr;
+ if (cacheHead) {
+ cacheTail = cacheHead;
+ do {
+ if (cacheTail->version == version) {
+ if (cacheTail->qmldirFilePath.isEmpty()) {
+ return cacheTail->qmldirPathUrl.isEmpty()
+ ? QmldirNotFound
+ : QmldirInterceptedToRemote;
+ }
+ if (callback(cacheTail->qmldirFilePath, cacheTail->qmldirPathUrl))
+ return QmldirFound;
+ result = QmldirRejected;
+ }
+ } while (cacheTail->next && (cacheTail = cacheTail->next));
+ }
+
+
+ // Do not try to construct the cache if it already had any entries for the URI.
+ // Otherwise we might duplicate cache entries.
+ if (location == QmldirCacheOnly || result != QmldirNotFound)
+ return result;
+
+ const bool hasInterceptors = !engine->urlInterceptors().isEmpty();
+
+ // Interceptor might redirect remote files to local ones.
+ QStringList localImportPaths = importPathList(hasInterceptors ? LocalOrRemote : Local);
+
+ // Search local import paths for a matching version
+ const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(
+ uri, localImportPaths, version);
+
+ QString qmldirAbsoluteFilePath;
+ for (QString qmldirPath : qmlDirPaths) {
+ if (hasInterceptors) {
+ const QUrl intercepted = engine->interceptUrl(
+ QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath),
+ QQmlAbstractUrlInterceptor::QmldirFile);
+ qmldirPath = QQmlFile::urlToLocalFileOrQrc(intercepted);
+ if (result != QmldirInterceptedToRemote
+ && qmldirPath.isEmpty()
+ && !QQmlFile::isLocalFile(intercepted)) {
+ result = QmldirInterceptedToRemote;
+ }
+ }
+
+ qmldirAbsoluteFilePath = absoluteFilePath(qmldirPath);
+ if (!qmldirAbsoluteFilePath.isEmpty()) {
+ QString url;
+ const QString absolutePath = qmldirAbsoluteFilePath.left(
+ qmldirAbsoluteFilePath.lastIndexOf(u'/') + 1);
+ if (absolutePath.at(0) == u':') {
+ url = QStringLiteral("qrc") + absolutePath;
+ } else {
+ url = QUrl::fromLocalFile(absolutePath).toString();
+ // This handles the UNC path case as when the path is retrieved from the QUrl it
+ // will convert the host name from upper case to lower case. So the absoluteFilePath
+ // is changed at this point to make sure it will match later on in that case.
+ if (qmldirAbsoluteFilePath.startsWith(QStringLiteral("//"))) {
+ qmldirAbsoluteFilePath = QUrl::fromLocalFile(qmldirAbsoluteFilePath)
+ .toString(QUrl::RemoveScheme);
+ }
+ }
+
+ QmldirCache *cache = new QmldirCache;
+ cache->version = version;
+ cache->qmldirFilePath = qmldirAbsoluteFilePath;
+ cache->qmldirPathUrl = url;
+ cache->next = nullptr;
+ if (cacheTail)
+ cacheTail->next = cache;
+ else
+ qmldirCache.insert(uri, cache);
+ cacheTail = cache;
+
+ if (result != QmldirFound)
+ result = callback(qmldirAbsoluteFilePath, url) ? QmldirFound : QmldirRejected;
+
+ // Do not return here. Rather, construct the complete cache for this URI.
+ }
+ }
+
+ // Nothing found? Add an empty cache entry to signal that for further requests.
+ if (result == QmldirNotFound || result == QmldirInterceptedToRemote) {
+ QmldirCache *cache = new QmldirCache;
+ cache->version = version;
+ cache->next = cacheHead;
+ if (result == QmldirInterceptedToRemote) {
+ // The actual value doesn't matter as long as it's not empty.
+ // We only use it to discern QmldirInterceptedToRemote from QmldirNotFound above.
+ cache->qmldirPathUrl = QStringLiteral("intercepted");
+ }
+ qmldirCache.insert(uri, cache);
+
+ if (result == QmldirNotFound) {
+ qCDebug(lcQmlImport)
+ << "locateLocalQmldir:" << qPrintable(uri) << "module's qmldir file not found";
+ }
+ } else {
+ qCDebug(lcQmlImport)
+ << "locateLocalQmldir:" << qPrintable(uri) << "module's qmldir found at"
+ << qmldirAbsoluteFilePath;
+ }
+
+ return result;
+}
+
void qmlClearEnginePlugins();// For internal use by qmlClearRegisteredProperties
QT_END_NAMESPACE