diff options
Diffstat (limited to 'src/qmldom/qqmldomelements_p.h')
-rw-r--r-- | src/qmldom/qqmldomelements_p.h | 1172 |
1 files changed, 1172 insertions, 0 deletions
diff --git a/src/qmldom/qqmldomelements_p.h b/src/qmldom/qqmldomelements_p.h new file mode 100644 index 0000000000..66b568d871 --- /dev/null +++ b/src/qmldom/qqmldomelements_p.h @@ -0,0 +1,1172 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +**/ +#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 <QtQml/private/qqmljsast_p.h> +#include <QtQml/private/qqmljsengine_p.h> + +#include <QtCore/QCborValue> +#include <QtCore/QCborMap> +#include <QtCore/QMutexLocker> +#include <QtCore/QPair> + +#include <functional> +#include <limits> + +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(QString uri, int majorVersion, ErrorHandler errorHandler = nullptr); +Path moduleScopePath(QString uri, Version version, ErrorHandler errorHandler = nullptr); +Path moduleScopePath(QString uri, QString version, ErrorHandler errorHandler = nullptr); +inline Path moduleScopePath(QString uri, ErrorHandler errorHandler = nullptr) +{ + return moduleScopePath(uri, QString(), errorHandler); +} +inline Path qmlDirInfoPath(QString path) +{ + return Path::Root(PathRoot::Top).field(Fields::qmldirWithPath).key(path); +} +inline Path qmlDirPath(QString path) +{ + return qmlDirInfoPath(path).field(Fields::currentItem); +} +inline Path qmldirFileInfoPath(QString path) +{ + return Path::Root(PathRoot::Top).field(Fields::qmldirFileWithPath).key(path); +} +inline Path qmldirFilePath(QString path) +{ + return qmldirFileInfoPath(path).field(Fields::currentItem); +} +inline Path qmlFileInfoPath(QString canonicalFilePath) +{ + return Path::Root(PathRoot::Top).field(Fields::qmlFileWithPath).key(canonicalFilePath); +} +inline Path qmlFilePath(QString canonicalFilePath) +{ + return qmlFileInfoPath(canonicalFilePath).field(Fields::currentItem); +} +inline Path qmlFileObjectPath(QString canonicalFilePath) +{ + return qmlFilePath(canonicalFilePath) + .field(Fields::components) + .key(QString()) + .index(0) + .field(Fields::objects) + .index(0); +} +inline Path qmltypesFileInfoPath(QString path) +{ + return Path::Root(PathRoot::Top).field(Fields::qmltypesFileWithPath).key(path); +} +inline Path qmltypesFilePath(QString path) +{ + return qmltypesFileInfoPath(path).field(Fields::currentItem); +} +inline Path jsFileInfoPath(QString path) +{ + return Path::Root(PathRoot::Top).field(Fields::jsFileWithPath).key(path); +} +inline Path jsFilePath(QString path) +{ + return jsFileInfoPath(path).field(Fields::currentItem); +} +inline Path qmlDirectoryInfoPath(QString path) +{ + return Path::Root(PathRoot::Top).field(Fields::qmlDirectoryWithPath).key(path); +} +inline Path qmlDirectoryPath(QString path) +{ + return qmlDirectoryInfoPath(path).field(Fields::currentItem); +} +inline Path globalScopeInfoPath(QString name) +{ + return Path::Root(PathRoot::Top).field(Fields::globalScopeWithName).key(name); +} +inline Path globalScopePath(QString name) +{ + return globalScopeInfoPath(name).field(Fields::currentItem); +} +inline Path lookupCppTypePath(QString name) +{ + return Path::Current(PathCurrent::Lookup).field(Fields::cppType).key(name); +} +inline Path lookupPropertyPath(QString name) +{ + return Path::Current(PathCurrent::Lookup).field(Fields::propertyDef).key(name); +} +inline Path lookupSymbolPath(QString name) +{ + return Path::Current(PathCurrent::Lookup).field(Fields::symbol).key(name); +} +inline Path lookupTypePath(QString name) +{ + return Path::Current(PathCurrent::Lookup).field(Fields::type).key(name); +} +inline Path loadInfoPath(Path el) +{ + return Path::Root(PathRoot::Env).field(Fields::loadInfo).key(el.toString()); +} +} // end namespace Paths + +class IndentInfo +{ +public: + QStringView string; + QStringView trailingString; + int nNewlines = 0; + int column = 0; + + IndentInfo(QStringView line, int tabSize, int initialColumn = 0) + { + string = line; + int fixup = 0; + if (initialColumn < 0) // we do not want % of negative numbers + fixup = (-initialColumn + tabSize - 1) / tabSize * tabSize; + column = initialColumn + fixup; + const QChar tab = QLatin1Char('\t'); + int iStart = 0; + int len = line.length(); + for (int i = 0; i < len; i++) { + if (line[i] == tab) + column = ((column / tabSize) + 1) * tabSize; + else if (line[i] == QLatin1Char('\n') + || (line[i] == QLatin1Char('\r') + && (i + 1 == len || line[i + 1] != QLatin1Char('\n')))) { + iStart = i + 1; + ++nNewlines; + column = 0; + } else if (!line[i].isLowSurrogate()) + column++; + } + column -= fixup; + trailingString = line.mid(iStart); + } +}; + +class QMLDOM_EXPORT CommentableDomElement : public DomElement +{ +public: + CommentableDomElement(Path pathFromOwner = Path()) : DomElement(pathFromOwner) { } + CommentableDomElement(const CommentableDomElement &o) : DomElement(o), m_comments(o.m_comments) + { + } + CommentableDomElement &operator=(const CommentableDomElement &o) = default; + bool iterateDirectSubpaths(DomItem &self, DirectVisitor) 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; + enum { Undefined = -1, Latest = -2 }; + + Version(qint32 majorVersion = Undefined, qint32 minorVersion = Undefined); + static Version fromString(QStringView v); + + bool iterateDirectSubpaths(DomItem &self, DirectVisitor); + + 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 Import +{ + Q_DECLARE_TR_FUNCTIONS(Import) +public: + constexpr static DomType kindValue = DomType::Import; + + static Import fromUriString(QString importStr, Version v = Version(), + QString importId = QString(), ErrorHandler handler = nullptr); + static Import fromFileString(QString importStr, QString baseDir = QString(), + QString importId = QString(), ErrorHandler handler = nullptr); + + Import(QString uri = QString(), Version version = Version(), QString importId = QString()) + : uri(uri), version(version), importId(importId) + { + } + + bool iterateDirectSubpaths(DomItem &self, DirectVisitor); + bool isDirectoryImport() const + { + return uri.startsWith(u"http://") || uri.startsWith(u"https://") + || uri.startsWith(u"file://"); + } + QString filePath() const + { + if (uri.startsWith(u"file://")) + return uri.mid(7); + return QString(); + } + bool isSpecialImport() const { return uri.startsWith(u"<"); } + Path importedPath() const + { + if (isDirectoryImport()) { + if (!filePath().isEmpty()) { + return Paths::qmlDirPath(filePath()); + } else { + Q_ASSERT_X(false, "Import", "url imports not supported"); + return Paths::qmldirFilePath(uri); + } + } else { + return Paths::moduleScopePath(uri, 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); } + + static QRegularExpression importRe(); + + QString uri; + Version version; + QString importId; + RegionComments comments; + bool implicit = false; +}; + +class QMLDOM_EXPORT ModuleAutoExport +{ +public: + constexpr static DomType kindValue = DomType::ModuleAutoExport; + + bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) + { + 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(QString pragmaName = QString()) : name(pragmaName) { } + + bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) + { + bool cont = self.dvValueField(visitor, Fields::name, name); + cont = cont && self.dvWrapField(visitor, Fields::comments, comments); + return cont; + } + + QString name; + RegionComments comments; +}; + +class QMLDOM_EXPORT Id +{ +public: + constexpr static DomType kindValue = DomType::Id; + + Id(QString idName = QString(), Path referredObject = Path()); + + bool iterateDirectSubpaths(DomItem &self, DirectVisitor); + void updatePathFromOwner(Path pathFromOwner); + Path addAnnotation(Path selfPathFromOwner, const QmlObject &ann, QmlObject **aPtr = nullptr); + + QString name; + Path referredObjectPath; + RegionComments comments; + QList<QmlObject> annotations; +}; + +class QMLDOM_EXPORT ScriptExpression final : public OwningItem +{ + Q_GADGET + Q_DECLARE_TR_FUNCTIONS(ScriptExpression) +public: + enum class ExpressionType { BindingExpression, FunctionBody, ArgInitializer }; + Q_ENUM(ExpressionType); + constexpr static DomType kindValue = DomType::ScriptExpression; + DomType kind() const override { return kindValue; } + + explicit ScriptExpression(QStringView code, std::shared_ptr<QQmlJS::Engine> engine, + AST::Node *ast, std::shared_ptr<AstComments> comments, + ExpressionType expressionType, + SourceLocation localOffset = SourceLocation(), int derivedFrom = 0, + QStringView preCode = QStringView(), + QStringView postCode = QStringView()) + : OwningItem(derivedFrom), + m_expressionType(expressionType), + m_code(code), + m_preCode(preCode), + m_postCode(postCode), + m_engine(engine), + m_ast(ast), + m_astComments(comments), + m_localOffset(localOffset) + { + Q_ASSERT(m_astComments); + } + + ScriptExpression() + : ScriptExpression(QStringView(), std::shared_ptr<QQmlJS::Engine>(), nullptr, + std::shared_ptr<AstComments>(), ExpressionType::BindingExpression, + SourceLocation(), 0) + { + } + + explicit ScriptExpression(QString code, ExpressionType expressionType, int derivedFrom = 0, + QString preCode = QString(), QString postCode = QString()) + : OwningItem(derivedFrom), m_expressionType(expressionType) + { + setCode(code, preCode, postCode); + } + + ScriptExpression(const ScriptExpression &e); + + std::shared_ptr<ScriptExpression> makeCopy(DomItem &self) const + { + return std::static_pointer_cast<ScriptExpression>(doCopy(self)); + } + + std::shared_ptr<ScriptExpression> copyWithUpdatedCode(DomItem &self, QString code) const; + + bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) override; + + Path canonicalPath(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(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<QQmlJS::Engine> engine() const + { + QMutexLocker l(mutex()); + return m_engine; + } + std::shared_ptr<AstComments> astComments() const { return m_astComments; } + SourceLocation globalLocation(DomItem &self) const; + SourceLocation localOffset() const { return m_localOffset; } + QStringView preCode() const { return m_preCode; } + QStringView postCode() const { return m_postCode; } + +protected: + std::shared_ptr<OwningItem> doCopy(DomItem &) const override + { + return std::shared_ptr<OwningItem>(new ScriptExpression(*this)); + } + + std::function<SourceLocation(SourceLocation)> locationToGlobalF(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<SourceLocation(SourceLocation)> locationToLocalF(DomItem &) const + { + return [this](SourceLocation x) { return locationToLocal(x); }; + } + +private: + void setCode(QString code, QString preCode, QString postCode); + ExpressionType m_expressionType; + QString m_codeStr; + QStringView m_code; + QStringView m_preCode; + QStringView m_postCode; + mutable std::shared_ptr<QQmlJS::Engine> m_engine; + mutable AST::Node *m_ast; + std::shared_ptr<AstComments> m_astComments; + SourceLocation m_localOffset; +}; + +class BindingValue; + +class QMLDOM_EXPORT Binding +{ +public: + constexpr static DomType kindValue = DomType::Binding; + + Binding(QString m_name = QString(), + std::unique_ptr<BindingValue> value = std::unique_ptr<BindingValue>(), + BindingType bindingType = BindingType::Normal); + Binding(QString m_name, std::shared_ptr<ScriptExpression> value, + BindingType bindingType = BindingType::Normal); + Binding(QString m_name, QString scriptCode, BindingType bindingType = BindingType::Normal); + Binding(QString m_name, QmlObject value, BindingType bindingType = BindingType::Normal); + Binding(QString m_name, QList<QmlObject> value, BindingType bindingType = BindingType::Normal); + Binding(const Binding &o); + Binding(Binding &&o) = default; + ~Binding(); + Binding &operator=(const Binding &); + Binding &operator=(Binding &&) = default; + + bool iterateDirectSubpaths(DomItem &self, DirectVisitor); + DomItem valueItem(DomItem &self) const; + BindingValueKind valueKind() const; + QString name() const { return m_name; } + BindingType bindingType() const { return m_bindingType; } + QmlObject const *objectValue() const; + QList<QmlObject> const *arrayValue() const; + std::shared_ptr<ScriptExpression> scriptExpressionValue() const; + QmlObject *objectValue(); + QList<QmlObject> *arrayValue(); + std::shared_ptr<ScriptExpression> scriptExpressionValue(); + QList<QmlObject> annotations() const { return m_annotations; } + void setAnnotations(QList<QmlObject> annotations) { m_annotations = annotations; } + void setValue(std::unique_ptr<BindingValue> &&value) { m_value = std::move(value); } + Path addAnnotation(Path selfPathFromOwner, const QmlObject &a, QmlObject **aPtr = nullptr); + const RegionComments &comments() const { return m_comments; } + RegionComments &comments() { return m_comments; } + void updatePathFromOwner(Path newPath); + bool isSignalHandler() const + { + QString baseName = m_name.split(QLatin1Char('.')).last(); + if (baseName.startsWith(u"on") && baseName.length() > 2 && baseName.at(2).isUpper()) + return true; + return false; + } + QString preCode() const + { + return QStringLiteral(u"function %1() {\n").arg(m_name.split(u'.').last()); + } + QString postCode() const { return QStringLiteral(u"\n}\n"); } + +private: + friend class QmlDomAstCreator; + BindingType m_bindingType; + QString m_name; + std::unique_ptr<BindingValue> m_value; + QList<QmlObject> m_annotations; + RegionComments m_comments; +}; + +class QMLDOM_EXPORT AttributeInfo +{ +public: + enum Access { Private, Protected, Public }; + + bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor); + + Path addAnnotation(Path selfPathFromOwner, const QmlObject &annotation, + QmlObject **aPtr = nullptr); + void updatePathFromOwner(Path newPath); + + QString name; + Access access = Access::Public; + QString typeName; + bool isReadonly = false; + bool isList = false; + QList<QmlObject> annotations; + RegionComments comments; +}; + +class QMLDOM_EXPORT PropertyDefinition : public AttributeInfo +{ +public: + constexpr static DomType kindValue = DomType::PropertyDefinition; + + bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) + { + bool cont = AttributeInfo::iterateDirectSubpaths(self, visitor); + cont = cont && self.dvValueField(visitor, Fields::isPointer, isPointer); + 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.dvReferenceField(visitor, Fields::type, typePath()); + return cont; + } + + Path typePath() const + { + Path res = Path::Current(PathCurrent::Types); + for (QString el : typeName.split(QChar::fromLatin1('.'))) + res = res.key(el); + return res; + } + + bool isPointer = false; + bool isAlias = false; + bool isDefaultMember = false; + bool isRequired = false; +}; + +class QMLDOM_EXPORT PropertyInfo +{ +public: + constexpr static DomType kindValue = DomType::PropertyInfo; + + bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor); + + QList<DomItem> propertyDefs; + QList<DomItem> bindings; +}; + +class QMLDOM_EXPORT MethodParameter +{ +public: + constexpr static DomType kindValue = DomType::MethodParameter; + + bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor); + + QString name; + QString typeName; + bool isPointer = false; + bool isReadonly = false; + bool isList = false; + std::shared_ptr<ScriptExpression> defaultValue; + QList<QmlObject> annotations; + RegionComments comments; +}; + +class QMLDOM_EXPORT MethodInfo : public AttributeInfo +{ + Q_GADGET +public: + enum MethodType { Signal, Method }; + Q_ENUM(MethodType) + + constexpr static DomType kindValue = DomType::MethodInfo; + + Path typePath(DomItem &) const + { + return (typeName.isEmpty() ? Path() : Paths::lookupTypePath(typeName)); + } + + bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor); + QString preCode(DomItem &) const; + QString postCode(DomItem &) const; + void setCode(QString code) + { + body = std::shared_ptr<ScriptExpression>( + new ScriptExpression(code, ScriptExpression::ExpressionType::FunctionBody, 0, + QLatin1String("function foo(){\n"), QLatin1String("\n}\n"))); + } + + MethodInfo() = default; + + QList<MethodParameter> parameters; + MethodType methodType = Method; + std::shared_ptr<ScriptExpression> body; +}; + +class QMLDOM_EXPORT EnumItem +{ +public: + constexpr static DomType kindValue = DomType::EnumItem; + + EnumItem(QString name = QString(), int value = 0) : m_name(name), m_value(value) { } + + bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor); + + QString name() const { return m_name; } + double value() const { return m_value; } + RegionComments &comments() { return m_comments; } + const RegionComments &comments() const { return m_comments; } + +private: + QString m_name; + double m_value; + RegionComments m_comments; +}; + +class QMLDOM_EXPORT EnumDecl final : public CommentableDomElement +{ +public: + constexpr static DomType kindValue = DomType::EnumDecl; + DomType kind() const override { return kindValue; } + + EnumDecl(QString name = QString(), QList<EnumItem> values = QList<EnumItem>(), + Path pathFromOwner = Path()) + : CommentableDomElement(pathFromOwner), m_name(name), m_values(values) + { + } + EnumDecl &operator=(const EnumDecl &) = default; + + bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) override; + + QString name() const { return m_name; } + void setName(QString name) { m_name = name; } + QList<EnumItem> 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(QString aliasName) { m_alias = aliasName; } + void setValues(QList<EnumItem> values) { m_values = values; } + Path addValue(EnumItem value) + { + m_values.append(value); + return Path::Field(Fields::values).index(index_type(m_values.size() - 1)); + } + void updatePathFromOwner(Path newP) override; + + QList<QmlObject> annotations() const; + void setAnnotations(QList<QmlObject> annotations); + Path addAnnotation(const QmlObject &child, QmlObject **cPtr = nullptr); + +private: + QString m_name; + bool m_isFlag; + QString m_alias; + QList<EnumItem> m_values; + QList<QmlObject> 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(Path pathFromOwner = Path()); + QmlObject &operator=(const QmlObject &) = default; + bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override; + bool iterateBaseDirectSubpaths(DomItem &self, DirectVisitor); + QList<QString> fields() const; + QList<QString> fields(DomItem &) const override { return fields(); } + DomItem field(DomItem &self, QStringView name); + DomItem field(DomItem &self, QStringView name) const override + { + return const_cast<QmlObject *>(this)->field(self, name); + } + void updatePathFromOwner(Path newPath) override; + QString localDefaultPropertyName() const; + QString defaultPropertyName(DomItem &self) const; + virtual bool iterateSubOwners(DomItem &self, function_ref<bool(DomItem &owner)> visitor) const; + + QString idStr() const { return m_idStr; } + QString name() const { return m_name; } + QList<Path> prototypePaths() const { return m_prototypePaths; } + Path nextScopePath() const { return m_nextScopePath; } + QMultiMap<QString, PropertyDefinition> propertyDefs() const { return m_propertyDefs; } + QMultiMap<QString, Binding> bindings() const { return m_bindings; } + QMultiMap<QString, MethodInfo> methods() const { return m_methods; } + QList<QmlObject> children() const { return m_children; } + QList<QmlObject> annotations() const { return m_annotations; } + + void setIdStr(QString id) { m_idStr = id; } + void setName(QString name) { m_name = name; } + void setDefaultPropertyName(QString name) { m_defaultPropertyName = name; } + void setPrototypePaths(QList<Path> prototypePaths) { m_prototypePaths = prototypePaths; } + Path addPrototypePath(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::Field(Fields::prototypes).index(idx); + } + void setNextScopePath(Path nextScopePath) { m_nextScopePath = nextScopePath; } + void setPropertyDefs(QMultiMap<QString, PropertyDefinition> propertyDefs) + { + m_propertyDefs = propertyDefs; + } + void setBindings(QMultiMap<QString, Binding> bindings) { m_bindings = bindings; } + void setMethods(QMultiMap<QString, MethodInfo> functionDefs) { m_methods = functionDefs; } + void setChildren(QList<QmlObject> children) + { + m_children = children; + if (pathFromOwner()) + updatePathFromOwner(pathFromOwner()); + } + void setAnnotations(QList<QmlObject> annotations) + { + m_annotations = annotations; + if (pathFromOwner()) + updatePathFromOwner(pathFromOwner()); + } + Path addPropertyDef(PropertyDefinition propertyDef, AddOption option, + PropertyDefinition **pDef = nullptr) + { + return insertUpdatableElementInMultiMap(pathFromOwner().field(Fields::propertyDefs), + m_propertyDefs, propertyDef.name, propertyDef, + option, pDef); + } + MutableDomItem addPropertyDef(MutableDomItem &self, PropertyDefinition propertyDef, + AddOption option); + + Path addBinding(Binding binding, AddOption option, Binding **bPtr = nullptr) + { + return insertUpdatableElementInMultiMap(pathFromOwner().field(Fields::bindings), m_bindings, + binding.name(), binding, option, bPtr); + } + MutableDomItem addBinding(MutableDomItem &self, Binding binding, AddOption option); + Path addMethod(MethodInfo functionDef, AddOption option, MethodInfo **mPtr = nullptr) + { + return insertUpdatableElementInMultiMap(pathFromOwner().field(Fields::methods), m_methods, + functionDef.name, functionDef, option, mPtr); + } + MutableDomItem addMethod(MutableDomItem &self, MethodInfo functionDef, AddOption option); + Path addChild(QmlObject child, QmlObject **cPtr = nullptr) + { + return appendUpdatableElementInQList(pathFromOwner().field(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().field(Fields::annotations), + m_annotations, annotation, aPtr); + } + +private: + friend class QmlDomAstCreator; + QString m_idStr; + QString m_name; + QList<Path> m_prototypePaths; + Path m_nextScopePath; + QString m_defaultPropertyName; + QMultiMap<QString, PropertyDefinition> m_propertyDefs; + QMultiMap<QString, Binding> m_bindings; + QMultiMap<QString, MethodInfo> m_methods; + QList<QmlObject> m_children; + QList<QmlObject> m_annotations; +}; + +class Export +{ + Q_DECLARE_TR_FUNCTIONS(Export) +public: + constexpr static DomType kindValue = DomType::Export; + static Export fromString(Path source, QStringView exp, Path typePath, ErrorHandler h); + bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) + { + 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(QString name); + Component(Path pathFromOwner = Path()); + Component(const Component &o) = default; + Component &operator=(const Component &) = default; + + bool iterateDirectSubpaths(DomItem &, DirectVisitor) override; + void updatePathFromOwner(Path newPath) override; + DomItem field(DomItem &self, QStringView name) const override + { + return const_cast<Component *>(this)->field(self, name); + } + DomItem field(DomItem &self, QStringView name); + + QString name() const { return m_name; } + QMultiMap<QString, EnumDecl> enumerations() const { return m_enumerations; } + QList<QmlObject> 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(DomItem &) const { return m_attachedTypePath; } + + void setName(QString name) { m_name = name; } + void setEnumerations(QMultiMap<QString, EnumDecl> enumerations) + { + m_enumerations = enumerations; + } + Path addEnumeration(const EnumDecl &enumeration, AddOption option = AddOption::Overwrite, + EnumDecl **ePtr = nullptr) + { + return insertUpdatableElementInMultiMap(pathFromOwner().field(Fields::enumerations), + m_enumerations, enumeration.name(), enumeration, + option, ePtr); + } + void setObjects(QList<QmlObject> 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(QString name) { m_attachedTypeName = name; } + void setAttachedTypePath(Path p) { m_attachedTypePath = p; } + +private: + friend class QmlDomAstCreator; + QString m_name; + QMultiMap<QString, EnumDecl> m_enumerations; + QList<QmlObject> 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(Path pathFromOwner = Path()) : Component(pathFromOwner) { } + bool iterateDirectSubpaths(DomItem &, DirectVisitor) 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(Path pathFromOwner = Path()) : Component(pathFromOwner) { } + bool iterateDirectSubpaths(DomItem &, DirectVisitor) override; + QList<Export> exports() const { return m_exports; } + QString fileName() const { return m_fileName; } + void setExports(QList<Export> exports) { m_exports = exports; } + void addExport(const Export &exportedEntry) { m_exports.append(exportedEntry); } + void setFileName(QString fileName) { m_fileName = fileName; } + QList<int> metaRevisions() const { return m_metaRevisions; } + void setMetaRevisions(QList<int> metaRevisions) { m_metaRevisions = metaRevisions; } + +private: + QList<Export> m_exports; + QList<int> m_metaRevisions; + QString m_fileName; // remove? +}; + +class QMLDOM_EXPORT QmlComponent final : public Component +{ +public: + constexpr static DomType kindValue = DomType::QmlComponent; + DomType kind() const override { return kindValue; } + + QmlComponent(QString name = QString()) : Component(name) + { + setIsComposite(true); + setIsCreatable(true); + } + + QmlComponent(const QmlComponent &o) + : Component(o), m_nextComponentPath(o.m_nextComponentPath), m_ids(o.m_ids) + { + } + QmlComponent &operator=(const QmlComponent &) = default; + + bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override; + + QMultiMap<QString, Id> ids() const { return m_ids; } + Path nextComponentPath() const { return m_nextComponentPath; } + void setIds(QMultiMap<QString, Id> ids) { m_ids = ids; } + void setNextComponentPath(Path p) { m_nextComponentPath = p; } + void updatePathFromOwner(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().field(Fields::ids), m_ids, id.name, + id, option, idPtr); + } + QList<QString> subComponentsNames(DomItem &self) const; + QList<DomItem> subComponents(DomItem &self) const; + +private: + friend class QmlDomAstCreator; + Path m_nextComponentPath; + QMultiMap<QString, Id> m_ids; +}; + +class QMLDOM_EXPORT GlobalComponent final : public Component +{ +public: + constexpr static DomType kindValue = DomType::GlobalComponent; + DomType kind() const override { return kindValue; } + + GlobalComponent(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; + ~ImportScope() = default; + + QList<Path> importSourcePaths() const { return m_importSourcePaths; } + + QMap<QString, ImportScope> subImports() const { return m_subImports; } + + QList<Path> allSources(DomItem &self) const; + + QSet<QString> importedNames(DomItem &self) const + { + QSet<QString> res; + for (Path p : allSources(self)) { + QSet<QString> ks = self.path(p.field(Fields::exports), self.errorHandler()).keys(); + res += ks; + } + return res; + } + + QList<DomItem> importedItemsWithName(DomItem &self, QString name) const + { + QList<DomItem> res; + for (Path p : allSources(self)) { + DomItem source = self.path(p.field(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<Export> importedExportsWithName(DomItem &self, QString name) const + { + QList<Export> res; + for (DomItem &i : importedItemsWithName(self, name)) + if (const Export *e = i.as<Export>()) + res.append(*e); + else + self.addError(importErrors.warning( + tr("Expected Export looking up '%1', not %1").arg(name, i.toString()))); + return res; + } + + bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor); + + void addImport(QStringList p, Path targetExports) + { + if (!p.isEmpty()) { + QString current = p.takeFirst(); + m_subImports[current].addImport(p, targetExports); + } else if (!m_importSourcePaths.contains(targetExports)) { + m_importSourcePaths.append(targetExports); + } + } + +private: + QList<Path> m_importSourcePaths; + QMap<QString, ImportScope> m_subImports; +}; + +class BindingValue +{ +public: + BindingValue(); + BindingValue(const QmlObject &o); + BindingValue(std::shared_ptr<ScriptExpression> o); + BindingValue(const QList<QmlObject> &l); + ~BindingValue(); + BindingValue(const BindingValue &o); + BindingValue &operator=(const BindingValue &o); + + DomItem value(DomItem &binding); + void updatePathFromOwner(Path newPath); + +private: + friend class Binding; + void clearValue(); + + BindingValueKind kind; + union { + int dummy; + QmlObject object; + std::shared_ptr<ScriptExpression> scriptExpression; + QList<QmlObject> array; + }; +}; + +} // end namespace Dom +} // end namespace QQmlJS +QT_END_NAMESPACE +#endif // QQMLDOMELEMENTS_P_H |