diff options
Diffstat (limited to 'src/qml/qml/qqmltypenamecache_p.h')
-rw-r--r-- | src/qml/qml/qqmltypenamecache_p.h | 177 |
1 files changed, 129 insertions, 48 deletions
diff --git a/src/qml/qml/qqmltypenamecache_p.h b/src/qml/qml/qqmltypenamecache_p.h index 974f99ecae..1ec0a65fa0 100644 --- a/src/qml/qml/qqmltypenamecache_p.h +++ b/src/qml/qml/qqmltypenamecache_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** 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 QQMLTYPENAMECACHE_P_H #define QQMLTYPENAMECACHE_P_H @@ -81,11 +45,11 @@ struct QQmlImportRef { class QQmlType; class QQmlEngine; -class Q_QML_PRIVATE_EXPORT QQmlTypeNameCache : public QQmlRefCount +class Q_QML_EXPORT QQmlTypeNameCache final : public QQmlRefCounted<QQmlTypeNameCache> { public: - QQmlTypeNameCache(const QQmlImports &imports); - ~QQmlTypeNameCache() override; + QQmlTypeNameCache(const QQmlRefPointer<QQmlImports> &imports) : m_imports(imports) {} + ~QQmlTypeNameCache() {} inline bool isEmpty() const; @@ -104,16 +68,133 @@ public: const QQmlImportRef *importNamespace; int scriptIndex; }; - Result query(const QHashedStringRef &) const; - Result query(const QHashedStringRef &, const QQmlImportRef *importNamespace) const; - Result query(const QV4::String *, QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion) const; - Result query(const QV4::String *, const QQmlImportRef *importNamespace) const; + + enum class QueryNamespaced { No, Yes }; + + // Restrict the types allowed for key. We don't want QV4::ScopedString, for example. + + template<QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion> + Result query(const QHashedStringRef &key, QQmlTypeLoader *typeLoader) const + { + return doQuery<const QHashedStringRef &, recursionRestriction>(key, typeLoader); + } + + template<QueryNamespaced queryNamespaced = QueryNamespaced::Yes> + Result query(const QHashedStringRef &key, const QQmlImportRef *importNamespace, + QQmlTypeLoader *typeLoader) const + { + return doQuery<const QHashedStringRef &, queryNamespaced>(key, importNamespace, typeLoader); + } + + template<QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion> + Result query(const QV4::String *key, QQmlTypeLoader *typeLoader) const + { + return doQuery<const QV4::String *, recursionRestriction>(key, typeLoader); + } + + template<QueryNamespaced queryNamespaced = QueryNamespaced::Yes> + Result query(const QV4::String *key, const QQmlImportRef *importNamespace, + QQmlTypeLoader *typeLoader) const + { + return doQuery<const QV4::String *, queryNamespaced>(key, importNamespace, typeLoader); + } private: friend class QQmlImports; + static QHashedStringRef toHashedStringRef(const QHashedStringRef &key) { return key; } + static QHashedStringRef toHashedStringRef(const QV4::String *key) + { + const QV4::Heap::String *heapString = key->d(); + + // toQString() would also do simplifyString(). Therefore, we can be sure that this + // is safe. Any other operation on the string data cannot keep references on the + // non-simplified pieces. + if (heapString->subtype >= QV4::Heap::String::StringType_Complex) + heapString->simplifyString(); + + // This is safe because the string data is backed by the QV4::String we got as + // parameter. The contract about passing V4 values as parameters is that you have to + // scope them first, so that they don't get gc'd while the callee is working on them. + const QStringPrivate &text = heapString->text(); + return QHashedStringRef(QStringView(text.ptr, text.size)); + } + + static QString toQString(const QHashedStringRef &key) { return key.toString(); } + static QString toQString(const QV4::String *key) { return key->toQStringNoThrow(); } + + template<typename Key, QQmlImport::RecursionRestriction recursionRestriction> + Result doQuery(Key name, QQmlTypeLoader *typeLoader) const + { + Result result = doQuery(m_namedImports, name); + + if (!result.isValid()) + result = typeSearch(m_anonymousImports, name); + + if (!result.isValid()) + result = doQuery(m_anonymousCompositeSingletons, name); + + if (!result.isValid()) { + // Look up anonymous types from the imports of this document + // ### it would be nice if QQmlImports allowed us to resolve a namespace + // first, and then types on it. + QQmlImportNamespace *typeNamespace = nullptr; + QList<QQmlError> errors; + QQmlType t; + bool typeRecursionDetected = false; + const bool typeFound = m_imports->resolveType( + typeLoader, toHashedStringRef(name), &t, nullptr, &typeNamespace, &errors, + QQmlType::AnyRegistrationType, + recursionRestriction == QQmlImport::AllowRecursion + ? &typeRecursionDetected + : nullptr); + if (typeFound) + return Result(t); + + } + + return result; + } + + template<typename Key, QueryNamespaced queryNamespaced> + Result doQuery(Key name, const QQmlImportRef *importNamespace, QQmlTypeLoader *typeLoader) const + { + Q_ASSERT(importNamespace && importNamespace->scriptIndex == -1); + + if constexpr (queryNamespaced == QueryNamespaced::Yes) { + QMap<const QQmlImportRef *, QStringHash<QQmlImportRef> >::const_iterator it + = m_namespacedImports.constFind(importNamespace); + if (it != m_namespacedImports.constEnd()) { + Result r = doQuery(*it, name); + if (r.isValid()) + return r; + } + } + + Result result = typeSearch(importNamespace->modules, name); + + if (!result.isValid()) + result = doQuery(importNamespace->compositeSingletons, name); + + if (!result.isValid()) { + // Look up types from the imports of this document + // ### it would be nice if QQmlImports allowed us to resolve a namespace + // first, and then types on it. + const QString qualifiedTypeName = importNamespace->m_qualifier + u'.' + toQString(name); + QQmlImportNamespace *typeNamespace = nullptr; + QList<QQmlError> errors; + QQmlType t; + bool typeFound = m_imports->resolveType( + typeLoader, qualifiedTypeName, &t, nullptr, &typeNamespace, &errors); + if (typeFound) + return Result(t); + } + + return result; + } + template<typename Key> - Result query(const QStringHash<QQmlImportRef> &imports, Key key) const + Result doQuery(const QStringHash<QQmlImportRef> &imports, Key key) const { QQmlImportRef *i = imports.value(key); if (i) { @@ -129,7 +210,7 @@ private: } template<typename Key> - Result query(const QStringHash<QUrl> &urls, Key key) const + Result doQuery(const QStringHash<QUrl> &urls, Key key) const { QUrl *url = urls.value(key); if (url) { @@ -157,7 +238,7 @@ private: QMap<const QQmlImportRef *, QStringHash<QQmlImportRef> > m_namespacedImports; QVector<QQmlTypeModuleVersion> m_anonymousImports; QStringHash<QUrl> m_anonymousCompositeSingletons; - QQmlImports m_imports; + QQmlRefPointer<QQmlImports> m_imports; }; QQmlTypeNameCache::Result::Result() |