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