Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqmltypenamecache_p.h
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant
4
5#ifndef QQMLTYPENAMECACHE_P_H
6#define QQMLTYPENAMECACHE_P_H
7
8//
9// W A R N I N G
10// -------------
11//
12// This file is not part of the Qt API. It exists purely as an
13// implementation detail. This header file may change from version to
14// version without notice, or even be removed.
15//
16// We mean it.
17//
18
19#include <private/qqmlrefcount_p.h>
20#include "qqmlmetatype_p.h"
21
22#include <private/qstringhash_p.h>
23#include <private/qqmlimport_p.h>
24#include <private/qqmltypemoduleversion_p.h>
25
26#include <QtCore/qvector.h>
27
29
32 : scriptIndex(-1)
33 {}
34 // Imported module
36
37 // Or, imported script
39
40 // Or, imported compositeSingletons
42
43 // The qualifier of this import
45};
46
47class QQmlType;
48class QQmlEngine;
49class Q_QML_EXPORT QQmlTypeNameCache final : public QQmlRefCounted<QQmlTypeNameCache>
50{
51public:
52 QQmlTypeNameCache(const QQmlRefPointer<QQmlImports> &imports) : m_imports(imports) {}
53 ~QQmlTypeNameCache() {}
54
55 const QQmlImportInstance *findImportByModuleUri(const QString &uri, QTypeRevision version) const
56 {
57 return m_imports->findImportByModuleUri(uri, version);
58 }
59
60 inline bool isEmpty() const;
61
62 void add(const QHashedString &name, int sciptIndex = -1, const QHashedString &nameSpace = QHashedString());
63 void add(const QHashedString &name, const QUrl &url, const QHashedString &nameSpace = QHashedString());
64
65 struct Result {
66 inline Result();
67 inline Result(const QQmlImportRef *importNamespace);
68 inline Result(const QQmlType &type);
69 inline Result(int scriptIndex);
70
71 inline bool isValid() const;
72
73 QQmlType type;
74 const QQmlImportRef *importNamespace;
75 int scriptIndex;
76 };
77
78 enum class QueryNamespaced { No, Yes };
79
80 // Restrict the types allowed for key. We don't want QV4::ScopedString, for example.
81
82 template<QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion>
83 Result query(const QHashedStringRef &key, QQmlTypeLoader *typeLoader) const
84 {
85 return doQuery<const QHashedStringRef &, recursionRestriction>(key, typeLoader);
86 }
87
88 template<QueryNamespaced queryNamespaced = QueryNamespaced::Yes>
89 Result query(const QHashedStringRef &key, const QQmlImportRef *importNamespace,
90 QQmlTypeLoader *typeLoader) const
91 {
92 return doQuery<const QHashedStringRef &, queryNamespaced>(key, importNamespace, typeLoader);
93 }
94
95 template<QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion>
96 Result query(const QV4::String *key, QQmlTypeLoader *typeLoader) const
97 {
98 return doQuery<const QV4::String *, recursionRestriction>(key, typeLoader);
99 }
100
101 template<QueryNamespaced queryNamespaced = QueryNamespaced::Yes>
102 Result query(const QV4::String *key, const QQmlImportRef *importNamespace,
103 QQmlTypeLoader *typeLoader) const
104 {
105 return doQuery<const QV4::String *, queryNamespaced>(key, importNamespace, typeLoader);
106 }
107
108private:
109 friend class QQmlImports;
110
111 static QHashedStringRef toHashedStringRef(const QHashedStringRef &key) { return key; }
112 static QHashedStringRef toHashedStringRef(const QV4::String *key)
113 {
114 const QV4::Heap::String *heapString = key->d();
115
116 // toQString() would also do simplifyString(). Therefore, we can be sure that this
117 // is safe. Any other operation on the string data cannot keep references on the
118 // non-simplified pieces.
119 if (heapString->subtype >= QV4::Heap::String::StringType_Complex)
120 heapString->simplifyString();
121
122 // This is safe because the string data is backed by the QV4::String we got as
123 // parameter. The contract about passing V4 values as parameters is that you have to
124 // scope them first, so that they don't get gc'd while the callee is working on them.
125 const QStringPrivate &text = heapString->text();
126 return QHashedStringRef(QStringView(text.ptr, text.size));
127 }
128
129 static QString toQString(const QHashedStringRef &key) { return key.toString(); }
130 static QString toQString(const QV4::String *key) { return key->toQStringNoThrow(); }
131
132 template<typename Key, QQmlImport::RecursionRestriction recursionRestriction>
133 Result doQuery(Key name, QQmlTypeLoader *typeLoader) const
134 {
135 Result result = doQuery(m_namedImports, name);
136
137 if (!result.isValid())
138 result = typeSearch(m_anonymousImports, name);
139
140 if (!result.isValid())
141 result = doQuery(m_anonymousCompositeSingletons, name);
142
143 if (!result.isValid()) {
144 // Look up anonymous types from the imports of this document
145 // ### it would be nice if QQmlImports allowed us to resolve a namespace
146 // first, and then types on it.
147 QQmlImportNamespace *typeNamespace = nullptr;
148 QList<QQmlError> errors;
149 QQmlType t;
150 bool typeRecursionDetected = false;
151 const bool typeFound = m_imports->resolveType(
152 typeLoader, toHashedStringRef(name), &t, nullptr, &typeNamespace, &errors,
153 QQmlType::AnyRegistrationType,
154 recursionRestriction == QQmlImport::AllowRecursion
155 ? &typeRecursionDetected
156 : nullptr);
157 if (typeFound)
158 return Result(t);
159
160 }
161
162 return result;
163 }
164
165 template<typename Key, QueryNamespaced queryNamespaced>
166 Result doQuery(Key name, const QQmlImportRef *importNamespace, QQmlTypeLoader *typeLoader) const
167 {
168 Q_ASSERT(importNamespace && importNamespace->scriptIndex == -1);
169
170 if constexpr (queryNamespaced == QueryNamespaced::Yes) {
171 const auto it = m_namespacedImports.constFind(importNamespace);
172 if (it != m_namespacedImports.constEnd()) {
173 Result r = doQuery(*it, name);
174 if (r.isValid())
175 return r;
176 }
177 }
178
179 Result result = typeSearch(importNamespace->modules, name);
180
181 if (!result.isValid())
182 result = doQuery(importNamespace->compositeSingletons, name);
183
184 if (!result.isValid()) {
185 // Look up types from the imports of this document
186 // ### it would be nice if QQmlImports allowed us to resolve a namespace
187 // first, and then types on it.
188 const QString qualifiedTypeName = importNamespace->m_qualifier + u'.' + toQString(name);
189 QQmlImportNamespace *typeNamespace = nullptr;
190 QList<QQmlError> errors;
191 QQmlType t;
192 bool typeFound = m_imports->resolveType(
193 typeLoader, qualifiedTypeName, &t, nullptr, &typeNamespace, &errors);
194 if (typeFound)
195 return Result(t);
196 }
197
198 return result;
199 }
200
201 template<typename Key>
202 Result doQuery(const QStringHash<QQmlImportRef> &imports, Key key) const
203 {
204 QQmlImportRef *i = imports.value(key);
205 if (i) {
206 Q_ASSERT(!i->m_qualifier.isEmpty());
207 if (i->scriptIndex != -1) {
208 return Result(i->scriptIndex);
209 } else {
210 return Result(i);
211 }
212 }
213
214 return Result();
215 }
216
217 template<typename Key>
218 Result doQuery(const QStringHash<QUrl> &urls, Key key) const
219 {
220 QUrl *url = urls.value(key);
221 if (url) {
222 QQmlType type = QQmlMetaType::qmlType(*url);
223 return Result(type);
224 }
225
226 return Result();
227 }
228
229 template<typename Key>
230 Result typeSearch(const QList<QQmlTypeModuleVersion> &modules, Key key) const
231 {
232 for (auto it = modules.crbegin(), end = modules.crend(); it != end; ++it) {
233 QQmlType type = it->type(key);
234 if (type.isValid())
235 return Result(type);
236 }
237
238 return Result();
239 }
240
241 QStringHash<QQmlImportRef> m_namedImports;
242 QHash<const QQmlImportRef *, QStringHash<QQmlImportRef>> m_namespacedImports;
243 QList<QQmlTypeModuleVersion> m_anonymousImports;
244 QStringHash<QUrl> m_anonymousCompositeSingletons;
245 QQmlRefPointer<QQmlImports> m_imports;
246};
247
248QQmlTypeNameCache::Result::Result()
249: importNamespace(nullptr), scriptIndex(-1)
250{
251}
252
253QQmlTypeNameCache::Result::Result(const QQmlImportRef *importNamespace)
254: importNamespace(importNamespace), scriptIndex(-1)
255{
256}
257
258QQmlTypeNameCache::Result::Result(const QQmlType &type)
259: type(type), importNamespace(nullptr), scriptIndex(-1)
260{
261}
262
263QQmlTypeNameCache::Result::Result(int scriptIndex)
264: importNamespace(nullptr), scriptIndex(scriptIndex)
265{
266}
267
268bool QQmlTypeNameCache::Result::isValid() const
269{
270 return type.isValid() || importNamespace || scriptIndex != -1;
271}
272
273bool QQmlTypeNameCache::isEmpty() const
274{
275 return m_namedImports.isEmpty() && m_anonymousImports.isEmpty()
276 && m_anonymousCompositeSingletons.isEmpty();
277}
278
279QT_END_NAMESPACE
280
281#endif // QQMLTYPENAMECACHE_P_H
Combined button and popup list for selecting options.
QList< QQmlTypeModuleVersion > modules
QStringHash< QUrl > compositeSingletons