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 QList<QQmlJS::Import> &&moduleImports = {})
91 : m_types(std::move(types)),
92 m_warnings(std::move(warnings)),
93 m_moduleImports(std::move(moduleImports))
94 {}
95
96 ImportedTypes(const ImportedTypes &) = default;
97 ImportedTypes(ImportedTypes &&) = default;
98 ImportedTypes &operator=(const ImportedTypes &) = default;
99 ImportedTypes &operator=(ImportedTypes &&) = default;
100 ~ImportedTypes() = default;
101
102 void clear()
103 {
104 m_types.clearTypes();
105 m_warnings.clear();
106 }
107
108 const QQmlJS::ContextualTypes &contextualTypes() const { return m_types; }
109 const QList<QQmlJS::DiagnosticMessage> &warnings() const { return m_warnings; };
110 const QList<QQmlJS::Import> &moduleImports() const { return m_moduleImports; }
111
112 void setCurrentFileSelector(const QString &selector)
113 {
114 m_types.setCurrentFileSelector(selector);
115 }
116
117 bool isEmpty() const { return m_types.types().isEmpty(); }
118
119 bool hasType(const QString &name) const { return m_types.hasType(name); }
120 QQmlJS::ImportedScope<QQmlJSScope::ConstPtr> type(const QString &name) const
121 {
122 return m_types.type(name);
123 }
124 QString name(const QQmlJSScope::ConstPtr &type) const { return m_types.name(type); }
125 void setType(const QString &name, const QQmlJS::ContextualType &type)
126 {
127 m_types.setType(name, type);
128 }
129 bool isNullType(const QString &name) const { return m_types.isNullType(name); }
130 const QHash<QString, QQmlJS::ContextualType> &types() const { return m_types.types(); }
131 const auto &names() const { return m_types.names(); }
132
133 void add(ImportedTypes &&other)
134 {
135 m_types.addTypes(std::move(other.m_types));
136 m_warnings.append(std::move(other.m_warnings));
137 }
138
139 void addWarnings(QList<QQmlJS::DiagnosticMessage> &&warnings)
140 {
141 m_warnings.append(std::move(warnings));
142 }
143
144 private:
145 QQmlJS::ContextualTypes m_types;
146 QList<QQmlJS::DiagnosticMessage> m_warnings;
147
148 // The imports of modules, including the ones forwarded via qmldir "import" lines,
149 // but not the dependencies.
150 QList<QQmlJS::Import> m_moduleImports;
151 };
152
153 struct VersionedImport
154 {
155 QString module;
156 QString name;
157 QTypeRevision version;
158
159 friend bool operator==(const VersionedImport &a, const VersionedImport &b)
160 {
161 return a.module == b.module && a.name == b.name && a.version == b.version;
162 }
163
164 friend bool operator!=(const VersionedImport &a, const VersionedImport &b)
165 {
166 return !(a == b);
167 }
168 };
169
170 void registerVersionedImports(const ImportedTypes &imported);
171 QList<VersionedImport> versionedImports(const QString &filePath) const
172 {
173 return m_versionedImports.value(filePath);
174 }
175
176 QQmlJSImporter(const QStringList &importPaths, QQmlJSResourceFileMapper *mapper,
177 QQmlJSImporterFlags flags = QQmlJSImporterFlags{});
178
179 const QQmlJSResourceFileMapper *resourceFileMapper() const { return m_mapper; }
180 void setResourceFileMapper(const QQmlJSResourceFileMapper *mapper) { m_mapper = mapper; }
181
182 QQmlJSResourceFileMapper *metaDataMapper() const { return m_metaDataMapper; }
183 void setMetaDataMapper(QQmlJSResourceFileMapper *mapper) { m_metaDataMapper = mapper; }
184
185 ImportedTypes importHardCodedBuiltins();
186 QList<QQmlJS::DiagnosticMessage> importQmldirs(const QStringList &qmltypesFiles);
187
188 QQmlJSScope::Ptr importFile(const QString &file);
189 ImportedTypes importDirectory(const QString &directory, quint8 precedence,
190 const QString &prefix = QString());
191
192 // ### qmltc needs this. once re-written, we no longer need to expose this
193 QHash<QString, QQmlJSScope::Ptr> importedFiles() const { return m_importedFiles; }
194
195 ImportedTypes importModule(const QString &module, quint8 precedence,
196 const QString &prefix = QString(),
197 QTypeRevision version = QTypeRevision(),
198 QStringList *staticModuleList = nullptr);
199
200 ImportedTypes builtinInternalNames();
201
202 QList<QQmlJS::DiagnosticMessage> takeGlobalWarnings()
203 {
204 const auto result = std::move(m_globalWarnings);
205 m_globalWarnings.clear();
206 return result;
207 }
208
209 QStringList importPaths() const { return m_importPaths; }
210 void setImportPaths(const QStringList &importPaths);
211
212 void clearCache();
213
214 QQmlJSScope::ConstPtr jsGlobalObject();
215 QString pathOfModule(const QString &moduleName, QTypeRevision revision) const
216 {
217 const auto it = m_seenImports.constFind({ moduleName, revision });
218 return it != m_seenImports.constEnd() ? *it : QString();
219 }
220
221 struct ImportVisitorPrerequisites
222 {
223 ImportVisitorPrerequisites(QQmlJSScope::Ptr target, QQmlJSLogger *logger,
224 const QString &implicitImportDirectory = {},
225 const QStringList &qmldirFiles = {})
226 : m_target(target),
227 m_logger(logger),
228 m_implicitImportDirectory(implicitImportDirectory),
229 m_qmldirFiles(qmldirFiles)
230 {
231 Q_ASSERT(target && logger);
232 }
233
234 QQmlJSScope::Ptr m_target;
235 QQmlJSLogger *m_logger;
236 QString m_implicitImportDirectory;
237 QStringList m_qmldirFiles;
238 };
239 void runImportVisitor(QQmlJS::AST::Node *rootNode,
240 const ImportVisitorPrerequisites &prerequisites);
241
242 /*!
243 \internal
244 When a qml file gets lazily loaded, it will be lexed and parsed and finally be constructed
245 via an ImportVisitor. By default, this is done via the QQmlJSImportVisitor, but can also be done
246 via other import visitors like QmltcVisitor, which is used by qmltc to compile a QML file, or
247 QQmlDomAstCreatorWithQQmlJSScope, which is used to construct the Dom of lazily loaded QML files.
248 */
249 using ImportVisitor = std::function<void(QQmlJS::AST::Node *rootNode, QQmlJSImporter *self,
250 const ImportVisitorPrerequisites &prerequisites)>;
251
252 void setImportVisitor(ImportVisitor visitor) { m_importVisitor = visitor; }
253 void setFlags(const QQmlJSImporterFlags &flags) { m_flags = flags; }
254 QQmlJSImporterFlags flags() const { return m_flags; }
255
256private:
257 struct AvailableTypes
258 {
259 AvailableTypes(QQmlJS::ContextualTypes builtins)
260 : cppNames(std::move(builtins))
261 , qmlNames(QQmlJS::ContextualTypes::QML, {}, {}, cppNames.arrayType())
262 {
263 }
264
265 // C++ names used in qmltypes files for non-composite types
266 QQmlJS::ContextualTypes cppNames;
267
268 // Names the importing component sees, including any prefixes
269 QQmlJS::ContextualTypes qmlNames;
270
271 // Static modules included here
272 QStringList staticModules;
273
274 // Warnings produced when importing
275 QList<QQmlJS::DiagnosticMessage> warnings;
276
277 // The imports of modules, including the ones forwarded via qmldir "import" lines,
278 // but not the dependencies.
279 QList<QQmlJS::Import> moduleImports;
280
281 // Whether a system module has been imported
282 bool hasSystemModule = false;
283 // Whether QQmlJSImporter::importHelper() returned false on the first time it loaded the
284 // QML Module, so that further calls to importHelper() have the same return value.
285 bool wasFound = true;
286 };
287
288 struct Import {
289 enum Type : bool { Directory, Qmldir };
290
291 QString name;
292 bool isStaticModule = false;
293 bool isSystemModule = false;
294 Type type = Directory;
295
296 QList<QQmlJSExportedScope> objects;
297 QHash<QString, QQmlJSExportedScope> scripts;
298 QList<QQmlDirParser::Import> imports;
299 QList<QQmlDirParser::Import> dependencies;
300
301 // Warnings produced when importing
302 QList<QQmlJS::DiagnosticMessage> warnings;
303 };
304
305 AvailableTypes builtinImportHelper();
306 bool importHelper(const QString &module, AvailableTypes *types, quint8 precedence,
307 const QString &prefix = QString(), QTypeRevision version = QTypeRevision(),
308 bool isDependency = false, bool isFile = false);
309 void processImport(const QQmlJS::Import &importDescription, const Import &import,
310 quint8 precedence, AvailableTypes *types);
311 static void insertAliases(const QQmlJS::ContextualType &type,
312 QQmlJSImporter::AvailableTypes *types);
313 void insertExport(const QQmlJS::ContextualType &type, const QQmlJS::Export &valExport,
314 const QString &qmlName,
315 QHash<QString, QList<QQmlJSScope::Export>> *seenExports,
316 QQmlJSImporter::AvailableTypes *types) const;
317 QQmlJSScope::Export
318 resolveConflictingExports(const QQmlJS::Import &importDescription,
319 const QQmlJSExportedScope &val, quint8 precedence,
320 QHash<QString, QList<QQmlJSScope::Export>> *seenExports,
321 QQmlJSImporter::AvailableTypes *types);
322 enum SeenVersion { LowerVersion, SameVersion, HigherVersion };
323 void insertExportWithConflictingVersion(const QQmlJSExportedScope &val, quint8 precedence,
324 const QString &qmlName,
325 const QQmlJSScope::Export &valExport,
326 const QQmlJSScope::ConstPtr &scope,
327 QHash<QString, QList<QQmlJSScope::Export>> *seenExports,
328 QQmlJSImporter::AvailableTypes *types,
329 SeenVersion seenVersion) const;
330 SeenVersion computeSeenVersion(const QQmlJS::Import &importDescription,
331 const QList<QQmlJS::Export> &existingExports,
332 QTypeRevision valExportVersion) const;
333 void insertExports(const QQmlJS::Import &importDescription, const QQmlJSExportedScope &val,
334 const QString &cppName, quint8 precedence,
335 QHash<QString, QList<QQmlJSScope::Export>> *seenExports,
336 QQmlJSImporter::AvailableTypes *types);
337 void importDependencies(const Import &import, quint8 precedence, AvailableTypes *types,
338 const QString &prefix = QString(),
339 QTypeRevision version = QTypeRevision(), bool isDependency = false);
340 QQmlDirParser createQmldirParserForFile(const QString &filename, Import *import);
341 void readQmltypes(const QString &filename, Import *result);
342 Import readQmldir(const QString &dirname);
343 Import readDirectory(const QString &directory);
344
345 QQmlJSScope::Ptr localFile2QQmlJSScope(const QString &filePath);
346 static void setQualifiedNamesOn(const Import &import);
347
348 QStringList m_importPaths;
349
350 QHash<std::pair<QString, QTypeRevision>, QString> m_seenImports;
351 QHash<QQmlJS::Import, QSharedPointer<AvailableTypes>> m_cachedImportTypes;
352 QHash<QString, Import> m_seenQmldirFilesAndDirectories;
353
354 QHash<QString, QQmlJSScope::Ptr> m_importedFiles;
355
356 // The imports through which documents see a type, by file path of the type
357 QHash<QString, QList<VersionedImport>> m_versionedImports;
358 QList<QQmlJS::DiagnosticMessage> m_globalWarnings;
359 std::optional<AvailableTypes> m_builtins;
360
361 const QQmlJSResourceFileMapper *m_mapper = nullptr;
362 QQmlJSResourceFileMapper *m_metaDataMapper = nullptr;
363 QQmlJSImporterFlags m_flags;
364 bool useOptionalImports() const { return m_flags.testFlag(UseOptionalImports); };
365 bool preferQmlFilesFromSourceFolder() const
366 {
367 return m_flags.testFlag(PreferQmlFilesFromSourceFolder);
368 };
369
370 ImportVisitor m_importVisitor;
371};
372
373QT_END_NAMESPACE
374
375#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 QString filePath(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 const QString prefixedName(const QString &prefix, const QString &name)
static QString ensureSlashQmldir(const QString &path)
static QString resolvePreferredPath(const QString &qmldirPath, const QString &prefer, const QQmlJSResourceFileMapper *mapper)
static const QLatin1String SlashQmldir
static QString internalName(const QQmlJSScope::ConstPtr &scope)
static QList< QQmlJS::Export > createExports(const QString &name)
static QString moduleName(const QQmlJSScope::ConstPtr &scope)
static const QLatin1String PluginsDotQmltypes
QQmlJSImporterFlag
@ UseOptionalImports
@ PreferQmlFilesFromSourceFolder
@ TolerateFileSelectors