/**************************************************************************** ** ** 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$ ** ****************************************************************************/ #ifndef QQMLTYPENAMECACHE_P_H #define QQMLTYPENAMECACHE_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include #include "qqmlmetatype_p.h" #include #include #include #include QT_BEGIN_NAMESPACE struct QQmlImportRef { inline QQmlImportRef() : scriptIndex(-1) {} // Imported module QVector modules; // Or, imported script int scriptIndex; // Or, imported compositeSingletons QStringHash compositeSingletons; // The qualifier of this import QString m_qualifier; }; class QQmlType; class QQmlEngine; class Q_QML_PRIVATE_EXPORT QQmlTypeNameCache : public QQmlRefCount { public: QQmlTypeNameCache(const QQmlImports &imports); ~QQmlTypeNameCache() override; inline bool isEmpty() const; void add(const QHashedString &name, int sciptIndex = -1, const QHashedString &nameSpace = QHashedString()); void add(const QHashedString &name, const QUrl &url, const QHashedString &nameSpace = QHashedString()); struct Result { inline Result(); inline Result(const QQmlImportRef *importNamespace); inline Result(const QQmlType &type); inline Result(int scriptIndex); inline bool isValid() const; QQmlType type; const QQmlImportRef *importNamespace; int scriptIndex; }; enum class QueryNamespaced { No, Yes }; // Restrict the types allowed for key. We don't want QV4::ScopedString, for example. template Result query(const QHashedStringRef &key) const { return doQuery(key); } template Result query(const QHashedStringRef &key, const QQmlImportRef *importNamespace) const { return doQuery(key, importNamespace); } template Result query(const QV4::String *key) const { return doQuery(key); } template Result query(const QV4::String *key, const QQmlImportRef *importNamespace) const { return doQuery(key, importNamespace); } 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 Result doQuery(Key name) 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 errors; QQmlType t; bool typeRecursionDetected = false; const bool typeFound = m_imports.resolveType( toHashedStringRef(name), &t, nullptr, &typeNamespace, &errors, QQmlType::AnyRegistrationType, recursionRestriction == QQmlImport::AllowRecursion ? &typeRecursionDetected : nullptr); if (typeFound) return Result(t); } return result; } template Result doQuery(Key name, const QQmlImportRef *importNamespace) const { Q_ASSERT(importNamespace && importNamespace->scriptIndex == -1); if constexpr (queryNamespaced == QueryNamespaced::Yes) { QMap >::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 errors; QQmlType t; bool typeFound = m_imports.resolveType( qualifiedTypeName, &t, nullptr, &typeNamespace, &errors); if (typeFound) return Result(t); } return result; } template Result doQuery(const QStringHash &imports, Key key) const { QQmlImportRef *i = imports.value(key); if (i) { Q_ASSERT(!i->m_qualifier.isEmpty()); if (i->scriptIndex != -1) { return Result(i->scriptIndex); } else { return Result(i); } } return Result(); } template Result doQuery(const QStringHash &urls, Key key) const { QUrl *url = urls.value(key); if (url) { QQmlType type = QQmlMetaType::qmlType(*url); return Result(type); } return Result(); } template Result typeSearch(const QVector &modules, Key key) const { QVector::const_iterator end = modules.constEnd(); for (QVector::const_iterator it = modules.constBegin(); it != end; ++it) { QQmlType type = it->type(key); if (type.isValid()) return Result(type); } return Result(); } QStringHash m_namedImports; QMap > m_namespacedImports; QVector m_anonymousImports; QStringHash m_anonymousCompositeSingletons; QQmlImports m_imports; }; QQmlTypeNameCache::Result::Result() : importNamespace(nullptr), scriptIndex(-1) { } QQmlTypeNameCache::Result::Result(const QQmlImportRef *importNamespace) : importNamespace(importNamespace), scriptIndex(-1) { } QQmlTypeNameCache::Result::Result(const QQmlType &type) : type(type), importNamespace(nullptr), scriptIndex(-1) { } QQmlTypeNameCache::Result::Result(int scriptIndex) : importNamespace(nullptr), scriptIndex(scriptIndex) { } bool QQmlTypeNameCache::Result::isValid() const { return type.isValid() || importNamespace || scriptIndex != -1; } bool QQmlTypeNameCache::isEmpty() const { return m_namedImports.isEmpty() && m_anonymousImports.isEmpty() && m_anonymousCompositeSingletons.isEmpty(); } QT_END_NAMESPACE #endif // QQMLTYPENAMECACHE_P_H