1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QQMLDOMEXTERNALITEMS_P_H
5#define QQMLDOMEXTERNALITEMS_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
18#include "qqmldomitem_p.h"
19#include "qqmldomelements_p.h"
20#include "qqmldommoduleindex_p.h"
21#include "qqmldomcomments_p.h"
22
23#include <QtQml/private/qqmljsast_p.h>
24#include <QtQml/private/qqmljsengine_p.h>
25#include <QtQml/private/qqmldirparser_p.h>
26#include <QtQmlCompiler/private/qqmljstyperesolver_p.h>
27#include <QtCore/QMetaType>
28
29#include <limits>
30#include <memory>
31
32Q_DECLARE_METATYPE(QQmlDirParser::Plugin)
33
34QT_BEGIN_NAMESPACE
35
36namespace QQmlJS {
37namespace Dom {
38
39/*!
40\internal
41\class QQmlJS::Dom::ExternalOwningItem
42
43\brief A OwningItem that refers to an external resource (file,...)
44
45Every owning item has a file or directory it refers to.
46
47
48*/
49class QMLDOM_EXPORT ExternalOwningItem: public OwningItem {
50public:
51 ExternalOwningItem(QString filePath, QDateTime lastDataUpdateAt, Path pathFromTop,
52 int derivedFrom = 0, QString code = QString());
53 ExternalOwningItem(const ExternalOwningItem &o) = default;
54 QString canonicalFilePath(DomItem &) const override;
55 QString canonicalFilePath() const;
56 Path canonicalPath(DomItem &) const override;
57 Path canonicalPath() const;
58 bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) override
59 {
60 bool cont = OwningItem::iterateDirectSubpaths(self, visitor);
61 cont = cont && self.dvValueLazyField(visitor, f: Fields::canonicalFilePath, valueF: [this]() {
62 return canonicalFilePath();
63 });
64 cont = cont
65 && self.dvValueLazyField(visitor, f: Fields::isValid, valueF: [this]() { return isValid(); });
66 if (!code().isNull())
67 cont = cont
68 && self.dvValueLazyField(visitor, f: Fields::code, valueF: [this]() { return code(); });
69 return cont;
70 }
71
72 bool iterateSubOwners(DomItem &self, function_ref<bool(DomItem &owner)> visitor) override
73 {
74 bool cont = OwningItem::iterateSubOwners(self, visitor);
75 cont = cont && self.field(name: Fields::components).visitKeys(visitor: [visitor](QString, DomItem &comps) {
76 return comps.visitIndexes(visitor: [visitor](DomItem &comp) {
77 return comp.field(name: Fields::objects).visitIndexes(visitor: [visitor](DomItem &qmlObj) {
78 if (const QmlObject *qmlObjPtr = qmlObj.as<QmlObject>())
79 return qmlObjPtr->iterateSubOwners(self&: qmlObj, visitor);
80 Q_ASSERT(false);
81 return true;
82 });
83 });
84 });
85 return cont;
86 }
87
88 bool isValid() const {
89 QMutexLocker l(mutex());
90 return m_isValid;
91 }
92 void setIsValid(bool val) {
93 QMutexLocker l(mutex());
94 m_isValid = val;
95 }
96 // null code means invalid
97 const QString &code() const { return m_code; }
98
99protected:
100 QString m_canonicalFilePath;
101 QString m_code;
102 Path m_path;
103 bool m_isValid = false;
104};
105
106class QMLDOM_EXPORT QmlDirectory final : public ExternalOwningItem
107{
108protected:
109 std::shared_ptr<OwningItem> doCopy(DomItem &) const override
110 {
111 return std::make_shared<QmlDirectory>(args: *this);
112 }
113
114public:
115 constexpr static DomType kindValue = DomType::QmlDirectory;
116 DomType kind() const override { return kindValue; }
117 QmlDirectory(QString filePath = QString(), QStringList dirList = QStringList(),
118 QDateTime lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(msecs: 0, timeZone: QTimeZone::UTC),
119 int derivedFrom = 0);
120 QmlDirectory(const QmlDirectory &o) = default;
121
122 std::shared_ptr<QmlDirectory> makeCopy(DomItem &self) const
123 {
124 return std::static_pointer_cast<QmlDirectory>(r: doCopy(self));
125 }
126
127 bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) override;
128
129 const QMultiMap<QString, Export> &exports() const & { return m_exports; }
130
131 const QMultiMap<QString, QString> &qmlFiles() const & { return m_qmlFiles; }
132
133 bool addQmlFilePath(QString relativePath);
134
135private:
136 QMultiMap<QString, Export> m_exports;
137 QMultiMap<QString, QString> m_qmlFiles;
138};
139
140class QMLDOM_EXPORT QmldirFile final : public ExternalOwningItem
141{
142 Q_DECLARE_TR_FUNCTIONS(QmldirFile)
143protected:
144 std::shared_ptr<OwningItem> doCopy(DomItem &) const override
145 {
146 auto copy = std::make_shared<QmldirFile>(args: *this);
147 return copy;
148 }
149
150public:
151 constexpr static DomType kindValue = DomType::QmldirFile;
152 DomType kind() const override { return kindValue; }
153
154 static ErrorGroups myParsingErrors();
155
156 QmldirFile(QString filePath = QString(), QString code = QString(),
157 QDateTime lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(msecs: 0, timeZone: QTimeZone::UTC),
158 int derivedFrom = 0)
159 : ExternalOwningItem(filePath, lastDataUpdateAt, Paths::qmldirFilePath(path: filePath),
160 derivedFrom, code)
161 {
162 }
163 QmldirFile(const QmldirFile &o) = default;
164
165 static std::shared_ptr<QmldirFile> fromPathAndCode(QString path, QString code);
166
167 std::shared_ptr<QmldirFile> makeCopy(DomItem &self) const
168 {
169 return std::static_pointer_cast<QmldirFile>(r: doCopy(self));
170 }
171
172 bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) override;
173
174 QmlUri uri() const { return m_uri; }
175
176 const QSet<int> &majorVersions() const & { return m_majorVersions; }
177
178 const QMultiMap<QString, Export> &exports() const & { return m_exports; }
179
180 const QList<Import> &imports() const & { return m_imports; }
181
182 const QList<Path> &qmltypesFilePaths() const & { return m_qmltypesFilePaths; }
183
184 QMap<QString, QString> qmlFiles() const;
185
186 bool designerSupported() const { return m_qmldir.designerSupported(); }
187
188 QStringList classNames() const { return m_qmldir.classNames(); }
189
190 QList<ModuleAutoExport> autoExports() const;
191 void setAutoExports(const QList<ModuleAutoExport> &autoExport);
192
193 void ensureInModuleIndex(DomItem &self, QString uri);
194
195private:
196 void parse();
197 void setFromQmldir();
198
199 QmlUri m_uri;
200 QSet<int> m_majorVersions;
201 QQmlDirParser m_qmldir;
202 QList<QQmlDirParser::Plugin> m_plugins;
203 QList<Import> m_imports;
204 QList<ModuleAutoExport> m_autoExports;
205 QMultiMap<QString, Export> m_exports;
206 QList<Path> m_qmltypesFilePaths;
207};
208
209class QMLDOM_EXPORT JsFile final : public ExternalOwningItem
210{
211protected:
212 std::shared_ptr<OwningItem> doCopy(DomItem &) const override
213 {
214 auto copy = std::make_shared<JsFile>(args: *this);
215 return copy;
216 }
217
218public:
219 constexpr static DomType kindValue = DomType::JsFile;
220 DomType kind() const override { return kindValue; }
221 JsFile(QString filePath = QString(),
222 QDateTime lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(msecs: 0, timeZone: QTimeZone::UTC),
223 Path pathFromTop = Path(), int derivedFrom = 0)
224 : ExternalOwningItem(filePath, lastDataUpdateAt, pathFromTop, derivedFrom)
225 {
226 }
227 JsFile(const JsFile &o) = default;
228
229 std::shared_ptr<JsFile> makeCopy(DomItem &self) const
230 {
231 return std::static_pointer_cast<JsFile>(r: doCopy(self));
232 }
233
234 std::shared_ptr<QQmlJS::Engine> engine() const { return m_engine; }
235 JsResource rootComponent() const { return m_rootComponent; }
236
237private:
238 std::shared_ptr<QQmlJS::Engine> m_engine;
239 JsResource m_rootComponent;
240};
241
242class QMLDOM_EXPORT QmlFile final : public ExternalOwningItem
243{
244protected:
245 std::shared_ptr<OwningItem> doCopy(DomItem &self) const override;
246
247public:
248 constexpr static DomType kindValue = DomType::QmlFile;
249 DomType kind() const override { return kindValue; }
250
251 QmlFile(const QmlFile &o);
252 QmlFile(QString filePath = QString(), QString code = QString(),
253 QDateTime lastDataUpdate = QDateTime::fromMSecsSinceEpoch(msecs: 0, timeZone: QTimeZone::UTC),
254 int derivedFrom = 0);
255 static ErrorGroups myParsingErrors();
256 bool iterateDirectSubpaths(DomItem &self, DirectVisitor)
257 override; // iterates the *direct* subpaths, returns false if a quick end was requested
258 DomItem field(DomItem &self, QStringView name) const override
259 {
260 return const_cast<QmlFile *>(this)->field(self, name);
261 }
262 DomItem field(DomItem &self, QStringView name);
263 std::shared_ptr<QmlFile> makeCopy(DomItem &self) const
264 {
265 return std::static_pointer_cast<QmlFile>(r: doCopy(self));
266 }
267 void addError(DomItem &self, ErrorMessage msg) override;
268
269 const QMultiMap<QString, QmlComponent> &components() const & { return m_components; }
270 void setComponents(const QMultiMap<QString, QmlComponent> &components)
271 {
272 m_components = components;
273 }
274 Path addComponent(const QmlComponent &component, AddOption option = AddOption::Overwrite,
275 QmlComponent **cPtr = nullptr)
276 {
277 QStringList nameEls = component.name().split(sep: QChar::fromLatin1(c: '.'));
278 QString key = nameEls.mid(pos: 1).join(sep: QChar::fromLatin1(c: '.'));
279 return insertUpdatableElementInMultiMap(mapPathFromOwner: Path::Field(s: Fields::components), mmap&: m_components, key,
280 value: component, option, valuePtr: cPtr);
281 }
282
283 void writeOut(DomItem &self, OutWriter &lw) const override;
284
285 AST::UiProgram *ast() const
286 {
287 return m_ast; // avoid making it public? would make moving away from it easier
288 }
289 const QList<Import> &imports() const & { return m_imports; }
290 void setImports(const QList<Import> &imports) { m_imports = imports; }
291 Path addImport(const Import &i)
292 {
293 index_type idx = index_type(m_imports.size());
294 m_imports.append(t: i);
295 if (i.uri.isModule()) {
296 m_importScope.addImport(p: (i.importId.isEmpty()
297 ? QStringList()
298 : i.importId.split(sep: QChar::fromLatin1(c: '.'))),
299 targetExports: i.importedPath());
300 } else {
301 QString path = i.uri.absoluteLocalPath(basePath: canonicalFilePath());
302 if (!path.isEmpty())
303 m_importScope.addImport(p: (i.importId.isEmpty()
304 ? QStringList()
305 : i.importId.split(sep: QChar::fromLatin1(c: '.'))),
306 targetExports: Paths::qmlDirPath(path));
307 }
308 return Path::Field(s: Fields::imports).index(i: idx);
309 }
310 std::shared_ptr<QQmlJS::Engine> engine() const { return m_engine; }
311 RegionComments &comments() { return m_comments; }
312 std::shared_ptr<AstComments> astComments() const { return m_astComments; }
313 void setAstComments(std::shared_ptr<AstComments> comm) { m_astComments = comm; }
314 FileLocations::Tree fileLocationsTree() const { return m_fileLocationsTree; }
315 void setFileLocationsTree(FileLocations::Tree v) { m_fileLocationsTree = v; }
316 const QList<Pragma> &pragmas() const & { return m_pragmas; }
317 void setPragmas(QList<Pragma> pragmas) { m_pragmas = pragmas; }
318 Path addPragma(const Pragma &pragma)
319 {
320 int idx = m_pragmas.size();
321 m_pragmas.append(t: pragma);
322 return Path::Field(s: Fields::pragmas).index(i: idx);
323 }
324 ImportScope &importScope() { return m_importScope; }
325 const ImportScope &importScope() const { return m_importScope; }
326
327 std::optional<std::shared_ptr<QQmlJSTypeResolver>> typeResolver() const
328 {
329 return m_typeResolver;
330 }
331 void setTypeResolver(const std::shared_ptr<QQmlJSTypeResolver> &typeResolver)
332 {
333 m_typeResolver = typeResolver;
334 }
335
336private:
337 friend class QQmlDomAstCreator;
338 std::shared_ptr<Engine> m_engine;
339 AST::UiProgram *m_ast; // avoid? would make moving away from it easier
340 std::shared_ptr<AstComments> m_astComments;
341 RegionComments m_comments;
342 FileLocations::Tree m_fileLocationsTree;
343 QMultiMap<QString, QmlComponent> m_components;
344 QList<Pragma> m_pragmas;
345 QList<Import> m_imports;
346 ImportScope m_importScope;
347 std::optional<std::shared_ptr<QQmlJSTypeResolver>> m_typeResolver;
348};
349
350class QMLDOM_EXPORT QmltypesFile final : public ExternalOwningItem
351{
352protected:
353 std::shared_ptr<OwningItem> doCopy(DomItem &) const override
354 {
355 auto res = std::make_shared<QmltypesFile>(args: *this);
356 return res;
357 }
358
359public:
360 constexpr static DomType kindValue = DomType::QmltypesFile;
361 DomType kind() const override { return kindValue; }
362
363 QmltypesFile(QString filePath = QString(), QString code = QString(),
364 QDateTime lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(msecs: 0, timeZone: QTimeZone::UTC),
365 int derivedFrom = 0)
366 : ExternalOwningItem(filePath, lastDataUpdateAt, Paths::qmltypesFilePath(path: filePath),
367 derivedFrom, code)
368 {
369 }
370
371 QmltypesFile(const QmltypesFile &o) = default;
372
373 void ensureInModuleIndex(DomItem &self);
374
375 bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override;
376 std::shared_ptr<QmltypesFile> makeCopy(DomItem &self) const
377 {
378 return std::static_pointer_cast<QmltypesFile>(r: doCopy(self));
379 }
380
381 void addImport(const Import i)
382 { // builder only: not threadsafe...
383 m_imports.append(t: i);
384 }
385 const QList<Import> &imports() const & { return m_imports; }
386 const QMultiMap<QString, QmltypesComponent> &components() const & { return m_components; }
387 void setComponents(QMultiMap<QString, QmltypesComponent> c) { m_components = std::move(c); }
388 Path addComponent(const QmltypesComponent &comp, AddOption option = AddOption::Overwrite,
389 QmltypesComponent **cPtr = nullptr)
390 {
391 for (const Export &e : comp.exports())
392 addExport(e);
393 return insertUpdatableElementInMultiMap(mapPathFromOwner: Path::Field(s: u"components"), mmap&: m_components,
394 key: comp.name(), value: comp, option, valuePtr: cPtr);
395 }
396 const QMultiMap<QString, Export> &exports() const & { return m_exports; }
397 void setExports(QMultiMap<QString, Export> e) { m_exports = e; }
398 Path addExport(const Export &e)
399 {
400 index_type i = m_exports.values(key: e.typeName).size();
401 m_exports.insert(key: e.typeName, value: e);
402 addUri(uri: e.uri, majorVersion: e.version.majorVersion);
403 return canonicalPath().field(name: Fields::exports).index(i);
404 }
405
406 const QMap<QString, QSet<int>> &uris() const & { return m_uris; }
407 void addUri(QString uri, int majorVersion)
408 {
409 QSet<int> &v = m_uris[uri];
410 if (!v.contains(value: majorVersion)) {
411 v.insert(value: majorVersion);
412 }
413 }
414
415private:
416 QList<Import> m_imports;
417 QMultiMap<QString, QmltypesComponent> m_components;
418 QMultiMap<QString, Export> m_exports;
419 QMap<QString, QSet<int>> m_uris;
420};
421
422class QMLDOM_EXPORT GlobalScope final : public ExternalOwningItem
423{
424protected:
425 std::shared_ptr<OwningItem> doCopy(DomItem &) const override;
426
427public:
428 constexpr static DomType kindValue = DomType::GlobalScope;
429 DomType kind() const override { return kindValue; }
430
431 GlobalScope(QString filePath = QString(),
432 QDateTime lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(msecs: 0, timeZone: QTimeZone::UTC),
433 int derivedFrom = 0)
434 : ExternalOwningItem(filePath, lastDataUpdateAt, Paths::globalScopePath(name: filePath),
435 derivedFrom)
436 {
437 setIsValid(true);
438 }
439
440 bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) override;
441 std::shared_ptr<GlobalScope> makeCopy(DomItem &self) const
442 {
443 return std::static_pointer_cast<GlobalScope>(r: doCopy(self));
444 }
445 QString name() const { return m_name; }
446 Language language() const { return m_language; }
447 GlobalComponent rootComponent() const { return m_rootComponent; }
448 void setName(QString name) { m_name = name; }
449 void setLanguage(Language language) { m_language = language; }
450 void setRootComponent(const GlobalComponent &ob)
451 {
452 m_rootComponent = ob;
453 m_rootComponent.updatePathFromOwner(newPath: Path::Field(s: Fields::rootComponent));
454 }
455
456private:
457 QString m_name;
458 Language m_language;
459 GlobalComponent m_rootComponent;
460};
461
462} // end namespace Dom
463} // end namespace QQmlJS
464QT_END_NAMESPACE
465#endif // QQMLDOMEXTERNALITEMS_P_H
466

source code of qtdeclarative/src/qmldom/qqmldomexternalitems_p.h