// Copyright (C) 2021 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QQMLDOMELEMENTS_P_H #define QQMLDOMELEMENTS_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include "qqmldomitem_p.h" #include "qqmldomconstants_p.h" #include "qqmldomcomments_p.h" #include "qqmldomlinewriter_p.h" #include #include #include #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE namespace QQmlJS { namespace Dom { // namespace for utility methods building specific paths // using a namespace one can reopen it and add more methods in other places namespace Paths { Path moduleIndexPath( const QString &uri, int majorVersion, const ErrorHandler &errorHandler = nullptr); Path moduleScopePath( const QString &uri, Version version, const ErrorHandler &errorHandler = nullptr); Path moduleScopePath( const QString &uri, const QString &version, const ErrorHandler &errorHandler = nullptr); inline Path moduleScopePath( const QString &uri, const ErrorHandler &errorHandler = nullptr) { return moduleScopePath(uri, QString(), errorHandler); } inline Path qmlDirInfoPath(const QString &path) { return Path::fromRoot(PathRoot::Top).withField(Fields::qmldirWithPath).withKey(path); } inline Path qmlDirPath(const QString &path) { return qmlDirInfoPath(path).withField(Fields::currentItem); } inline Path qmldirFileInfoPath(const QString &path) { return Path::fromRoot(PathRoot::Top).withField(Fields::qmldirFileWithPath).withKey(path); } inline Path qmldirFilePath(const QString &path) { return qmldirFileInfoPath(path).withField(Fields::currentItem); } inline Path qmlFileInfoPath(const QString &canonicalFilePath) { return Path::fromRoot(PathRoot::Top).withField(Fields::qmlFileWithPath).withKey(canonicalFilePath); } inline Path qmlFilePath(const QString &canonicalFilePath) { return qmlFileInfoPath(canonicalFilePath).withField(Fields::currentItem); } inline Path qmlFileObjectPath(const QString &canonicalFilePath) { return qmlFilePath(canonicalFilePath) .withField(Fields::components) .withKey(QString()) .withIndex(0) .withField(Fields::objects) .withIndex(0); } inline Path qmltypesFileInfoPath(const QString &path) { return Path::fromRoot(PathRoot::Top).withField(Fields::qmltypesFileWithPath).withKey(path); } inline Path qmltypesFilePath(const QString &path) { return qmltypesFileInfoPath(path).withField(Fields::currentItem); } inline Path jsFileInfoPath(const QString &path) { return Path::fromRoot(PathRoot::Top).withField(Fields::jsFileWithPath).withKey(path); } inline Path jsFilePath(const QString &path) { return jsFileInfoPath(path).withField(Fields::currentItem); } inline Path qmlDirectoryInfoPath(const QString &path) { return Path::fromRoot(PathRoot::Top).withField(Fields::qmlDirectoryWithPath).withKey(path); } inline Path qmlDirectoryPath(const QString &path) { return qmlDirectoryInfoPath(path).withField(Fields::currentItem); } inline Path globalScopeInfoPath(const QString &name) { return Path::fromRoot(PathRoot::Top).withField(Fields::globalScopeWithName).withKey(name); } inline Path globalScopePath(const QString &name) { return globalScopeInfoPath(name).withField(Fields::currentItem); } inline Path lookupCppTypePath(const QString &name) { return Path::fromCurrent(PathCurrent::Lookup).withField(Fields::cppType).withKey(name); } inline Path lookupPropertyPath(const QString &name) { return Path::fromCurrent(PathCurrent::Lookup).withField(Fields::propertyDef).withKey(name); } inline Path lookupSymbolPath(const QString &name) { return Path::fromCurrent(PathCurrent::Lookup).withField(Fields::symbol).withKey(name); } inline Path lookupTypePath(const QString &name) { return Path::fromCurrent(PathCurrent::Lookup).withField(Fields::type).withKey(name); } inline Path loadInfoPath(const Path &el) { return Path::fromRoot(PathRoot::Env).withField(Fields::loadInfo).withKey(el.toString()); } } // end namespace Paths class QMLDOM_EXPORT CommentableDomElement : public DomElement { public: CommentableDomElement(const Path &pathFromOwner = Path()) : DomElement(pathFromOwner) { } CommentableDomElement(const CommentableDomElement &o) : DomElement(o), m_comments(o.m_comments) { } CommentableDomElement &operator=(const CommentableDomElement &o) = default; bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override; RegionComments &comments() { return m_comments; } const RegionComments &comments() const { return m_comments; } private: RegionComments m_comments; }; class QMLDOM_EXPORT Version { public: constexpr static DomType kindValue = DomType::Version; constexpr static qint32 Undefined = -1; constexpr static qint32 Latest = -2; Version(qint32 majorVersion = Undefined, qint32 minorVersion = Undefined); static Version fromString(QStringView v); bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const; bool isLatest() const; bool isValid() const; QString stringValue() const; QString majorString() const { if (majorVersion >= 0 || majorVersion == Undefined) return QString::number(majorVersion); return QString(); } QString majorSymbolicString() const { if (majorVersion == Version::Latest) return QLatin1String("Latest"); if (majorVersion >= 0 || majorVersion == Undefined) return QString::number(majorVersion); return QString(); } QString minorString() const { if (minorVersion >= 0 || minorVersion == Undefined) return QString::number(minorVersion); return QString(); } int compare(const Version &o) const { int c = majorVersion - o.majorVersion; if (c != 0) return c; return minorVersion - o.minorVersion; } qint32 majorVersion; qint32 minorVersion; }; inline bool operator==(const Version &v1, const Version &v2) { return v1.compare(v2) == 0; } inline bool operator!=(const Version &v1, const Version &v2) { return v1.compare(v2) != 0; } inline bool operator<(const Version &v1, const Version &v2) { return v1.compare(v2) < 0; } inline bool operator<=(const Version &v1, const Version &v2) { return v1.compare(v2) <= 0; } inline bool operator>(const Version &v1, const Version &v2) { return v1.compare(v2) > 0; } inline bool operator>=(const Version &v1, const Version &v2) { return v1.compare(v2) >= 0; } class QMLDOM_EXPORT QmlUri { public: enum class Kind { Invalid, ModuleUri, DirectoryUrl, RelativePath, AbsolutePath }; QmlUri() = default; static QmlUri fromString(const QString &importStr); static QmlUri fromUriString(const QString &importStr); static QmlUri fromDirectoryString(const QString &importStr); bool isValid() const; bool isDirectory() const; bool isModule() const; QString moduleUri() const; QString localPath() const; QString absoluteLocalPath(const QString &basePath = QString()) const; QUrl directoryUrl() const; QString directoryString() const; QString toString() const; Kind kind() const; friend bool operator==(const QmlUri &i1, const QmlUri &i2) { return i1.m_kind == i2.m_kind && i1.m_value == i2.m_value; } friend bool operator!=(const QmlUri &i1, const QmlUri &i2) { return !(i1 == i2); } private: QmlUri(const QUrl &url) : m_kind(Kind::DirectoryUrl), m_value(url) { } QmlUri(Kind kind, const QString &value) : m_kind(kind), m_value(value) { } Kind m_kind = Kind::Invalid; std::variant m_value; }; class QMLDOM_EXPORT Import { Q_DECLARE_TR_FUNCTIONS(Import) public: constexpr static DomType kindValue = DomType::Import; static Import fromUriString( const QString &importStr, Version v = Version(), const QString &importId = QString(), const ErrorHandler &handler = nullptr); static Import fromFileString( const QString &importStr, const QString &importId = QString(), const ErrorHandler &handler = nullptr); Import(const QmlUri &uri = QmlUri(), Version version = Version(), const QString &importId = QString()) : uri(uri), version(version), importId(importId) { } bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const; Path importedPath() const { if (uri.isDirectory()) { QString path = uri.absoluteLocalPath(); if (!path.isEmpty()) { return Paths::qmlDirPath(path); } else { Q_ASSERT_X(false, "Import", "url imports not supported"); return Paths::qmldirFilePath(uri.directoryString()); } } else { return Paths::moduleScopePath(uri.moduleUri(), version); } } Import baseImport() const { return Import { uri, version }; } friend bool operator==(const Import &i1, const Import &i2) { return i1.uri == i2.uri && i1.version == i2.version && i1.importId == i2.importId && i1.comments == i2.comments && i1.implicit == i2.implicit; } friend bool operator!=(const Import &i1, const Import &i2) { return !(i1 == i2); } void writeOut(const DomItem &self, OutWriter &ow) const; static QRegularExpression importRe(); QmlUri uri; Version version; QString importId; RegionComments comments; bool implicit = false; }; class QMLDOM_EXPORT ModuleAutoExport { public: constexpr static DomType kindValue = DomType::ModuleAutoExport; bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const { bool cont = true; cont = cont && self.dvWrapField(visitor, Fields::import, import); cont = cont && self.dvValueField(visitor, Fields::inheritVersion, inheritVersion); return cont; } friend bool operator==(const ModuleAutoExport &i1, const ModuleAutoExport &i2) { return i1.import == i2.import && i1.inheritVersion == i2.inheritVersion; } friend bool operator!=(const ModuleAutoExport &i1, const ModuleAutoExport &i2) { return !(i1 == i2); } Import import; bool inheritVersion = false; }; class QMLDOM_EXPORT Pragma { public: constexpr static DomType kindValue = DomType::Pragma; Pragma(const QString &pragmaName = QString(), const QStringList &pragmaValues = {}) : name(pragmaName), values{ pragmaValues } { } bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const { bool cont = self.dvValueField(visitor, Fields::name, name); cont = cont && self.dvValueField(visitor, Fields::values, values); cont = cont && self.dvWrapField(visitor, Fields::comments, comments); return cont; } void writeOut(const DomItem &self, OutWriter &ow) const; QString name; QStringList values; RegionComments comments; }; class QMLDOM_EXPORT Id { public: constexpr static DomType kindValue = DomType::Id; Id(const QString &idName = QString(), const Path &referredObject = Path()); bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const; void updatePathFromOwner(const Path &pathFromOwner); Path addAnnotation(const Path &selfPathFromOwner, const QmlObject &ann, QmlObject **aPtr = nullptr); QString name; Path referredObjectPath; RegionComments comments; QList annotations; std::shared_ptr value; }; // TODO: rename? it may contain statements and stuff, not only expressions // TODO QTBUG-121933 class QMLDOM_EXPORT ScriptExpression final : public OwningItem { Q_GADGET Q_DECLARE_TR_FUNCTIONS(ScriptExpression) public: enum class ExpressionType { BindingExpression, FunctionBody, ArgInitializer, ArgumentStructure, ReturnType, JSCode, // Used for storing the content of the whole .js file as "one" Expression ESMCode, // Used for storing the content of the whole ECMAScript module (.mjs) as "one" // Expression }; Q_ENUM(ExpressionType); constexpr static DomType kindValue = DomType::ScriptExpression; DomType kind() const override { return kindValue; } explicit ScriptExpression( QStringView code, const std::shared_ptr &engine, AST::Node *ast, const std::shared_ptr &comments, ExpressionType expressionType, SourceLocation localOffset = SourceLocation(), int derivedFrom = 0, QStringView preCode = QStringView(), QStringView postCode = QStringView()); ScriptExpression() : ScriptExpression(QStringView(), std::shared_ptr(), nullptr, std::shared_ptr(), ExpressionType::BindingExpression, SourceLocation(), 0) { } explicit ScriptExpression( const QString &code, ExpressionType expressionType, int derivedFrom = 0, const QString &preCode = QString(), const QString &postCode = QString()) : OwningItem(derivedFrom), m_expressionType(expressionType) { setCode(code, preCode, postCode); } ScriptExpression(const ScriptExpression &e); std::shared_ptr makeCopy(const DomItem &self) const { return std::static_pointer_cast(doCopy(self)); } std::shared_ptr copyWithUpdatedCode(const DomItem &self, const QString &code) const; bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override; Path canonicalPath(const DomItem &self) const override { return self.m_ownerPath; } // parsed and created if not available AST::Node *ast() const { return m_ast; } // dump of the ast (without locations) void astDumper(const Sink &s, AstDumperOptions options) const; QString astRelocatableDump() const; // definedSymbols name, value, from // usedSymbols name, locations QStringView code() const { QMutexLocker l(mutex()); return m_code; } ExpressionType expressionType() const { QMutexLocker l(mutex()); return m_expressionType; } bool isNull() const { QMutexLocker l(mutex()); return m_code.isNull(); } std::shared_ptr engine() const { QMutexLocker l(mutex()); return m_engine; } QStringView loc2Str(SourceLocation) const; std::shared_ptr astComments() const { return m_astComments; } void writeOut(const DomItem &self, OutWriter &lw) const override; SourceLocation globalLocation(const DomItem &self) const; SourceLocation localOffset() const { return m_localOffset; } QStringView preCode() const { return m_preCode; } QStringView postCode() const { return m_postCode; } void setScriptElement(const ScriptElementVariant &p); ScriptElementVariant scriptElement() { return m_element; } protected: std::shared_ptr doCopy(const DomItem &) const override { return std::make_shared(*this); } std::function locationToGlobalF(const DomItem &self) const { SourceLocation loc = globalLocation(self); return [loc, this](SourceLocation x) { return SourceLocation(x.offset - m_localOffset.offset + loc.offset, x.length, x.startLine - m_localOffset.startLine + loc.startLine, ((x.startLine == m_localOffset.startLine) ? x.startColumn - m_localOffset.startColumn + loc.startColumn : x.startColumn)); }; } SourceLocation locationToLocal(SourceLocation x) const { return SourceLocation( x.offset - m_localOffset.offset, x.length, x.startLine - m_localOffset.startLine, ((x.startLine == m_localOffset.startLine) ? x.startColumn - m_localOffset.startColumn : x.startColumn)); // are line and column 1 based? then we should + 1 } std::function locationToLocalF(const DomItem &) const { return [this](SourceLocation x) { return locationToLocal(x); }; } private: enum class ParseMode { QML, JS, ESM, // ECMAScript module }; inline ParseMode resolveParseMode() { switch (m_expressionType) { case ExpressionType::BindingExpression: // unfortunately there are no documentation explaining this resolution // this was just moved from the original implementation return ParseMode::QML; case ExpressionType::ESMCode: return ParseMode::ESM; default: return ParseMode::JS; } } void setCode(const QString &code, const QString &preCode, const QString &postCode); [[nodiscard]] AST::Node *parse(ParseMode mode); ExpressionType m_expressionType; QString m_codeStr; QStringView m_code; QStringView m_preCode; QStringView m_postCode; mutable std::shared_ptr m_engine; mutable AST::Node *m_ast; std::shared_ptr m_astComments; SourceLocation m_localOffset; ScriptElementVariant m_element; }; class BindingValue; class QMLDOM_EXPORT Binding { public: constexpr static DomType kindValue = DomType::Binding; Binding(const QString &m_name = QString()); Binding(const QString &m_name, std::unique_ptr value, BindingType bindingType = BindingType::Normal); Binding(const QString &m_name, const std::shared_ptr &value, BindingType bindingType = BindingType::Normal); Binding(const QString &m_name, const QString &scriptCode, BindingType bindingType = BindingType::Normal); Binding(const QString &m_name, const QmlObject &value, BindingType bindingType = BindingType::Normal); Binding(const QString &m_name, const QList &value, BindingType bindingType = BindingType::Normal); Binding(const Binding &o); Binding(Binding &&o) = default; ~Binding(); Binding &operator=(const Binding &); Binding &operator=(Binding &&) = default; bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const; DomItem valueItem(const DomItem &self) const; // ### REVISIT: consider replacing return value with variant BindingValueKind valueKind() const; QString name() const { return m_name; } BindingType bindingType() const { return m_bindingType; } QmlObject const *objectValue() const; QList const *arrayValue() const; std::shared_ptr scriptExpressionValue() const; QmlObject *objectValue(); QList *arrayValue(); std::shared_ptr scriptExpressionValue(); QList annotations() const { return m_annotations; } void setAnnotations(const QList &annotations) { m_annotations = annotations; } void setValue(std::unique_ptr &&value); Path addAnnotation(const Path &selfPathFromOwner, const QmlObject &a, QmlObject **aPtr = nullptr); const RegionComments &comments() const { return m_comments; } RegionComments &comments() { return m_comments; } void updatePathFromOwner(const Path &newPath); void writeOut(const DomItem &self, OutWriter &lw) const; void writeOutValue(const DomItem &self, OutWriter &lw) const; bool isSignalHandler() const { QString baseName = m_name.split(QLatin1Char('.')).last(); return QQmlSignalNames::isHandlerName(baseName); } static QString preCodeForName(QStringView n) { return QStringLiteral(u"QtObject{\n %1: ").arg(n.split(u'.').last()); } static QString postCodeForName(QStringView) { return QStringLiteral(u"\n}\n"); } QString preCode() const { return preCodeForName(m_name); } QString postCode() const { return postCodeForName(m_name); } ScriptElementVariant bindingIdentifiers() const { return m_bindingIdentifiers; } void setBindingIdentifiers(const ScriptElementVariant &bindingIdentifiers) { m_bindingIdentifiers = bindingIdentifiers; } private: friend class QQmlDomAstCreator; BindingType m_bindingType; QString m_name; std::unique_ptr m_value; QList m_annotations; RegionComments m_comments; ScriptElementVariant m_bindingIdentifiers; }; class QMLDOM_EXPORT AttributeInfo { public: enum Access { Private, Protected, Public }; bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const; Path addAnnotation(const Path &selfPathFromOwner, const QmlObject &annotation, QmlObject **aPtr = nullptr); void updatePathFromOwner(const Path &newPath); QQmlJSScope::ConstPtr semanticScope() const { return m_semanticScope; } void setSemanticScope(const QQmlJSScope::ConstPtr &scope) { m_semanticScope = scope; } QString name; Access access = Access::Public; QString typeName; bool isReadonly = false; bool isList = false; QList annotations; RegionComments comments; QQmlJSScope::ConstPtr m_semanticScope; }; struct QMLDOM_EXPORT LocallyResolvedAlias { enum class Status { Invalid, ResolvedProperty, ResolvedObject, Loop, TooDeep }; bool valid() { switch (status) { case Status::ResolvedProperty: case Status::ResolvedObject: return true; default: return false; } } DomItem baseObject; DomItem localPropertyDef; QString typeName; QStringList accessedPath; Status status = Status::Invalid; int nAliases = 0; }; class QMLDOM_EXPORT PropertyDefinition : public AttributeInfo { public: constexpr static DomType kindValue = DomType::PropertyDefinition; bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const { bool cont = AttributeInfo::iterateDirectSubpaths(self, visitor); cont = cont && self.dvValueField(visitor, Fields::isPointer, isPointer); cont = cont && self.dvValueField(visitor, Fields::isFinal, isFinal); cont = cont && self.dvValueField(visitor, Fields::isAlias, isAlias()); cont = cont && self.dvValueField(visitor, Fields::isDefaultMember, isDefaultMember); cont = cont && self.dvValueField(visitor, Fields::isRequired, isRequired); cont = cont && self.dvValueField(visitor, Fields::read, read); cont = cont && self.dvValueField(visitor, Fields::write, write); cont = cont && self.dvValueField(visitor, Fields::bindable, bindable); cont = cont && self.dvValueField(visitor, Fields::notify, notify); cont = cont && self.dvReferenceField(visitor, Fields::type, typePath()); if (m_nameIdentifiers) { cont = cont && self.dvItemField(visitor, Fields::nameIdentifiers, [this, &self]() { return self.subScriptElementWrapperItem(m_nameIdentifiers); }); } return cont; } Path typePath() const { return Paths::lookupTypePath(typeName); } bool isAlias() const { return typeName == u"alias"; } bool isParametricType() const; void writeOut(const DomItem &self, OutWriter &lw) const; ScriptElementVariant nameIdentifiers() const { return m_nameIdentifiers; } void setNameIdentifiers(const ScriptElementVariant &name) { m_nameIdentifiers = name; } QString read; QString write; QString bindable; QString notify; bool isFinal = false; bool isPointer = false; bool isDefaultMember = false; bool isRequired = false; ScriptElementVariant m_nameIdentifiers; }; class QMLDOM_EXPORT PropertyInfo { public: constexpr static DomType kindValue = DomType::PropertyInfo; // used to get the correct kind in ObjectWrapper bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const; QList propertyDefs; QList bindings; }; class QMLDOM_EXPORT MethodParameter { public: constexpr static DomType kindValue = DomType::MethodParameter; enum class TypeAnnotationStyle { Prefix, // a(int x) Suffix, // a(x : int) }; bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const; void writeOut(const DomItem &self, OutWriter &ow) const; void writeOutSignal(const DomItem &self, OutWriter &ow) const; QString name; QString typeName; bool isPointer = false; bool isReadonly = false; bool isList = false; bool isRestElement = false; std::shared_ptr defaultValue; /*! \internal Contains the scriptElement representing this argument, inclusive default value, deconstruction, etc. */ std::shared_ptr value; QList annotations; RegionComments comments; TypeAnnotationStyle typeAnnotationStyle = TypeAnnotationStyle::Suffix; }; // TODO (QTBUG-128423) // Refactor to differentiate between Signals and Methods easily, // considering their distinct handling and formatting needs. // Explore separating Signal functionality or unifying shared methods. class QMLDOM_EXPORT MethodInfo : public AttributeInfo { Q_GADGET public: enum MethodType { Signal, Method }; Q_ENUM(MethodType) constexpr static DomType kindValue = DomType::MethodInfo; Path typePath(const DomItem &) const { return (typeName.isEmpty() ? Path() : Paths::lookupTypePath(typeName)); } bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const; QString preCode(const DomItem &) const; // ### REVISIT, might be simplified by using different toplevel production rules at usage site QString postCode(const DomItem &) const; void writePre(const DomItem &self, OutWriter &ow) const; void writeOut(const DomItem &self, OutWriter &ow) const; QString signature(const DomItem &self) const; void setCode(const QString &code) { body = std::make_shared( code, ScriptExpression::ExpressionType::FunctionBody, 0, QLatin1String("function foo(){\n"), QLatin1String("\n}\n")); } MethodInfo() = default; // TODO: make private + add getters/setters QList parameters; MethodType methodType = Method; std::shared_ptr body; std::shared_ptr returnType; bool isConstructor = false; private: void writeOutArguments(const DomItem &self, OutWriter &ow) const; void writeOutReturnType(OutWriter &ow) const; void writeOutBody(const DomItem &self, OutWriter &ow) const; }; class QMLDOM_EXPORT EnumItem { public: constexpr static DomType kindValue = DomType::EnumItem; enum class ValueKind : quint8 { ImplicitValue, ExplicitValue }; EnumItem(const QString &name = QString(), int value = 0, ValueKind valueKind = ValueKind::ImplicitValue) : m_name(name), m_value(value), m_valueKind(valueKind) { } bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const; QString name() const { return m_name; } double value() const { return m_value; } RegionComments &comments() { return m_comments; } const RegionComments &comments() const { return m_comments; } void writeOut(const DomItem &self, OutWriter &lw) const; private: QString m_name; double m_value; ValueKind m_valueKind; RegionComments m_comments; }; class QMLDOM_EXPORT EnumDecl final : public CommentableDomElement { public: constexpr static DomType kindValue = DomType::EnumDecl; DomType kind() const override { return kindValue; } EnumDecl(const QString &name = QString(), QList values = QList(), Path pathFromOwner = Path()) : CommentableDomElement(pathFromOwner), m_name(name), m_values(values) { } bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override; QString name() const { return m_name; } void setName(const QString &name) { m_name = name; } const QList &values() const & { return m_values; } bool isFlag() const { return m_isFlag; } void setIsFlag(bool flag) { m_isFlag = flag; } QString alias() const { return m_alias; } void setAlias(const QString &aliasName) { m_alias = aliasName; } void setValues(QList values) { m_values = values; } Path addValue(EnumItem value) { m_values.append(value); return Path::fromField(Fields::values).withIndex(index_type(m_values.size() - 1)); } void updatePathFromOwner(const Path &newP) override; const QList &annotations() const & { return m_annotations; } void setAnnotations(const QList &annotations); Path addAnnotation(const QmlObject &child, QmlObject **cPtr = nullptr); void writeOut(const DomItem &self, OutWriter &lw) const override; private: QString m_name; bool m_isFlag = false; QString m_alias; QList m_values; QList m_annotations; }; class QMLDOM_EXPORT QmlObject final : public CommentableDomElement { Q_DECLARE_TR_FUNCTIONS(QmlObject) public: constexpr static DomType kindValue = DomType::QmlObject; DomType kind() const override { return kindValue; } QmlObject(const Path &pathFromOwner = Path()); bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override; bool iterateBaseDirectSubpaths(const DomItem &self, DirectVisitor) const; QList fields() const; QList fields(const DomItem &) const override { return fields(); } DomItem field(const DomItem &self, QStringView name) const override; void updatePathFromOwner(const Path &newPath) override; QString localDefaultPropertyName() const; QString defaultPropertyName(const DomItem &self) const; virtual bool iterateSubOwners(const DomItem &self, function_ref visitor) const; QString idStr() const { return m_idStr; } QString name() const { return m_name; } const QList &prototypePaths() const & { return m_prototypePaths; } Path nextScopePath() const { return m_nextScopePath; } const QMultiMap &propertyDefs() const & { return m_propertyDefs; } const QMultiMap &bindings() const & { return m_bindings; } const QMultiMap &methods() const & { return m_methods; } QList children() const { return m_children; } QList annotations() const { return m_annotations; } void setIdStr(const QString &id) { m_idStr = id; } void setName(const QString &name) { m_name = name; } void setDefaultPropertyName(const QString &name) { m_defaultPropertyName = name; } void setPrototypePaths(QList prototypePaths) { m_prototypePaths = prototypePaths; } Path addPrototypePath(const Path &prototypePath) { index_type idx = index_type(m_prototypePaths.indexOf(prototypePath)); if (idx == -1) { idx = index_type(m_prototypePaths.size()); m_prototypePaths.append(prototypePath); } return Path::fromField(Fields::prototypes).withIndex(idx); } void setNextScopePath(const Path &nextScopePath) { m_nextScopePath = nextScopePath; } void setPropertyDefs(QMultiMap propertyDefs) { m_propertyDefs = propertyDefs; } void setBindings(QMultiMap bindings) { m_bindings = bindings; } void setMethods(QMultiMap functionDefs) { m_methods = functionDefs; } void setChildren(const QList &children) { m_children = children; if (pathFromOwner()) updatePathFromOwner(pathFromOwner()); } void setAnnotations(const QList &annotations) { m_annotations = annotations; if (pathFromOwner()) updatePathFromOwner(pathFromOwner()); } Path addPropertyDef(const PropertyDefinition &propertyDef, AddOption option, PropertyDefinition **pDef = nullptr) { return insertUpdatableElementInMultiMap(pathFromOwner().withField(Fields::propertyDefs), m_propertyDefs, propertyDef.name, propertyDef, option, pDef); } MutableDomItem addPropertyDef(MutableDomItem &self, const PropertyDefinition &propertyDef, AddOption option); Path addBinding(Binding binding, AddOption option, Binding **bPtr = nullptr) { return insertUpdatableElementInMultiMap(pathFromOwner().withField(Fields::bindings), m_bindings, binding.name(), binding, option, bPtr); } MutableDomItem addBinding(MutableDomItem &self, Binding binding, AddOption option); Path addMethod(const MethodInfo &functionDef, AddOption option, MethodInfo **mPtr = nullptr) { return insertUpdatableElementInMultiMap(pathFromOwner().withField(Fields::methods), m_methods, functionDef.name, functionDef, option, mPtr); } MutableDomItem addMethod(MutableDomItem &self, const MethodInfo &functionDef, AddOption option); Path addChild(QmlObject child, QmlObject **cPtr = nullptr) { return appendUpdatableElementInQList(pathFromOwner().withField(Fields::children), m_children, child, cPtr); } MutableDomItem addChild(MutableDomItem &self, QmlObject child) { Path p = addChild(child); return MutableDomItem(self.owner().item(), p); } Path addAnnotation(const QmlObject &annotation, QmlObject **aPtr = nullptr) { return appendUpdatableElementInQList(pathFromOwner().withField(Fields::annotations), m_annotations, annotation, aPtr); } QList> orderOfAttributes(const DomItem &self, const DomItem &component) const; void writeOutAttributes(const DomItem &self, OutWriter &ow, const DomItem &component, const QString &code) const; void writeOutSortedEnumerations(const DomItem &component, OutWriter &ow) const; void writeOutSortedAttributes(const DomItem &self, OutWriter &ow, const DomItem &component) const; void writeOutSortedPropertyDefinition(const DomItem &self, OutWriter &ow, QSet &mergedDefBinding) const; void writeOutId(const DomItem &self, OutWriter &ow) const; void writeOut(const DomItem &self, OutWriter &ow, const QString &onTarget) const; void writeOut(const DomItem &self, OutWriter &lw) const override { writeOut(self, lw, QString()); } LocallyResolvedAlias resolveAlias(const DomItem &self, std::shared_ptr accessSequence) const; LocallyResolvedAlias resolveAlias(const DomItem &self, const QStringList &accessSequence) const; QQmlJSScope::ConstPtr semanticScope() const { return m_scope; } void setSemanticScope(const QQmlJSScope::ConstPtr &scope) { m_scope = scope; } ScriptElementVariant nameIdentifiers() const { return m_nameIdentifiers; } void setNameIdentifiers(const ScriptElementVariant &name) { m_nameIdentifiers = name; } private: friend class QQmlDomAstCreator; QString m_idStr; QString m_name; QList m_prototypePaths; Path m_nextScopePath; QString m_defaultPropertyName; QMultiMap m_propertyDefs; QMultiMap m_bindings; QMultiMap m_methods; QList m_children; QList m_annotations; QQmlJSScope::ConstPtr m_scope; ScriptElementVariant m_nameIdentifiers; static constexpr quint32 posOfNewElements = std::numeric_limits::max(); }; class Export { Q_DECLARE_TR_FUNCTIONS(Export) public: constexpr static DomType kindValue = DomType::Export; static Export fromString( const Path &source, QStringView exp, const Path &typePath, const ErrorHandler &h); bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const { bool cont = true; cont = cont && self.dvValueField(visitor, Fields::uri, uri); cont = cont && self.dvValueField(visitor, Fields::typeName, typeName); cont = cont && self.dvWrapField(visitor, Fields::version, version); if (typePath) cont = cont && self.dvReferenceField(visitor, Fields::type, typePath); cont = cont && self.dvValueField(visitor, Fields::isInternal, isInternal); cont = cont && self.dvValueField(visitor, Fields::isSingleton, isSingleton); if (exportSourcePath) cont = cont && self.dvReferenceField(visitor, Fields::exportSource, exportSourcePath); return cont; } Path exportSourcePath; QString uri; QString typeName; Version version; Path typePath; bool isInternal = false; bool isSingleton = false; }; class QMLDOM_EXPORT Component : public CommentableDomElement { public: Component(const QString &name); Component(const Path &pathFromOwner = Path()); Component(const Component &o) = default; Component &operator=(const Component &) = default; bool iterateDirectSubpaths(const DomItem &, DirectVisitor) const override; void updatePathFromOwner(const Path &newPath) override; DomItem field(const DomItem &self, QStringView name) const override; QString name() const { return m_name; } const QMultiMap &enumerations() const & { return m_enumerations; } const QList &objects() const & { return m_objects; } bool isSingleton() const { return m_isSingleton; } bool isCreatable() const { return m_isCreatable; } bool isComposite() const { return m_isComposite; } QString attachedTypeName() const { return m_attachedTypeName; } Path attachedTypePath(const DomItem &) const { return m_attachedTypePath; } void setName(const QString &name) { m_name = name; } void setEnumerations(QMultiMap enumerations) { m_enumerations = enumerations; } Path addEnumeration(const EnumDecl &enumeration, AddOption option = AddOption::Overwrite, EnumDecl **ePtr = nullptr) { return insertUpdatableElementInMultiMap(pathFromOwner().withField(Fields::enumerations), m_enumerations, enumeration.name(), enumeration, option, ePtr); } void setObjects(const QList &objects) { m_objects = objects; } Path addObject(const QmlObject &object, QmlObject **oPtr = nullptr); void setIsSingleton(bool isSingleton) { m_isSingleton = isSingleton; } void setIsCreatable(bool isCreatable) { m_isCreatable = isCreatable; } void setIsComposite(bool isComposite) { m_isComposite = isComposite; } void setAttachedTypeName(const QString &name) { m_attachedTypeName = name; } void setAttachedTypePath(const Path &p) { m_attachedTypePath = p; } private: friend class QQmlDomAstCreator; QString m_name; QMultiMap m_enumerations; QList m_objects; bool m_isSingleton = false; bool m_isCreatable = true; bool m_isComposite = true; QString m_attachedTypeName; Path m_attachedTypePath; }; class QMLDOM_EXPORT JsResource final : public Component { public: constexpr static DomType kindValue = DomType::JsResource; DomType kind() const override { return kindValue; } JsResource(const Path &pathFromOwner = Path()) : Component(pathFromOwner) { } bool iterateDirectSubpaths(const DomItem &, DirectVisitor) const override { // to do: complete return true; } // globalSymbols defined/exported, required/used }; class QMLDOM_EXPORT QmltypesComponent final : public Component { public: constexpr static DomType kindValue = DomType::QmltypesComponent; DomType kind() const override { return kindValue; } QmltypesComponent(const Path &pathFromOwner = Path()) : Component(pathFromOwner) { } bool iterateDirectSubpaths(const DomItem &, DirectVisitor) const override; const QList &exports() const & { return m_exports; } QString fileName() const { return m_fileName; } void setExports(QList exports) { m_exports = exports; } void addExport(const Export &exportedEntry) { m_exports.append(exportedEntry); } void setFileName(const QString &fileName) { m_fileName = fileName; } const QList &metaRevisions() const & { return m_metaRevisions; } void setMetaRevisions(QList metaRevisions) { m_metaRevisions = metaRevisions; } void setInterfaceNames(const QStringList& interfaces) { m_interfaceNames = interfaces; } const QStringList &interfaceNames() const & { return m_interfaceNames; } QString extensionTypeName() const { return m_extensionTypeName; } void setExtensionTypeName(const QString &name) { m_extensionTypeName = name; } QString valueTypeName() const { return m_valueTypeName; } void setValueTypeName(const QString &name) { m_valueTypeName = name; } bool hasCustomParser() const { return m_hasCustomParser; } void setHasCustomParser(bool v) { m_hasCustomParser = v; } bool extensionIsJavaScript() const { return m_extensionIsJavaScript; } void setExtensionIsJavaScript(bool v) { m_extensionIsJavaScript = v; } bool extensionIsNamespace() const { return m_extensionIsNamespace; } void setExtensionIsNamespace(bool v) { m_extensionIsNamespace = v; } QQmlJSScope::AccessSemantics accessSemantics() const { return m_accessSemantics; } void setAccessSemantics(QQmlJSScope::AccessSemantics v) { m_accessSemantics = v; } void setSemanticScope(const QQmlJSScope::ConstPtr &scope) { m_semanticScope = scope; } QQmlJSScope::ConstPtr semanticScope() const { return m_semanticScope; } private: QList m_exports; QList m_metaRevisions; QString m_fileName; // remove? QStringList m_interfaceNames; bool m_hasCustomParser = false; bool m_extensionIsJavaScript = false; bool m_extensionIsNamespace = false; QString m_valueTypeName; QString m_extensionTypeName; QQmlJSScope::AccessSemantics m_accessSemantics = QQmlJSScope::AccessSemantics::None; QQmlJSScope::ConstPtr m_semanticScope; }; class QMLDOM_EXPORT QmlComponent final : public Component { public: constexpr static DomType kindValue = DomType::QmlComponent; DomType kind() const override { return kindValue; } QmlComponent(const QString &name = QString()) : Component(name) { setIsComposite(true); setIsCreatable(true); } bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override; const QMultiMap &ids() const & { return m_ids; } Path nextComponentPath() const { return m_nextComponentPath; } void setIds(QMultiMap ids) { m_ids = ids; } void setNextComponentPath(const Path &p) { m_nextComponentPath = p; } void updatePathFromOwner(const Path &newPath) override; Path addId(const Id &id, AddOption option = AddOption::Overwrite, Id **idPtr = nullptr) { // warning does nor remove old idStr when overwriting... return insertUpdatableElementInMultiMap(pathFromOwner().withField(Fields::ids), m_ids, id.name, id, option, idPtr); } void writeOut(const DomItem &self, OutWriter &) const override; QList subComponentsNames(const DomItem &self) const; QList subComponents(const DomItem &self) const; void setSemanticScope(const QQmlJSScope::ConstPtr &scope) { m_semanticScope = scope; } QQmlJSScope::ConstPtr semanticScope() const { return m_semanticScope; } ScriptElementVariant nameIdentifiers() const { return m_nameIdentifiers; } void setNameIdentifiers(const ScriptElementVariant &name) { m_nameIdentifiers = name; } private: friend class QQmlDomAstCreator; Path m_nextComponentPath; QMultiMap m_ids; QQmlJSScope::ConstPtr m_semanticScope; // m_nameIdentifiers contains the name of the component as FieldMemberExpression, and therefore // only exists in inline components! ScriptElementVariant m_nameIdentifiers; }; class QMLDOM_EXPORT GlobalComponent final : public Component { public: constexpr static DomType kindValue = DomType::GlobalComponent; DomType kind() const override { return kindValue; } GlobalComponent(const Path &pathFromOwner = Path()) : Component(pathFromOwner) { } }; static ErrorGroups importErrors = { { DomItem::domErrorGroup, NewErrorGroup("importError") } }; class QMLDOM_EXPORT ImportScope { Q_DECLARE_TR_FUNCTIONS(ImportScope) public: constexpr static DomType kindValue = DomType::ImportScope; ImportScope() = default; const QList &importSourcePaths() const & { return m_importSourcePaths; } const QMap &subImports() const & { return m_subImports; } QList allSources(const DomItem &self) const; QSet importedNames(const DomItem &self) const { QSet res; const auto sources = allSources(self); for (const Path &p : sources) { QSet ks = self.path(p.withField(Fields::exports), self.errorHandler()).keys(); res += ks; } return res; } QList importedItemsWithName(const DomItem &self, const QString &name) const { QList res; const auto sources = allSources(self); for (const Path &p : sources) { DomItem source = self.path(p.withField(Fields::exports), self.errorHandler()); DomItem els = source.key(name); int nEls = els.indexes(); for (int i = 0; i < nEls; ++i) res.append(els.index(i)); if (nEls == 0 && els) { self.addError(importErrors.warning( tr("Looking up '%1' expected a list of exports, not %2") .arg(name, els.toString()))); } } return res; } QList importedExportsWithName(const DomItem &self, const QString &name) const { QList res; for (const DomItem &i : importedItemsWithName(self, name)) if (const Export *e = i.as()) res.append(*e); else self.addError(importErrors.warning( tr("Expected Export looking up '%1', not %2").arg(name, i.toString()))); return res; } bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const; void addImport(QStringList p, const Path &targetExports) { if (!p.isEmpty()) { const QString current = p.takeFirst(); m_subImports[current].addImport(std::move(p), targetExports); } else if (!m_importSourcePaths.contains(targetExports)) { m_importSourcePaths.append(targetExports); } } private: QList m_importSourcePaths; QMap m_subImports; }; class BindingValue { public: BindingValue(); BindingValue(const QmlObject &o); BindingValue(const std::shared_ptr &o); BindingValue(const QList &l); ~BindingValue(); BindingValue(const BindingValue &o); BindingValue &operator=(const BindingValue &o); DomItem value(const DomItem &binding) const; void updatePathFromOwner(const Path &newPath); private: friend class Binding; void clearValue(); BindingValueKind kind; union { int dummy; QmlObject object; std::shared_ptr scriptExpression; QList array; }; }; } // end namespace Dom } // end namespace QQmlJS QT_END_NAMESPACE #endif // QQMLDOMELEMENTS_P_H