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

source code of qtdeclarative/src/qmlcompiler/qqmljsimporter_p.h