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
qqmljsimporter_p.h
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3// Qt-Security score:significant
4
5#ifndef QQMLJSIMPORTER_P_H
6#define QQMLJSIMPORTER_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#include <qtqmlcompilerexports.h>
19
21#include "qqmljsscope_p.h"
23#include <QtQml/private/qqmldirparser_p.h>
24#include <QtQml/private/qqmljsast_p.h>
25
26#include <QtCore/qtyperevision.h>
27
29
30namespace QQmlJS {
31class Import
32{
33public:
34 Import() = default;
35 Import(QString prefix, QString name, QTypeRevision version, bool isFile, bool isDependency);
36
37 bool isValid() const;
38
39 QString prefix() const { return m_prefix; }
40 QString name() const { return m_name; }
41 QTypeRevision version() const { return m_version; }
42 bool isFile() const { return m_isFile; }
43 bool isDependency() const { return m_isDependency; }
44
45private:
46 QString m_prefix;
47 QString m_name;
48 QTypeRevision m_version;
49 bool m_isFile = false;
50 bool m_isDependency = false;
51
52 friend inline size_t qHash(const Import &key, size_t seed = 0) noexcept
53 {
54 return qHashMulti(seed, key.m_prefix, key.m_name, key.m_version,
55 key.m_isFile, key.m_isDependency);
56 }
57
58 friend inline bool operator==(const Import &a, const Import &b)
59 {
60 return a.m_prefix == b.m_prefix && a.m_name == b.m_name && a.m_version == b.m_version
61 && a.m_isFile == b.m_isFile && a.m_isDependency == b.m_isDependency;
62 }
63};
64}
65
69 TolerateFileSelectors = 0x4, // if we find a type "twice", check if one looks like it's from a file selector and use the other
70};
71Q_DECLARE_FLAGS(QQmlJSImporterFlags, QQmlJSImporterFlag)
72
73class QQmlJSImportVisitor;
74class QQmlJSLogger;
75class Q_QMLCOMPILER_EXPORT QQmlJSImporter
76{
77 // In the list of QML types we prefix unresolvable QML names with $anonymous$, and C++
78 // names with $internal$. This is to avoid clashes between them.
79 // In the list of C++ types we insert types that don't have a C++ name as their
80 // QML name prefixed with $anonymous$.
81 static inline constexpr QLatin1String anonPrefix = QLatin1String("$anonymous$");
82 static inline constexpr QLatin1String internalPrefix = QLatin1String("$internal$");
83 static inline constexpr QLatin1String modulePrefix = QLatin1String("$module$");
84
85public:
86 static inline constexpr QLatin1String s_inProcessMarker = QLatin1String("$InProcess$");
87
88 struct ImportedTypes {
89 ImportedTypes(QQmlJS::ContextualTypes &&types, QList<QQmlJS::DiagnosticMessage> &&warnings)
90 : m_types(std::move(types)), m_warnings(std::move(warnings))
91 {}
92
93 ImportedTypes(const ImportedTypes &) = default;
94 ImportedTypes(ImportedTypes &&) = default;
95 ImportedTypes &operator=(const ImportedTypes &) = default;
96 ImportedTypes &operator=(ImportedTypes &&) = default;
97 ~ImportedTypes() = default;
98
99 void clear()
100 {
101 m_types.clearTypes();
102 m_warnings.clear();
103 }
104
105 const QQmlJS::ContextualTypes &contextualTypes() const { return m_types; }
106 const QList<QQmlJS::DiagnosticMessage> &warnings() const { return m_warnings; };
107
108 void setCurrentFileSelector(const QString &selector)
109 {
110 m_types.setCurrentFileSelector(selector);
111 }
112
113 bool isEmpty() const { return m_types.types().isEmpty(); }
114
115 bool hasType(const QString &name) const { return m_types.hasType(name); }
116 QQmlJS::ImportedScope<QQmlJSScope::ConstPtr> type(const QString &name) const
117 {
118 return m_types.type(name);
119 }
120 QString name(const QQmlJSScope::ConstPtr &type) const { return m_types.name(type); }
121 void setType(const QString &name, const QQmlJS::ContextualType &type)
122 {
123 m_types.setType(name, type);
124 }
125 bool isNullType(const QString &name) const { return m_types.isNullType(name); }
126 const QHash<QString, QQmlJS::ContextualType> &types() const { return m_types.types(); }
127 const auto &names() const { return m_types.names(); }
128
129 void add(ImportedTypes &&other)
130 {
131 m_types.addTypes(std::move(other.m_types));
132 m_warnings.append(std::move(other.m_warnings));
133 }
134
135 void addWarnings(QList<QQmlJS::DiagnosticMessage> &&warnings)
136 {
137 m_warnings.append(std::move(warnings));
138 }
139
140 private:
141 QQmlJS::ContextualTypes m_types;
142 QList<QQmlJS::DiagnosticMessage> m_warnings;
143 };
144
145 QQmlJSImporter(const QStringList &importPaths, QQmlJSResourceFileMapper *mapper,
146 QQmlJSImporterFlags flags = QQmlJSImporterFlags{});
147
148 QQmlJSResourceFileMapper *resourceFileMapper() const { return m_mapper; }
149 void setResourceFileMapper(QQmlJSResourceFileMapper *mapper) { m_mapper = mapper; }
150
151 QQmlJSResourceFileMapper *metaDataMapper() const { return m_metaDataMapper; }
152 void setMetaDataMapper(QQmlJSResourceFileMapper *mapper) { m_metaDataMapper = mapper; }
153
154 ImportedTypes importHardCodedBuiltins();
155 QList<QQmlJS::DiagnosticMessage> importQmldirs(const QStringList &qmltypesFiles);
156
157 QQmlJSScope::Ptr importFile(const QString &file);
158 ImportedTypes importDirectory(const QString &directory, quint8 precedence,
159 const QString &prefix = QString());
160
161 // ### qmltc needs this. once re-written, we no longer need to expose this
162 QHash<QString, QQmlJSScope::Ptr> importedFiles() const { return m_importedFiles; }
163
164 ImportedTypes importModule(const QString &module, quint8 precedence,
165 const QString &prefix = QString(),
166 QTypeRevision version = QTypeRevision(),
167 QStringList *staticModuleList = nullptr);
168
169 ImportedTypes builtinInternalNames();
170
171 QList<QQmlJS::DiagnosticMessage> takeGlobalWarnings()
172 {
173 const auto result = std::move(m_globalWarnings);
174 m_globalWarnings.clear();
175 return result;
176 }
177
178 QStringList importPaths() const { return m_importPaths; }
179 void setImportPaths(const QStringList &importPaths);
180
181 void clearCache();
182
183 QQmlJSScope::ConstPtr jsGlobalObject();
184 QString pathOfModule(const QString &moduleName, QTypeRevision revision) const
185 {
186 const auto it = m_seenImports.constFind({ moduleName, revision });
187 return it != m_seenImports.constEnd() ? *it : QString();
188 }
189
190 struct ImportVisitorPrerequisites
191 {
192 ImportVisitorPrerequisites(QQmlJSScope::Ptr target, QQmlJSLogger *logger,
193 const QString &implicitImportDirectory = {},
194 const QStringList &qmldirFiles = {})
195 : m_target(target),
196 m_logger(logger),
197 m_implicitImportDirectory(implicitImportDirectory),
198 m_qmldirFiles(qmldirFiles)
199 {
200 Q_ASSERT(target && logger);
201 }
202
203 QQmlJSScope::Ptr m_target;
204 QQmlJSLogger *m_logger;
205 QString m_implicitImportDirectory;
206 QStringList m_qmldirFiles;
207 };
208 void runImportVisitor(QQmlJS::AST::Node *rootNode,
209 const ImportVisitorPrerequisites &prerequisites);
210
211 /*!
212 \internal
213 When a qml file gets lazily loaded, it will be lexed and parsed and finally be constructed
214 via an ImportVisitor. By default, this is done via the QQmlJSImportVisitor, but can also be done
215 via other import visitors like QmltcVisitor, which is used by qmltc to compile a QML file, or
216 QQmlDomAstCreatorWithQQmlJSScope, which is used to construct the Dom of lazily loaded QML files.
217 */
218 using ImportVisitor = std::function<void(QQmlJS::AST::Node *rootNode, QQmlJSImporter *self,
219 const ImportVisitorPrerequisites &prerequisites)>;
220
221 void setImportVisitor(ImportVisitor visitor) { m_importVisitor = visitor; }
222 void setFlags(const QQmlJSImporterFlags &flags) { m_flags = flags; }
223 QQmlJSImporterFlags flags() const { return m_flags; }
224
225private:
226 struct AvailableTypes
227 {
228 AvailableTypes(QQmlJS::ContextualTypes builtins)
229 : cppNames(std::move(builtins))
230 , qmlNames(QQmlJS::ContextualTypes::QML, {}, {}, cppNames.arrayType())
231 {
232 }
233
234 // C++ names used in qmltypes files for non-composite types
235 QQmlJS::ContextualTypes cppNames;
236
237 // Names the importing component sees, including any prefixes
238 QQmlJS::ContextualTypes qmlNames;
239
240 // Static modules included here
241 QStringList staticModules;
242
243 // Warnings produced when importing
244 QList<QQmlJS::DiagnosticMessage> warnings;
245
246 // Whether a system module has been imported
247 bool hasSystemModule = false;
248 // Whether QQmlJSImporter::importHelper() returned false on the first time it loaded the
249 // QML Module, so that further calls to importHelper() have the same return value.
250 bool wasFound = true;
251 };
252
253 struct Import {
254 enum Type : bool { Directory, Qmldir };
255
256 QString name;
257 bool isStaticModule = false;
258 bool isSystemModule = false;
259 Type type = Directory;
260
261 QList<QQmlJSExportedScope> objects;
262 QHash<QString, QQmlJSExportedScope> scripts;
263 QList<QQmlDirParser::Import> imports;
264 QList<QQmlDirParser::Import> dependencies;
265
266 // Warnings produced when importing
267 QList<QQmlJS::DiagnosticMessage> warnings;
268 };
269
270 AvailableTypes builtinImportHelper();
271 bool importHelper(const QString &module, AvailableTypes *types, quint8 precedence,
272 const QString &prefix = QString(), QTypeRevision version = QTypeRevision(),
273 bool isDependency = false, bool isFile = false);
274 void processImport(const QQmlJS::Import &importDescription, const Import &import,
275 quint8 precedence, AvailableTypes *types);
276 static void insertAliases(const QQmlJS::ContextualType &type,
277 QQmlJSImporter::AvailableTypes *types);
278 void insertExport(const QQmlJS::ContextualType &type, const QQmlJS::Export &valExport,
279 const QString &qmlName,
280 QHash<QString, QList<QQmlJSScope::Export>> *seenExports,
281 QQmlJSImporter::AvailableTypes *types) const;
282 QQmlJSScope::Export
283 resolveConflictingExports(const QQmlJS::Import &importDescription,
284 const QQmlJSExportedScope &val, quint8 precedence,
285 QHash<QString, QList<QQmlJSScope::Export>> *seenExports,
286 QQmlJSImporter::AvailableTypes *types);
287 enum SeenVersion { LowerVersion, SameVersion, HigherVersion };
288 void insertExportWithConflictingVersion(const QQmlJSExportedScope &val, quint8 precedence,
289 const QString &qmlName,
290 const QQmlJSScope::Export &valExport,
291 const QQmlJSScope::ConstPtr &scope,
292 QHash<QString, QList<QQmlJSScope::Export>> *seenExports,
293 QQmlJSImporter::AvailableTypes *types,
294 SeenVersion seenVersion) const;
295 SeenVersion computeSeenVersion(const QQmlJS::Import &importDescription,
296 const QList<QQmlJS::Export> &existingExports,
297 QTypeRevision valExportVersion) const;
298 void insertExports(const QQmlJS::Import &importDescription, const QQmlJSExportedScope &val,
299 const QString &cppName, quint8 precedence,
300 QHash<QString, QList<QQmlJSScope::Export>> *seenExports,
301 QQmlJSImporter::AvailableTypes *types);
302 void importDependencies(const Import &import, quint8 precedence, AvailableTypes *types,
303 const QString &prefix = QString(),
304 QTypeRevision version = QTypeRevision(), bool isDependency = false);
305 QQmlDirParser createQmldirParserForFile(const QString &filename, Import *import);
306 void readQmltypes(const QString &filename, Import *result);
307 Import readQmldir(const QString &dirname);
308 Import readDirectory(const QString &directory);
309
310 QQmlJSScope::Ptr localFile2QQmlJSScope(const QString &filePath);
311 static void setQualifiedNamesOn(const Import &import);
312
313 QStringList m_importPaths;
314
315 QHash<std::pair<QString, QTypeRevision>, QString> m_seenImports;
316 QHash<QQmlJS::Import, QSharedPointer<AvailableTypes>> m_cachedImportTypes;
317 QHash<QString, Import> m_seenQmldirFilesAndDirectories;
318
319 QHash<QString, QQmlJSScope::Ptr> m_importedFiles;
320 QList<QQmlJS::DiagnosticMessage> m_globalWarnings;
321 std::optional<AvailableTypes> m_builtins;
322
323 QQmlJSResourceFileMapper *m_mapper = nullptr;
324 QQmlJSResourceFileMapper *m_metaDataMapper = nullptr;
325 QQmlJSImporterFlags m_flags;
326 bool useOptionalImports() const { return m_flags.testFlag(UseOptionalImports); };
327 bool preferQmlFilesFromSourceFolder() const
328 {
329 return m_flags.testFlag(PreferQmlFilesFromSourceFolder);
330 };
331
332 ImportVisitor m_importVisitor;
333};
334
335QT_END_NAMESPACE
336
337#endif // QQMLJSIMPORTER_P_H
friend bool operator==(const Import &a, const Import &b)
QString prefix() const
bool isValid() const
QTypeRevision version() const
QString name() const
bool isDependency() const
Import()=default
bool isFile() const
friend size_t qHash(const Import &key, size_t seed=0) noexcept
Import(QString prefix, QString name, QTypeRevision version, bool isFile, bool isDependency)
\inmodule QtCore
Combined button and popup list for selecting options.
static QStringList aliases(const QQmlJSScope::ConstPtr &scope)
static const QLatin1String JsrootDotQmltypes
static bool isVersionAllowed(const QQmlJSScope::Export &exportEntry, const QQmlJS::Import &importDescription)
static bool isComposite(const QQmlJSScope::ConstPtr &scope)
static QString resolvePreferredPath(const QString &qmldirPath, const QString &prefer, QQmlJSResourceFileMapper *mapper)
static const QString prefixedName(const QString &prefix, const QString &name)
static QString ensureSlashQmldir(const QString &path)
static const QLatin1String SlashQmldir
static QString internalName(const QQmlJSScope::ConstPtr &scope)
static const QLatin1String PluginsDotQmltypes
QQmlJSImporterFlag
@ UseOptionalImports
@ PreferQmlFilesFromSourceFolder
@ TolerateFileSelectors