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