Revision control
Copy as Markdown
// 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
// Qt-Security score:significant
#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 <QtQml/private/qqmljsast_p.h>
#include <QtQml/private/qqmljsengine_p.h>
#include <QtQml/private/qqmlsignalnames_p.h>
#include <QtCore/QCborValue>
#include <QtCore/QCborMap>
#include <QtCore/QMutexLocker>
#include <memory>
#include <private/qqmljsscope_p.h>
#include <functional>
#include <limits>
#include <utility>
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 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 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 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(Version o) const
{
int c = majorVersion - o.majorVersion;
if (c != 0)
return c;
return minorVersion - o.minorVersion;
}
qint32 majorVersion;
qint32 minorVersion;
};
inline bool operator==(Version v1, Version v2)
{
return v1.compare(v2) == 0;
}
inline bool operator!=(Version v1, Version v2)
{
return v1.compare(v2) != 0;
}
inline bool operator<(Version v1, Version v2)
{
return v1.compare(v2) < 0;
}
inline bool operator<=(Version v1, Version v2)
{
return v1.compare(v2) <= 0;
}
inline bool operator>(Version v1, Version v2)
{
return v1.compare(v2) > 0;
}
inline bool operator>=(Version v1, 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<QString, QUrl> 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;
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.invokeVisitorOnField(visitor, Fields::import, import);
cont = cont && self.invokeVisitorOnValue(visitor, PathEls::Field(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.invokeVisitorOnValue(visitor, PathEls::Field(Fields::name), name);
cont = cont && self.invokeVisitorOnValue(visitor, PathEls::Field(Fields::values), values);
cont = cont && self.invokeVisitorOnField(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<QmlObject> annotations;
std::shared_ptr<ScriptExpression> 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<QQmlJS::Engine> &engine,
AST::Node *ast, const std::shared_ptr<AstComments> &comments,
ExpressionType expressionType,
const SourceLocation &localOffset = SourceLocation());
ScriptExpression()
: ScriptExpression(QStringView(), std::shared_ptr<QQmlJS::Engine>(), nullptr,
std::shared_ptr<AstComments>(), ExpressionType::BindingExpression,
SourceLocation())
{
}
explicit ScriptExpression(const QString &code, ExpressionType expressionType)
: OwningItem(), m_expressionType(expressionType)
{
setCode(code);
}
ScriptExpression(const ScriptExpression &e);
std::shared_ptr<ScriptExpression> makeCopy(const DomItem &self) const
{
return std::static_pointer_cast<ScriptExpression>(doCopy(self));
}
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<QQmlJS::Engine> engine() const
{
QMutexLocker l(mutex());
return m_engine;
}
QStringView loc2Str(const SourceLocation &) const;
std::shared_ptr<AstComments> 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; }
void setScriptElement(const ScriptElementVariant &p);
ScriptElementVariant scriptElement() { return m_element; }
protected:
std::shared_ptr<OwningItem> doCopy(const DomItem &) const override
{
return std::make_shared<ScriptExpression>(*this);
}
SourceLocation locationToLocal(const 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
}
private:
void setCode(const QString &code);
[[nodiscard]] AST::Node *parse();
ExpressionType m_expressionType;
QString m_codeStr;
QStringView m_code;
mutable std::shared_ptr<QQmlJS::Engine> m_engine;
mutable AST::Node *m_ast;
std::shared_ptr<AstComments> 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<BindingValue> &&value,
BindingType bindingType = BindingType::Normal);
Binding(const QString &m_name, const std::shared_ptr<ScriptExpression> &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<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(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<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(const QList<QmlObject> &annotations) { m_annotations = annotations; }
void setValue(std::unique_ptr<BindingValue> &&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 QQmlDomAstCreatorBase;
BindingType m_bindingType;
QString m_name;
std::unique_ptr<BindingValue> m_value;
QList<QmlObject> 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<QmlObject> 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.invokeVisitorOnValue(visitor, PathEls::Field(Fields::isPointer), isPointer);
// virtual and override don't need to be accessed through DomItem API for now
cont = cont && self.invokeVisitorOnValue(visitor, PathEls::Field(Fields::isFinal), isFinal);
cont = cont && self.invokeVisitorOnValue(visitor, PathEls::Field(Fields::isAlias), isAlias());
cont = cont && self.invokeVisitorOnValue(visitor, PathEls::Field(Fields::isDefaultMember),
isDefaultMember);
cont = cont && self.invokeVisitorOnValue(visitor, PathEls::Field(Fields::isRequired),
isRequired);
cont = cont && self.invokeVisitorOnValue(visitor, PathEls::Field(Fields::read), read);
cont = cont && self.invokeVisitorOnValue(visitor, PathEls::Field(Fields::write), write);
cont = cont && self.invokeVisitorOnValue(visitor, PathEls::Field(Fields::bindable), bindable);
cont = cont && self.invokeVisitorOnValue(visitor, PathEls::Field(Fields::notify), notify);
if (m_nameIdentifiers) {
cont = cont && visitor(PathEls::Field(Fields::nameIdentifiers), [this, &self]() {
return self.subScriptElementWrapperItem(m_nameIdentifiers);
});
}
return cont;
}
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 isVirtual = false;
bool isOverride = false;
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<DomItem> propertyDefs;
QList<DomItem> 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<ScriptExpression> defaultValue;
/*!
\internal
Contains the scriptElement representing this argument, inclusive default value,
deconstruction, etc.
*/
std::shared_ptr<ScriptExpression> value;
QList<QmlObject> 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;
bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const;
void writePre(const DomItem &self, OutWriter &ow) const;
void writeOut(const DomItem &self, OutWriter &ow) const;
QString signature(const DomItem &self) const;
MethodInfo() = default;
// TODO: make private + add getters/setters
QList<MethodParameter> parameters;
MethodType methodType = Method;
std::shared_ptr<ScriptExpression> body;
std::shared_ptr<ScriptExpression> returnType;
bool isConstructor = false;
bool isGenerator = false;
private:
void writeOutArguments(const DomItem &self, OutWriter &ow) const;
void writeOutReturnType(const DomItem &self, 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(), const QList<EnumItem> &values = QList<EnumItem>(),
const 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<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(const QString &aliasName) { m_alias = aliasName; }
void setValues(const QList<EnumItem> &values) { m_values = values; }
Path addValue(const 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<QmlObject> &annotations() const & { return m_annotations; }
void setAnnotations(const QList<QmlObject> &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<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(const Path &pathFromOwner = Path());
bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override;
bool iterateBaseDirectSubpaths(const DomItem &self, DirectVisitor) const;
QList<QString> fields() const;
QList<QString> 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;
bool iterateSubOwners(const DomItem &self,
function_ref<bool(const DomItem &owner)> visitor) const;
QString idStr() const { return m_idStr; }
QString name() const { return m_name; }
const QList<Path> &prototypePaths() const & { return m_prototypePaths; }
Path nextScopePath() const { return m_nextScopePath; }
const QMultiMap<QString, PropertyDefinition> &propertyDefs() const & { return m_propertyDefs; }
const QMultiMap<QString, Binding> &bindings() const & { return m_bindings; }
const QMultiMap<QString, MethodInfo> &methods() const & { return m_methods; }
QList<QmlObject> children() const { return m_children; }
QList<QmlObject> 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(const QList<Path> &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(const QMultiMap<QString, PropertyDefinition> &propertyDefs)
{
m_propertyDefs = propertyDefs;
}
void setBindings(const QMultiMap<QString, Binding> &bindings) { m_bindings = bindings; }
void setMethods(const QMultiMap<QString, MethodInfo> &functionDefs)
{
m_methods = functionDefs;
}
void setChildren(const QList<QmlObject> &children)
{
m_children = children;
if (pathFromOwner())
updatePathFromOwner(pathFromOwner());
}
void setAnnotations(const QList<QmlObject> &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(const Binding &binding, AddOption option, Binding **bPtr = nullptr)
{
return insertUpdatableElementInMultiMap(pathFromOwner().withField(Fields::bindings), m_bindings,
binding.name(), binding, option, bPtr);
}
MutableDomItem addBinding(MutableDomItem &self, const 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(const QmlObject &child, QmlObject **cPtr = nullptr)
{
return appendUpdatableElementInQList(pathFromOwner().withField(Fields::children), m_children,
child, cPtr);
}
MutableDomItem addChild(MutableDomItem &self, const 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<std::pair<SourceLocation, DomItem>> orderOfAttributes(const DomItem &self,
const DomItem &component) const;
using Attributes = QList<std::pair<SourceLocation, DomItem>>;
void writeOutAttributes(OutWriter &ow, const Attributes &attribs, const QString &code) const;
void writeOutSortedEnumerations(const QList<DomItem> &descs, OutWriter &ow) const;
void writeOutSortedAttributes(const DomItem &self, OutWriter &ow, const DomItem &component,
const Attributes &attribs) const;
void writeOutSortedPropertyDefinition(const DomItem &self, OutWriter &ow,
QSet<QString> &mergedDefBinding,
const QStringList &keys) 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<ScriptExpression> 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 QQmlDomAstCreatorBase;
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;
QQmlJSScope::ConstPtr m_scope;
ScriptElementVariant m_nameIdentifiers;
static constexpr quint32 posOfNewElements = std::numeric_limits<quint32>::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.invokeVisitorOnValue(visitor, PathEls::Field(Fields::uri), uri);
cont = cont && self.invokeVisitorOnValue(visitor, PathEls::Field(Fields::typeName), typeName);
cont = cont && self.invokeVisitorOnField(visitor, Fields::version, version);
if (typePath)
cont = cont && self.invokeVisitorOnReference(visitor, Fields::type, typePath);
cont = cont && self.invokeVisitorOnValue(visitor, PathEls::Field(Fields::isInternal),
isInternal);
cont = cont && self.invokeVisitorOnValue(visitor, PathEls::Field(Fields::isSingleton),
isSingleton);
if (exportSourcePath)
cont = cont && self.invokeVisitorOnReference(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<QString, EnumDecl> &enumerations() const & { return m_enumerations; }
const 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(const DomItem &) const { return m_attachedTypePath; }
void setName(const QString &name) { m_name = name; }
void setEnumerations(const QMultiMap<QString, EnumDecl> &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<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(const QString &name) { m_attachedTypeName = name; }
void setAttachedTypePath(const Path &p) { m_attachedTypePath = p; }
private:
friend class QQmlDomAstCreatorBase;
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(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 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<QString, Id> &ids() const & { return m_ids; }
Path nextComponentPath() const { return m_nextComponentPath; }
void setIds(const QMultiMap<QString, Id> &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<QString> subComponentsNames(const DomItem &self) const;
QList<DomItem> 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 QQmlDomAstCreatorBase;
Path m_nextComponentPath;
QMultiMap<QString, Id> 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 BindingValue
{
public:
BindingValue();
BindingValue(const QmlObject &o);
BindingValue(const std::shared_ptr<ScriptExpression> &o);
BindingValue(const QList<QmlObject> &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> scriptExpression;
QList<QmlObject> array;
};
};
} // end namespace Dom
} // end namespace QQmlJS
QT_END_NAMESPACE
#endif // QQMLDOMELEMENTS_P_H