1// Copyright (C) 2021 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 QQMLDOMELEMENTS_P_H
5#define QQMLDOMELEMENTS_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 "qqmldomconstants_p.h"
20#include "qqmldomcomments_p.h"
21#include "qqmldomlinewriter_p.h"
22
23#include <QtQml/private/qqmljsast_p.h>
24#include <QtQml/private/qqmljsengine_p.h>
25
26#include <QtCore/QCborValue>
27#include <QtCore/QCborMap>
28#include <QtCore/QMutexLocker>
29#include <QtCore/QPair>
30
31#include <memory>
32#include <private/qqmljsscope_p.h>
33
34#include <functional>
35#include <limits>
36
37QT_BEGIN_NAMESPACE
38
39namespace QQmlJS {
40namespace Dom {
41
42// namespace for utility methods building specific paths
43// using a namespace one can reopen it and add more methods in other places
44namespace Paths {
45Path moduleIndexPath(QString uri, int majorVersion, ErrorHandler errorHandler = nullptr);
46Path moduleScopePath(QString uri, Version version, ErrorHandler errorHandler = nullptr);
47Path moduleScopePath(QString uri, QString version, ErrorHandler errorHandler = nullptr);
48inline Path moduleScopePath(QString uri, ErrorHandler errorHandler = nullptr)
49{
50 return moduleScopePath(uri, version: QString(), errorHandler);
51}
52inline Path qmlDirInfoPath(QString path)
53{
54 return Path::Root(r: PathRoot::Top).field(name: Fields::qmldirWithPath).key(name: path);
55}
56inline Path qmlDirPath(QString path)
57{
58 return qmlDirInfoPath(path).field(name: Fields::currentItem);
59}
60inline Path qmldirFileInfoPath(QString path)
61{
62 return Path::Root(r: PathRoot::Top).field(name: Fields::qmldirFileWithPath).key(name: path);
63}
64inline Path qmldirFilePath(QString path)
65{
66 return qmldirFileInfoPath(path).field(name: Fields::currentItem);
67}
68inline Path qmlFileInfoPath(QString canonicalFilePath)
69{
70 return Path::Root(r: PathRoot::Top).field(name: Fields::qmlFileWithPath).key(name: canonicalFilePath);
71}
72inline Path qmlFilePath(QString canonicalFilePath)
73{
74 return qmlFileInfoPath(canonicalFilePath).field(name: Fields::currentItem);
75}
76inline Path qmlFileObjectPath(QString canonicalFilePath)
77{
78 return qmlFilePath(canonicalFilePath)
79 .field(name: Fields::components)
80 .key(name: QString())
81 .index(i: 0)
82 .field(name: Fields::objects)
83 .index(i: 0);
84}
85inline Path qmltypesFileInfoPath(QString path)
86{
87 return Path::Root(r: PathRoot::Top).field(name: Fields::qmltypesFileWithPath).key(name: path);
88}
89inline Path qmltypesFilePath(QString path)
90{
91 return qmltypesFileInfoPath(path).field(name: Fields::currentItem);
92}
93inline Path jsFileInfoPath(QString path)
94{
95 return Path::Root(r: PathRoot::Top).field(name: Fields::jsFileWithPath).key(name: path);
96}
97inline Path jsFilePath(QString path)
98{
99 return jsFileInfoPath(path).field(name: Fields::currentItem);
100}
101inline Path qmlDirectoryInfoPath(QString path)
102{
103 return Path::Root(r: PathRoot::Top).field(name: Fields::qmlDirectoryWithPath).key(name: path);
104}
105inline Path qmlDirectoryPath(QString path)
106{
107 return qmlDirectoryInfoPath(path).field(name: Fields::currentItem);
108}
109inline Path globalScopeInfoPath(QString name)
110{
111 return Path::Root(r: PathRoot::Top).field(name: Fields::globalScopeWithName).key(name);
112}
113inline Path globalScopePath(QString name)
114{
115 return globalScopeInfoPath(name).field(name: Fields::currentItem);
116}
117inline Path lookupCppTypePath(QString name)
118{
119 return Path::Current(c: PathCurrent::Lookup).field(name: Fields::cppType).key(name);
120}
121inline Path lookupPropertyPath(QString name)
122{
123 return Path::Current(c: PathCurrent::Lookup).field(name: Fields::propertyDef).key(name);
124}
125inline Path lookupSymbolPath(QString name)
126{
127 return Path::Current(c: PathCurrent::Lookup).field(name: Fields::symbol).key(name);
128}
129inline Path lookupTypePath(QString name)
130{
131 return Path::Current(c: PathCurrent::Lookup).field(name: Fields::type).key(name);
132}
133inline Path loadInfoPath(Path el)
134{
135 return Path::Root(r: PathRoot::Env).field(name: Fields::loadInfo).key(name: el.toString());
136}
137} // end namespace Paths
138
139class QMLDOM_EXPORT CommentableDomElement : public DomElement
140{
141public:
142 CommentableDomElement(Path pathFromOwner = Path()) : DomElement(pathFromOwner) { }
143 CommentableDomElement(const CommentableDomElement &o) : DomElement(o), m_comments(o.m_comments)
144 {
145 }
146 CommentableDomElement &operator=(const CommentableDomElement &o) = default;
147 bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override;
148 RegionComments &comments() { return m_comments; }
149 const RegionComments &comments() const { return m_comments; }
150
151private:
152 RegionComments m_comments;
153};
154
155class QMLDOM_EXPORT Version
156{
157public:
158 constexpr static DomType kindValue = DomType::Version;
159 constexpr static qint32 Undefined = -1;
160 constexpr static qint32 Latest = -2;
161
162 Version(qint32 majorVersion = Undefined, qint32 minorVersion = Undefined);
163 static Version fromString(QStringView v);
164
165 bool iterateDirectSubpaths(DomItem &self, DirectVisitor);
166
167 bool isLatest() const;
168 bool isValid() const;
169 QString stringValue() const;
170 QString majorString() const
171 {
172 if (majorVersion >= 0 || majorVersion == Undefined)
173 return QString::number(majorVersion);
174 return QString();
175 }
176 QString majorSymbolicString() const
177 {
178 if (majorVersion == Version::Latest)
179 return QLatin1String("Latest");
180 if (majorVersion >= 0 || majorVersion == Undefined)
181 return QString::number(majorVersion);
182 return QString();
183 }
184 QString minorString() const
185 {
186 if (minorVersion >= 0 || minorVersion == Undefined)
187 return QString::number(minorVersion);
188 return QString();
189 }
190 int compare(const Version &o) const
191 {
192 int c = majorVersion - o.majorVersion;
193 if (c != 0)
194 return c;
195 return minorVersion - o.minorVersion;
196 }
197
198 qint32 majorVersion;
199 qint32 minorVersion;
200};
201inline bool operator==(const Version &v1, const Version &v2)
202{
203 return v1.compare(o: v2) == 0;
204}
205inline bool operator!=(const Version &v1, const Version &v2)
206{
207 return v1.compare(o: v2) != 0;
208}
209inline bool operator<(const Version &v1, const Version &v2)
210{
211 return v1.compare(o: v2) < 0;
212}
213inline bool operator<=(const Version &v1, const Version &v2)
214{
215 return v1.compare(o: v2) <= 0;
216}
217inline bool operator>(const Version &v1, const Version &v2)
218{
219 return v1.compare(o: v2) > 0;
220}
221inline bool operator>=(const Version &v1, const Version &v2)
222{
223 return v1.compare(o: v2) >= 0;
224}
225
226class QMLDOM_EXPORT QmlUri
227{
228public:
229 enum class Kind { Invalid, ModuleUri, DirectoryUrl, RelativePath, AbsolutePath };
230 QmlUri() = default;
231 static QmlUri fromString(const QString &importStr);
232 static QmlUri fromUriString(const QString &importStr);
233 static QmlUri fromDirectoryString(const QString &importStr);
234 bool isValid() const;
235 bool isDirectory() const;
236 bool isModule() const;
237 QString moduleUri() const;
238 QString localPath() const;
239 QString absoluteLocalPath(const QString &basePath = QString()) const;
240 QUrl directoryUrl() const;
241 QString directoryString() const;
242 QString toString() const;
243 Kind kind() const;
244
245 friend bool operator==(const QmlUri &i1, const QmlUri &i2)
246 {
247 return i1.m_kind == i2.m_kind && i1.m_value == i2.m_value;
248 }
249 friend bool operator!=(const QmlUri &i1, const QmlUri &i2) { return !(i1 == i2); }
250
251private:
252 QmlUri(const QUrl &url) : m_kind(Kind::DirectoryUrl), m_value(url) { }
253 QmlUri(Kind kind, const QString &value) : m_kind(kind), m_value(value) { }
254 Kind m_kind = Kind::Invalid;
255 std::variant<QString, QUrl> m_value;
256};
257
258class QMLDOM_EXPORT Import
259{
260 Q_DECLARE_TR_FUNCTIONS(Import)
261public:
262 constexpr static DomType kindValue = DomType::Import;
263
264 static Import fromUriString(QString importStr, Version v = Version(),
265 QString importId = QString(), ErrorHandler handler = nullptr);
266 static Import fromFileString(QString importStr, QString importId = QString(),
267 ErrorHandler handler = nullptr);
268
269 Import(QmlUri uri = QmlUri(), Version version = Version(), QString importId = QString())
270 : uri(uri), version(version), importId(importId)
271 {
272 }
273
274 bool iterateDirectSubpaths(DomItem &self, DirectVisitor);
275 Path importedPath() const
276 {
277 if (uri.isDirectory()) {
278 QString path = uri.absoluteLocalPath();
279 if (!path.isEmpty()) {
280 return Paths::qmlDirPath(path);
281 } else {
282 Q_ASSERT_X(false, "Import", "url imports not supported");
283 return Paths::qmldirFilePath(path: uri.directoryString());
284 }
285 } else {
286 return Paths::moduleScopePath(uri: uri.moduleUri(), version);
287 }
288 }
289 Import baseImport() const { return Import { uri, version }; }
290
291 friend bool operator==(const Import &i1, const Import &i2)
292 {
293 return i1.uri == i2.uri && i1.version == i2.version && i1.importId == i2.importId
294 && i1.comments == i2.comments && i1.implicit == i2.implicit;
295 }
296 friend bool operator!=(const Import &i1, const Import &i2) { return !(i1 == i2); }
297
298 void writeOut(DomItem &self, OutWriter &ow) const;
299
300 static QRegularExpression importRe();
301
302 QmlUri uri;
303 Version version;
304 QString importId;
305 RegionComments comments;
306 bool implicit = false;
307};
308
309class QMLDOM_EXPORT ModuleAutoExport
310{
311public:
312 constexpr static DomType kindValue = DomType::ModuleAutoExport;
313
314 bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
315 {
316 bool cont = true;
317 cont = cont && self.dvWrapField(visitor, f: Fields::import, obj&: import);
318 cont = cont && self.dvValueField(visitor, f: Fields::inheritVersion, value: inheritVersion);
319 return cont;
320 }
321
322 friend bool operator==(const ModuleAutoExport &i1, const ModuleAutoExport &i2)
323 {
324 return i1.import == i2.import && i1.inheritVersion == i2.inheritVersion;
325 }
326 friend bool operator!=(const ModuleAutoExport &i1, const ModuleAutoExport &i2)
327 {
328 return !(i1 == i2);
329 }
330
331 Import import;
332 bool inheritVersion = false;
333};
334
335class QMLDOM_EXPORT Pragma
336{
337public:
338 constexpr static DomType kindValue = DomType::Pragma;
339
340 Pragma(QString pragmaName = QString(), const QStringList &pragmaValues = {})
341 : name(pragmaName), values{ pragmaValues }
342 {
343 }
344
345 bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
346 {
347 bool cont = self.dvValueField(visitor, f: Fields::name, value: name);
348 cont = cont && self.dvValueField(visitor, f: Fields::values, value: values);
349 cont = cont && self.dvWrapField(visitor, f: Fields::comments, obj&: comments);
350 return cont;
351 }
352
353 void writeOut(DomItem &self, OutWriter &ow) const;
354
355 QString name;
356 QStringList values;
357 RegionComments comments;
358};
359
360class QMLDOM_EXPORT Id
361{
362public:
363 constexpr static DomType kindValue = DomType::Id;
364
365 Id(QString idName = QString(), Path referredObject = Path());
366
367 bool iterateDirectSubpaths(DomItem &self, DirectVisitor);
368 void updatePathFromOwner(Path pathFromOwner);
369 Path addAnnotation(Path selfPathFromOwner, const QmlObject &ann, QmlObject **aPtr = nullptr);
370
371 QString name;
372 Path referredObjectPath;
373 RegionComments comments;
374 QList<QmlObject> annotations;
375 std::shared_ptr<ScriptExpression> value;
376};
377
378// TODO: rename? it may contain statements and stuff, not only expressions
379class QMLDOM_EXPORT ScriptExpression final : public OwningItem
380{
381 Q_GADGET
382 Q_DECLARE_TR_FUNCTIONS(ScriptExpression)
383public:
384 enum class ExpressionType {
385 BindingExpression,
386 FunctionBody,
387 ArgInitializer,
388 ArgumentStructure,
389 ReturnType
390 };
391 Q_ENUM(ExpressionType);
392 constexpr static DomType kindValue = DomType::ScriptExpression;
393 DomType kind() const override { return kindValue; }
394
395 explicit ScriptExpression(QStringView code, std::shared_ptr<QQmlJS::Engine> engine,
396 AST::Node *ast, std::shared_ptr<AstComments> comments,
397 ExpressionType expressionType,
398 SourceLocation localOffset = SourceLocation(), int derivedFrom = 0,
399 QStringView preCode = QStringView(),
400 QStringView postCode = QStringView());
401
402 ScriptExpression()
403 : ScriptExpression(QStringView(), std::shared_ptr<QQmlJS::Engine>(), nullptr,
404 std::shared_ptr<AstComments>(), ExpressionType::BindingExpression,
405 SourceLocation(), 0)
406 {
407 }
408
409 explicit ScriptExpression(QString code, ExpressionType expressionType, int derivedFrom = 0,
410 QString preCode = QString(), QString postCode = QString())
411 : OwningItem(derivedFrom), m_expressionType(expressionType)
412 {
413 setCode(code, preCode, postCode);
414 }
415
416 ScriptExpression(const ScriptExpression &e);
417
418 std::shared_ptr<ScriptExpression> makeCopy(DomItem &self) const
419 {
420 return std::static_pointer_cast<ScriptExpression>(r: doCopy(self));
421 }
422
423 std::shared_ptr<ScriptExpression> copyWithUpdatedCode(DomItem &self, QString code) const;
424
425 bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) override;
426
427 Path canonicalPath(DomItem &self) const override { return self.m_ownerPath; }
428 // parsed and created if not available
429 AST::Node *ast() const { return m_ast; }
430 // dump of the ast (without locations)
431 void astDumper(Sink s, AstDumperOptions options) const;
432 QString astRelocatableDump() const;
433
434 // definedSymbols name, value, from
435 // usedSymbols name, locations
436 QStringView code() const
437 {
438 QMutexLocker l(mutex());
439 return m_code;
440 }
441
442 ExpressionType expressionType() const
443 {
444 QMutexLocker l(mutex());
445 return m_expressionType;
446 }
447
448 bool isNull() const
449 {
450 QMutexLocker l(mutex());
451 return m_code.isNull();
452 }
453 std::shared_ptr<QQmlJS::Engine> engine() const
454 {
455 QMutexLocker l(mutex());
456 return m_engine;
457 }
458 std::shared_ptr<AstComments> astComments() const { return m_astComments; }
459 void writeOut(DomItem &self, OutWriter &lw) const override;
460 SourceLocation globalLocation(DomItem &self) const;
461 SourceLocation localOffset() const { return m_localOffset; }
462 QStringView preCode() const { return m_preCode; }
463 QStringView postCode() const { return m_postCode; }
464 void setScriptElement(const ScriptElementVariant &p);
465 ScriptElementVariant scriptElement() { return m_element; }
466
467protected:
468 std::shared_ptr<OwningItem> doCopy(DomItem &) const override
469 {
470 return std::make_shared<ScriptExpression>(args: *this);
471 }
472
473 std::function<SourceLocation(SourceLocation)> locationToGlobalF(DomItem &self) const
474 {
475 SourceLocation loc = globalLocation(self);
476 return [loc, this](SourceLocation x) {
477 return SourceLocation(x.offset - m_localOffset.offset + loc.offset, x.length,
478 x.startLine - m_localOffset.startLine + loc.startLine,
479 ((x.startLine == m_localOffset.startLine) ? x.startColumn
480 - m_localOffset.startColumn + loc.startColumn
481 : x.startColumn));
482 };
483 }
484
485 SourceLocation locationToLocal(SourceLocation x) const
486 {
487 return SourceLocation(
488 x.offset - m_localOffset.offset, x.length, x.startLine - m_localOffset.startLine,
489 ((x.startLine == m_localOffset.startLine)
490 ? x.startColumn - m_localOffset.startColumn
491 : x.startColumn)); // are line and column 1 based? then we should + 1
492 }
493
494 std::function<SourceLocation(SourceLocation)> locationToLocalF(DomItem &) const
495 {
496 return [this](SourceLocation x) { return locationToLocal(x); };
497 }
498
499private:
500 void setCode(QString code, QString preCode, QString postCode);
501 ExpressionType m_expressionType;
502 QString m_codeStr;
503 QStringView m_code;
504 QStringView m_preCode;
505 QStringView m_postCode;
506 mutable std::shared_ptr<QQmlJS::Engine> m_engine;
507 mutable AST::Node *m_ast;
508 std::shared_ptr<AstComments> m_astComments;
509 SourceLocation m_localOffset;
510 ScriptElementVariant m_element;
511};
512
513class BindingValue;
514
515class QMLDOM_EXPORT Binding
516{
517public:
518 constexpr static DomType kindValue = DomType::Binding;
519
520 Binding(QString m_name = QString(),
521 std::unique_ptr<BindingValue> value = std::unique_ptr<BindingValue>(),
522 BindingType bindingType = BindingType::Normal);
523 Binding(QString m_name, std::shared_ptr<ScriptExpression> value,
524 BindingType bindingType = BindingType::Normal);
525 Binding(QString m_name, QString scriptCode, BindingType bindingType = BindingType::Normal);
526 Binding(QString m_name, QmlObject value, BindingType bindingType = BindingType::Normal);
527 Binding(QString m_name, QList<QmlObject> value, BindingType bindingType = BindingType::Normal);
528 Binding(const Binding &o);
529 Binding(Binding &&o) = default;
530 ~Binding();
531 Binding &operator=(const Binding &);
532 Binding &operator=(Binding &&) = default;
533
534 bool iterateDirectSubpaths(DomItem &self, DirectVisitor);
535 DomItem valueItem(DomItem &self) const; // ### REVISIT: consider replacing return value with variant
536 BindingValueKind valueKind() const;
537 QString name() const { return m_name; }
538 BindingType bindingType() const { return m_bindingType; }
539 QmlObject const *objectValue() const;
540 QList<QmlObject> const *arrayValue() const;
541 std::shared_ptr<ScriptExpression> scriptExpressionValue() const;
542 QmlObject *objectValue();
543 QList<QmlObject> *arrayValue();
544 std::shared_ptr<ScriptExpression> scriptExpressionValue();
545 QList<QmlObject> annotations() const { return m_annotations; }
546 void setAnnotations(QList<QmlObject> annotations) { m_annotations = annotations; }
547 void setValue(std::unique_ptr<BindingValue> &&value) { m_value = std::move(value); }
548 Path addAnnotation(Path selfPathFromOwner, const QmlObject &a, QmlObject **aPtr = nullptr);
549 const RegionComments &comments() const { return m_comments; }
550 RegionComments &comments() { return m_comments; }
551 void updatePathFromOwner(Path newPath);
552 void writeOut(DomItem &self, OutWriter &lw) const;
553 void writeOutValue(DomItem &self, OutWriter &lw) const;
554 bool isSignalHandler() const
555 {
556 QString baseName = m_name.split(sep: QLatin1Char('.')).last();
557 if (baseName.startsWith(s: u"on") && baseName.size() > 2 && baseName.at(i: 2).isUpper())
558 return true;
559 return false;
560 }
561 static QString preCodeForName(QStringView n)
562 {
563 return QStringLiteral(u"QtObject{\n %1: ").arg(a: n.split(sep: u'.').last());
564 }
565 static QString postCodeForName(QStringView) { return QStringLiteral(u"\n}\n"); }
566 QString preCode() const { return preCodeForName(n: m_name); }
567 QString postCode() const { return postCodeForName(m_name); }
568
569private:
570 friend class QQmlDomAstCreator;
571 BindingType m_bindingType;
572 QString m_name;
573 std::unique_ptr<BindingValue> m_value;
574 QList<QmlObject> m_annotations;
575 RegionComments m_comments;
576};
577
578class QMLDOM_EXPORT AttributeInfo
579{
580public:
581 enum Access { Private, Protected, Public };
582
583 bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor);
584
585 Path addAnnotation(Path selfPathFromOwner, const QmlObject &annotation,
586 QmlObject **aPtr = nullptr);
587 void updatePathFromOwner(Path newPath);
588
589 QString name;
590 Access access = Access::Public;
591 QString typeName;
592 bool isReadonly = false;
593 bool isList = false;
594 QList<QmlObject> annotations;
595 RegionComments comments;
596};
597
598struct QMLDOM_EXPORT LocallyResolvedAlias
599{
600 enum class Status { Invalid, ResolvedProperty, ResolvedObject, Loop, TooDeep };
601 bool valid()
602 {
603 switch (status) {
604 case Status::ResolvedProperty:
605 case Status::ResolvedObject:
606 return true;
607 default:
608 return false;
609 }
610 }
611 DomItem baseObject;
612 DomItem localPropertyDef;
613 QString typeName;
614 QStringList accessedPath;
615 Status status = Status::Invalid;
616 int nAliases = 0;
617};
618
619class QMLDOM_EXPORT PropertyDefinition : public AttributeInfo
620{
621public:
622 constexpr static DomType kindValue = DomType::PropertyDefinition;
623
624 bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
625 {
626 bool cont = AttributeInfo::iterateDirectSubpaths(self, visitor);
627 cont = cont && self.dvValueField(visitor, f: Fields::isPointer, value: isPointer);
628 cont = cont && self.dvValueField(visitor, f: Fields::isFinal, value: isFinal);
629 cont = cont && self.dvValueField(visitor, f: Fields::isAlias, value: isAlias());
630 cont = cont && self.dvValueField(visitor, f: Fields::isDefaultMember, value: isDefaultMember);
631 cont = cont && self.dvValueField(visitor, f: Fields::isRequired, value: isRequired);
632 cont = cont && self.dvValueField(visitor, f: Fields::read, value: read);
633 cont = cont && self.dvValueField(visitor, f: Fields::write, value: write);
634 cont = cont && self.dvValueField(visitor, f: Fields::bindable, value: bindable);
635 cont = cont && self.dvValueField(visitor, f: Fields::notify, value: notify);
636 cont = cont && self.dvReferenceField(visitor, f: Fields::type, referencedObject: typePath());
637 return cont;
638 }
639
640 Path typePath() const { return Paths::lookupTypePath(name: typeName); }
641
642 bool isAlias() const { return typeName == u"alias"; }
643 bool isParametricType() const;
644 void writeOut(DomItem &self, OutWriter &lw) const;
645
646 QString read;
647 QString write;
648 QString bindable;
649 QString notify;
650 bool isFinal = false;
651 bool isPointer = false;
652 bool isDefaultMember = false;
653 bool isRequired = false;
654 std::optional<QQmlJSScope::Ptr> scope;
655};
656
657class QMLDOM_EXPORT PropertyInfo
658{
659public:
660 constexpr static DomType kindValue = DomType::PropertyInfo; // used to get the correct kind in ObjectWrapper
661
662 bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor);
663
664 QList<DomItem> propertyDefs;
665 QList<DomItem> bindings;
666};
667
668class QMLDOM_EXPORT MethodParameter
669{
670public:
671 constexpr static DomType kindValue = DomType::MethodParameter;
672
673 bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor);
674
675 void writeOut(DomItem &self, OutWriter &ow) const;
676 void writeOutSignal(DomItem &self, OutWriter &ow) const;
677
678 QString name;
679 QString typeName;
680 bool isPointer = false;
681 bool isReadonly = false;
682 bool isList = false;
683 std::shared_ptr<ScriptExpression> defaultValue;
684 /*!
685 \internal
686 Contains the scriptElement representing this argument, inclusive default value,
687 deconstruction, etc.
688 */
689 std::shared_ptr<ScriptExpression> value;
690 QList<QmlObject> annotations;
691 RegionComments comments;
692};
693
694class QMLDOM_EXPORT MethodInfo : public AttributeInfo
695{
696 Q_GADGET
697public:
698 enum MethodType { Signal, Method };
699 Q_ENUM(MethodType)
700
701 constexpr static DomType kindValue = DomType::MethodInfo;
702
703 Path typePath(DomItem &) const
704 {
705 return (typeName.isEmpty() ? Path() : Paths::lookupTypePath(name: typeName));
706 }
707
708 bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor);
709 QString preCode(DomItem &) const; // ### REVISIT, might be simplified by using different toplevel production rules at usage site
710 QString postCode(DomItem &) const;
711 void writePre(DomItem &self, OutWriter &ow) const;
712 void writeOut(DomItem &self, OutWriter &ow) const;
713 void setCode(QString code)
714 {
715 body = std::make_shared<ScriptExpression>(
716 args&: code, args: ScriptExpression::ExpressionType::FunctionBody, args: 0,
717 args: QLatin1String("function foo(){\n"), args: QLatin1String("\n}\n"));
718 }
719 MethodInfo() = default;
720 std::optional<QQmlJSScope::Ptr> semanticScope() { return m_semanticScope; }
721 void setSemanticScope(QQmlJSScope::Ptr scope) { m_semanticScope = scope; }
722
723 // TODO: make private + add getters/setters
724 QList<MethodParameter> parameters;
725 MethodType methodType = Method;
726 std::shared_ptr<ScriptExpression> body;
727 std::shared_ptr<ScriptExpression> returnType;
728 bool isConstructor = false;
729 std::optional<QQmlJSScope::Ptr> m_semanticScope;
730};
731
732class QMLDOM_EXPORT EnumItem
733{
734public:
735 constexpr static DomType kindValue = DomType::EnumItem;
736
737 EnumItem(QString name = QString(), int value = 0) : m_name(name), m_value(value) { }
738
739 bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor);
740
741 QString name() const { return m_name; }
742 double value() const { return m_value; }
743 RegionComments &comments() { return m_comments; }
744 const RegionComments &comments() const { return m_comments; }
745 void writeOut(DomItem &self, OutWriter &lw) const;
746
747private:
748 QString m_name;
749 double m_value;
750 RegionComments m_comments;
751};
752
753class QMLDOM_EXPORT EnumDecl final : public CommentableDomElement
754{
755public:
756 constexpr static DomType kindValue = DomType::EnumDecl;
757 DomType kind() const override { return kindValue; }
758
759 EnumDecl(QString name = QString(), QList<EnumItem> values = QList<EnumItem>(),
760 Path pathFromOwner = Path())
761 : CommentableDomElement(pathFromOwner), m_name(name), m_values(values)
762 {
763 }
764
765 bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) override;
766
767 QString name() const { return m_name; }
768 void setName(QString name) { m_name = name; }
769 const QList<EnumItem> &values() const & { return m_values; }
770 bool isFlag() const { return m_isFlag; }
771 void setIsFlag(bool flag) { m_isFlag = flag; }
772 QString alias() const { return m_alias; }
773 void setAlias(QString aliasName) { m_alias = aliasName; }
774 void setValues(QList<EnumItem> values) { m_values = values; }
775 Path addValue(EnumItem value)
776 {
777 m_values.append(t: value);
778 return Path::Field(s: Fields::values).index(i: index_type(m_values.size() - 1));
779 }
780 void updatePathFromOwner(Path newP) override;
781
782 const QList<QmlObject> &annotations() const & { return m_annotations; }
783 void setAnnotations(QList<QmlObject> annotations);
784 Path addAnnotation(const QmlObject &child, QmlObject **cPtr = nullptr);
785 void writeOut(DomItem &self, OutWriter &lw) const override;
786
787private:
788 QString m_name;
789 bool m_isFlag = false;
790 QString m_alias;
791 QList<EnumItem> m_values;
792 QList<QmlObject> m_annotations;
793};
794
795class QMLDOM_EXPORT QmlObject final : public CommentableDomElement
796{
797 Q_DECLARE_TR_FUNCTIONS(QmlObject)
798public:
799 constexpr static DomType kindValue = DomType::QmlObject;
800 DomType kind() const override { return kindValue; }
801
802 QmlObject(Path pathFromOwner = Path());
803 bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override;
804 bool iterateBaseDirectSubpaths(DomItem &self, DirectVisitor);
805 QList<QString> fields() const;
806 QList<QString> fields(DomItem &) const override { return fields(); }
807 DomItem field(DomItem &self, QStringView name);
808 DomItem field(DomItem &self, QStringView name) const override
809 {
810 return const_cast<QmlObject *>(this)->field(self, name);
811 }
812 void updatePathFromOwner(Path newPath) override;
813 QString localDefaultPropertyName() const;
814 QString defaultPropertyName(DomItem &self) const;
815 virtual bool iterateSubOwners(DomItem &self, function_ref<bool(DomItem &owner)> visitor) const;
816
817 QString idStr() const { return m_idStr; }
818 QString name() const { return m_name; }
819 const QList<Path> &prototypePaths() const & { return m_prototypePaths; }
820 Path nextScopePath() const { return m_nextScopePath; }
821 const QMultiMap<QString, PropertyDefinition> &propertyDefs() const & { return m_propertyDefs; }
822 const QMultiMap<QString, Binding> &bindings() const & { return m_bindings; }
823 const QMultiMap<QString, MethodInfo> &methods() const & { return m_methods; }
824 QList<QmlObject> children() const { return m_children; }
825 QList<QmlObject> annotations() const { return m_annotations; }
826
827 void setIdStr(QString id) { m_idStr = id; }
828 void setName(QString name) { m_name = name; }
829 void setDefaultPropertyName(QString name) { m_defaultPropertyName = name; }
830 void setPrototypePaths(QList<Path> prototypePaths) { m_prototypePaths = prototypePaths; }
831 Path addPrototypePath(Path prototypePath)
832 {
833 index_type idx = index_type(m_prototypePaths.indexOf(t: prototypePath));
834 if (idx == -1) {
835 idx = index_type(m_prototypePaths.size());
836 m_prototypePaths.append(t: prototypePath);
837 }
838 return Path::Field(s: Fields::prototypes).index(i: idx);
839 }
840 void setNextScopePath(Path nextScopePath) { m_nextScopePath = nextScopePath; }
841 void setPropertyDefs(QMultiMap<QString, PropertyDefinition> propertyDefs)
842 {
843 m_propertyDefs = propertyDefs;
844 }
845 void setBindings(QMultiMap<QString, Binding> bindings) { m_bindings = bindings; }
846 void setMethods(QMultiMap<QString, MethodInfo> functionDefs) { m_methods = functionDefs; }
847 void setChildren(QList<QmlObject> children)
848 {
849 m_children = children;
850 if (pathFromOwner())
851 updatePathFromOwner(newPath: pathFromOwner());
852 }
853 void setAnnotations(QList<QmlObject> annotations)
854 {
855 m_annotations = annotations;
856 if (pathFromOwner())
857 updatePathFromOwner(newPath: pathFromOwner());
858 }
859 Path addPropertyDef(PropertyDefinition propertyDef, AddOption option,
860 PropertyDefinition **pDef = nullptr)
861 {
862 return insertUpdatableElementInMultiMap(mapPathFromOwner: pathFromOwner().field(name: Fields::propertyDefs),
863 mmap&: m_propertyDefs, key: propertyDef.name, value: propertyDef,
864 option, valuePtr: pDef);
865 }
866 MutableDomItem addPropertyDef(MutableDomItem &self, PropertyDefinition propertyDef,
867 AddOption option);
868
869 Path addBinding(Binding binding, AddOption option, Binding **bPtr = nullptr)
870 {
871 return insertUpdatableElementInMultiMap(mapPathFromOwner: pathFromOwner().field(name: Fields::bindings), mmap&: m_bindings,
872 key: binding.name(), value: binding, option, valuePtr: bPtr);
873 }
874 MutableDomItem addBinding(MutableDomItem &self, Binding binding, AddOption option);
875 Path addMethod(MethodInfo functionDef, AddOption option, MethodInfo **mPtr = nullptr)
876 {
877 return insertUpdatableElementInMultiMap(mapPathFromOwner: pathFromOwner().field(name: Fields::methods), mmap&: m_methods,
878 key: functionDef.name, value: functionDef, option, valuePtr: mPtr);
879 }
880 MutableDomItem addMethod(MutableDomItem &self, MethodInfo functionDef, AddOption option);
881 Path addChild(QmlObject child, QmlObject **cPtr = nullptr)
882 {
883 return appendUpdatableElementInQList(listPathFromOwner: pathFromOwner().field(name: Fields::children), list&: m_children,
884 value: child, vPtr: cPtr);
885 }
886 MutableDomItem addChild(MutableDomItem &self, QmlObject child)
887 {
888 Path p = addChild(child);
889 return MutableDomItem(self.owner().item(), p);
890 }
891 Path addAnnotation(const QmlObject &annotation, QmlObject **aPtr = nullptr)
892 {
893 return appendUpdatableElementInQList(listPathFromOwner: pathFromOwner().field(name: Fields::annotations),
894 list&: m_annotations, value: annotation, vPtr: aPtr);
895 }
896 void writeOut(DomItem &self, OutWriter &ow, QString onTarget) const;
897 void writeOut(DomItem &self, OutWriter &lw) const override { writeOut(self, ow&: lw, onTarget: QString()); }
898
899 LocallyResolvedAlias resolveAlias(DomItem &self,
900 std::shared_ptr<ScriptExpression> accessSequence) const;
901 LocallyResolvedAlias resolveAlias(DomItem &self, const QStringList &accessSequence) const;
902
903 std::optional<QQmlJSScope::Ptr> semanticScope() const { return m_scope; }
904 void setSemanticScope(const QQmlJSScope::Ptr &scope) { m_scope = scope; }
905
906private:
907 friend class QQmlDomAstCreator;
908 QString m_idStr;
909 QString m_name;
910 QList<Path> m_prototypePaths;
911 Path m_nextScopePath;
912 QString m_defaultPropertyName;
913 QMultiMap<QString, PropertyDefinition> m_propertyDefs;
914 QMultiMap<QString, Binding> m_bindings;
915 QMultiMap<QString, MethodInfo> m_methods;
916 QList<QmlObject> m_children;
917 QList<QmlObject> m_annotations;
918 std::optional<QQmlJSScope::Ptr> m_scope;
919};
920
921class Export
922{
923 Q_DECLARE_TR_FUNCTIONS(Export)
924public:
925 constexpr static DomType kindValue = DomType::Export;
926 static Export fromString(Path source, QStringView exp, Path typePath, ErrorHandler h);
927 bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
928 {
929 bool cont = true;
930 cont = cont && self.dvValueField(visitor, f: Fields::uri, value: uri);
931 cont = cont && self.dvValueField(visitor, f: Fields::typeName, value: typeName);
932 cont = cont && self.dvWrapField(visitor, f: Fields::version, obj&: version);
933 if (typePath)
934 cont = cont && self.dvReferenceField(visitor, f: Fields::type, referencedObject: typePath);
935 cont = cont && self.dvValueField(visitor, f: Fields::isInternal, value: isInternal);
936 cont = cont && self.dvValueField(visitor, f: Fields::isSingleton, value: isSingleton);
937 if (exportSourcePath)
938 cont = cont && self.dvReferenceField(visitor, f: Fields::exportSource, referencedObject: exportSourcePath);
939 return cont;
940 }
941
942 Path exportSourcePath;
943 QString uri;
944 QString typeName;
945 Version version;
946 Path typePath;
947 bool isInternal = false;
948 bool isSingleton = false;
949};
950
951class QMLDOM_EXPORT Component : public CommentableDomElement
952{
953public:
954 Component(QString name);
955 Component(Path pathFromOwner = Path());
956 Component(const Component &o) = default;
957 Component &operator=(const Component &) = default;
958
959 bool iterateDirectSubpaths(DomItem &, DirectVisitor) override;
960 void updatePathFromOwner(Path newPath) override;
961 DomItem field(DomItem &self, QStringView name) const override
962 {
963 return const_cast<Component *>(this)->field(self, name);
964 }
965 DomItem field(DomItem &self, QStringView name);
966
967 QString name() const { return m_name; }
968 const QMultiMap<QString, EnumDecl> &enumerations() const & { return m_enumerations; }
969 const QList<QmlObject> &objects() const & { return m_objects; }
970 bool isSingleton() const { return m_isSingleton; }
971 bool isCreatable() const { return m_isCreatable; }
972 bool isComposite() const { return m_isComposite; }
973 QString attachedTypeName() const { return m_attachedTypeName; }
974 Path attachedTypePath(DomItem &) const { return m_attachedTypePath; }
975
976 void setName(QString name) { m_name = name; }
977 void setEnumerations(QMultiMap<QString, EnumDecl> enumerations)
978 {
979 m_enumerations = enumerations;
980 }
981 Path addEnumeration(const EnumDecl &enumeration, AddOption option = AddOption::Overwrite,
982 EnumDecl **ePtr = nullptr)
983 {
984 return insertUpdatableElementInMultiMap(mapPathFromOwner: pathFromOwner().field(name: Fields::enumerations),
985 mmap&: m_enumerations, key: enumeration.name(), value: enumeration,
986 option, valuePtr: ePtr);
987 }
988 void setObjects(QList<QmlObject> objects) { m_objects = objects; }
989 Path addObject(const QmlObject &object, QmlObject **oPtr = nullptr);
990 void setIsSingleton(bool isSingleton) { m_isSingleton = isSingleton; }
991 void setIsCreatable(bool isCreatable) { m_isCreatable = isCreatable; }
992 void setIsComposite(bool isComposite) { m_isComposite = isComposite; }
993 void setAttachedTypeName(QString name) { m_attachedTypeName = name; }
994 void setAttachedTypePath(Path p) { m_attachedTypePath = p; }
995
996private:
997 friend class QQmlDomAstCreator;
998 QString m_name;
999 QMultiMap<QString, EnumDecl> m_enumerations;
1000 QList<QmlObject> m_objects;
1001 bool m_isSingleton = false;
1002 bool m_isCreatable = true;
1003 bool m_isComposite = true;
1004 QString m_attachedTypeName;
1005 Path m_attachedTypePath;
1006};
1007
1008class QMLDOM_EXPORT JsResource final : public Component
1009{
1010public:
1011 constexpr static DomType kindValue = DomType::JsResource;
1012 DomType kind() const override { return kindValue; }
1013
1014 JsResource(Path pathFromOwner = Path()) : Component(pathFromOwner) { }
1015 bool iterateDirectSubpaths(DomItem &, DirectVisitor) override
1016 { // to do: complete
1017 return true;
1018 }
1019 // globalSymbols defined/exported, required/used
1020};
1021
1022class QMLDOM_EXPORT QmltypesComponent final : public Component
1023{
1024public:
1025 constexpr static DomType kindValue = DomType::QmltypesComponent;
1026 DomType kind() const override { return kindValue; }
1027
1028 QmltypesComponent(Path pathFromOwner = Path()) : Component(pathFromOwner) { }
1029 bool iterateDirectSubpaths(DomItem &, DirectVisitor) override;
1030 const QList<Export> &exports() const & { return m_exports; }
1031 QString fileName() const { return m_fileName; }
1032 void setExports(QList<Export> exports) { m_exports = exports; }
1033 void addExport(const Export &exportedEntry) { m_exports.append(t: exportedEntry); }
1034 void setFileName(QString fileName) { m_fileName = fileName; }
1035 const QList<int> &metaRevisions() const & { return m_metaRevisions; }
1036 void setMetaRevisions(QList<int> metaRevisions) { m_metaRevisions = metaRevisions; }
1037 void setInterfaceNames(const QStringList& interfaces) { m_interfaceNames = interfaces; }
1038 const QStringList &interfaceNames() const & { return m_interfaceNames; }
1039 QString extensionTypeName() const { return m_extensionTypeName; }
1040 void setExtensionTypeName(const QString &name) { m_extensionTypeName = name; }
1041 QString valueTypeName() const { return m_valueTypeName; }
1042 void setValueTypeName(const QString &name) { m_valueTypeName = name; }
1043 bool hasCustomParser() const { return m_hasCustomParser; }
1044 void setHasCustomParser(bool v) { m_hasCustomParser = v; }
1045 bool extensionIsNamespace() const { return m_extensionIsNamespace; }
1046 void setExtensionIsNamespace(bool v) { m_extensionIsNamespace = v; }
1047 QQmlJSScope::AccessSemantics accessSemantics() const { return m_accessSemantics; }
1048 void setAccessSemantics(QQmlJSScope::AccessSemantics v) { m_accessSemantics = v; }
1049private:
1050 QList<Export> m_exports;
1051 QList<int> m_metaRevisions;
1052 QString m_fileName; // remove?
1053 QStringList m_interfaceNames;
1054 bool m_hasCustomParser = false;
1055 bool m_extensionIsNamespace = false;
1056 QString m_valueTypeName;
1057 QString m_extensionTypeName;
1058 QQmlJSScope::AccessSemantics m_accessSemantics;
1059};
1060
1061class QMLDOM_EXPORT QmlComponent final : public Component
1062{
1063public:
1064 constexpr static DomType kindValue = DomType::QmlComponent;
1065 DomType kind() const override { return kindValue; }
1066
1067 QmlComponent(QString name = QString()) : Component(name)
1068 {
1069 setIsComposite(true);
1070 setIsCreatable(true);
1071 }
1072
1073 QmlComponent(const QmlComponent &o)
1074 : Component(o), m_nextComponentPath(o.m_nextComponentPath), m_ids(o.m_ids)
1075 {
1076 }
1077 QmlComponent &operator=(const QmlComponent &) = default;
1078
1079 bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override;
1080
1081 const QMultiMap<QString, Id> &ids() const & { return m_ids; }
1082 Path nextComponentPath() const { return m_nextComponentPath; }
1083 void setIds(QMultiMap<QString, Id> ids) { m_ids = ids; }
1084 void setNextComponentPath(Path p) { m_nextComponentPath = p; }
1085 void updatePathFromOwner(Path newPath) override;
1086 Path addId(const Id &id, AddOption option = AddOption::Overwrite, Id **idPtr = nullptr)
1087 {
1088 // warning does nor remove old idStr when overwriting...
1089 return insertUpdatableElementInMultiMap(mapPathFromOwner: pathFromOwner().field(name: Fields::ids), mmap&: m_ids, key: id.name,
1090 value: id, option, valuePtr: idPtr);
1091 }
1092 void writeOut(DomItem &self, OutWriter &) const override;
1093 QList<QString> subComponentsNames(DomItem &self) const;
1094 QList<DomItem> subComponents(DomItem &self) const;
1095
1096 void setSemanticScope(const QQmlJSScope::Ptr &scope) { m_semanticScope = scope; }
1097 std::optional<QQmlJSScope::Ptr> semanticScope() { return m_semanticScope; }
1098
1099private:
1100 friend class QQmlDomAstCreator;
1101 Path m_nextComponentPath;
1102 QMultiMap<QString, Id> m_ids;
1103 std::optional<QQmlJSScope::Ptr> m_semanticScope;
1104};
1105
1106class QMLDOM_EXPORT GlobalComponent final : public Component
1107{
1108public:
1109 constexpr static DomType kindValue = DomType::GlobalComponent;
1110 DomType kind() const override { return kindValue; }
1111
1112 GlobalComponent(Path pathFromOwner = Path()) : Component(pathFromOwner) { }
1113};
1114
1115static ErrorGroups importErrors = { .groups: { DomItem::domErrorGroup, NewErrorGroup("importError") } };
1116
1117class QMLDOM_EXPORT ImportScope
1118{
1119 Q_DECLARE_TR_FUNCTIONS(ImportScope)
1120public:
1121 constexpr static DomType kindValue = DomType::ImportScope;
1122
1123 ImportScope() = default;
1124 ~ImportScope() = default;
1125
1126 const QList<Path> &importSourcePaths() const & { return m_importSourcePaths; }
1127
1128 const QMap<QString, ImportScope> &subImports() const & { return m_subImports; }
1129
1130 QList<Path> allSources(DomItem &self) const;
1131
1132 QSet<QString> importedNames(DomItem &self) const
1133 {
1134 QSet<QString> res;
1135 for (Path p : allSources(self)) {
1136 QSet<QString> ks = self.path(p: p.field(name: Fields::exports), h: self.errorHandler()).keys();
1137 res += ks;
1138 }
1139 return res;
1140 }
1141
1142 QList<DomItem> importedItemsWithName(DomItem &self, QString name) const
1143 {
1144 QList<DomItem> res;
1145 for (Path p : allSources(self)) {
1146 DomItem source = self.path(p: p.field(name: Fields::exports), h: self.errorHandler());
1147 DomItem els = source.key(name);
1148 int nEls = els.indexes();
1149 for (int i = 0; i < nEls; ++i)
1150 res.append(t: els.index(i));
1151 if (nEls == 0 && els) {
1152 self.addError(msg: importErrors.warning(
1153 message: tr(sourceText: "Looking up '%1' expected a list of exports, not %2")
1154 .arg(args&: name, args: els.toString())));
1155 }
1156 }
1157 return res;
1158 }
1159
1160 QList<Export> importedExportsWithName(DomItem &self, QString name) const
1161 {
1162 QList<Export> res;
1163 for (DomItem &i : importedItemsWithName(self, name))
1164 if (const Export *e = i.as<Export>())
1165 res.append(t: *e);
1166 else
1167 self.addError(msg: importErrors.warning(
1168 message: tr(sourceText: "Expected Export looking up '%1', not %2").arg(args&: name, args: i.toString())));
1169 return res;
1170 }
1171
1172 bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor);
1173
1174 void addImport(QStringList p, Path targetExports)
1175 {
1176 if (!p.isEmpty()) {
1177 QString current = p.takeFirst();
1178 m_subImports[current].addImport(p, targetExports);
1179 } else if (!m_importSourcePaths.contains(t: targetExports)) {
1180 m_importSourcePaths.append(t: targetExports);
1181 }
1182 }
1183
1184private:
1185 QList<Path> m_importSourcePaths;
1186 QMap<QString, ImportScope> m_subImports;
1187};
1188
1189class BindingValue
1190{
1191public:
1192 BindingValue();
1193 BindingValue(const QmlObject &o);
1194 BindingValue(std::shared_ptr<ScriptExpression> o);
1195 BindingValue(const QList<QmlObject> &l);
1196 ~BindingValue();
1197 BindingValue(const BindingValue &o);
1198 BindingValue &operator=(const BindingValue &o);
1199
1200 DomItem value(DomItem &binding);
1201 void updatePathFromOwner(Path newPath);
1202
1203private:
1204 friend class Binding;
1205 void clearValue();
1206
1207 BindingValueKind kind;
1208 union {
1209 int dummy;
1210 QmlObject object;
1211 std::shared_ptr<ScriptExpression> scriptExpression;
1212 QList<QmlObject> array;
1213 };
1214};
1215
1216} // end namespace Dom
1217} // end namespace QQmlJS
1218QT_END_NAMESPACE
1219#endif // QQMLDOMELEMENTS_P_H
1220

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