aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmldom/qqmldomelements.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qmldom/qqmldomelements.cpp')
-rw-r--r--src/qmldom/qqmldomelements.cpp1263
1 files changed, 1263 insertions, 0 deletions
diff --git a/src/qmldom/qqmldomelements.cpp b/src/qmldom/qqmldomelements.cpp
new file mode 100644
index 0000000000..2600035512
--- /dev/null
+++ b/src/qmldom/qqmldomelements.cpp
@@ -0,0 +1,1263 @@
+/****************************************************************************
+**
+** 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$
+**/
+#include "qqmldomelements_p.h"
+#include "qqmldomcomments_p.h"
+#include "qqmldomastdumper_p.h"
+#include "qqmldommock_p.h"
+#include "qqmldomtop_p.h"
+#include "qqmldomexternalitems_p.h"
+
+#include <QtQml/private/qqmljslexer_p.h>
+#include <QtQml/private/qqmljsparser_p.h>
+#include <QtQml/private/qqmljsengine_p.h>
+#include <QtQml/private/qqmljsastvisitor_p.h>
+#include <QtQml/private/qqmljsast_p.h>
+
+#include <QtCore/QScopeGuard>
+#include <QtCore/QRegularExpression>
+#include <QtCore/QDir>
+#include <QtCore/QBasicMutex>
+
+#include <optional>
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+namespace Dom {
+
+namespace Paths {
+
+Path moduleIndexPath(QString uri, int majorVersion, ErrorHandler errorHandler)
+{
+ QString version = QString::number(majorVersion);
+ if (majorVersion == Version::Latest)
+ version = QLatin1String("Latest");
+ else if (majorVersion == Version::Undefined)
+ version = QString();
+ if (uri.startsWith(u"file://") || uri.startsWith(u"http://") || uri.startsWith(u"https://")) {
+ if (majorVersion != Version::Undefined)
+ Path::myErrors()
+ .error(Path::tr("The module directory import %1 cannot have a version")
+ .arg(uri))
+ .handle(errorHandler);
+ version = QString();
+ } else {
+ QRegularExpression moduleRe(QLatin1String(R"(\A\w+(?:\.\w+)*\Z)"));
+ auto m = moduleRe.match(uri);
+ if (!m.isValid())
+ Path::myErrors()
+ .error(Path::tr("Invalid module name in import %1").arg(uri))
+ .handle(errorHandler);
+ }
+ return Path::Root(PathRoot::Env).field(Fields::moduleIndexWithUri).key(uri).key(version);
+}
+
+Path moduleScopePath(QString uri, Version version, ErrorHandler errorHandler)
+{
+ if (uri.startsWith(u"file://") || uri.startsWith(u"http://") || uri.startsWith(u"https://")) {
+ if (version.isValid())
+ Path::myErrors()
+ .error(Path::tr("The module directory import %1 cannot have a version")
+ .arg(uri))
+ .handle(errorHandler);
+ version = {};
+ } else {
+ QRegularExpression moduleRe(QLatin1String(R"(\A\w+(?:\.\w+)*\Z)"));
+ auto m = moduleRe.match(uri);
+ if (!m.isValid())
+ Path::myErrors()
+ .error(Path::tr("Invalid module name in import %1").arg(uri))
+ .handle(errorHandler);
+ }
+ return Path::Root(PathRoot::Env)
+ .field(Fields::moduleIndexWithUri)
+ .key(uri)
+ .key(version.majorSymbolicString())
+ .field(Fields::moduleScope)
+ .key(version.minorString());
+}
+
+Path moduleScopePath(QString uri, QString version, ErrorHandler errorHandler)
+{
+ Version v = Version::fromString(version);
+ if (!version.isEmpty() && !(v.isValid() || v.isLatest()))
+ Path::myErrors().error(Path::tr("Invalid Version %1").arg(version)).handle(errorHandler);
+ return moduleScopePath(uri, v, errorHandler);
+}
+
+} // end namespace Paths
+
+static ErrorGroups domParsingErrors()
+{
+ static ErrorGroups res = { { DomItem::domErrorGroup, NewErrorGroup("Parsing") } };
+ return res;
+}
+
+bool CommentableDomElement::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+{
+ bool cont = true;
+ cont = cont && self.dvWrapField(visitor, Fields::comments, m_comments);
+ return cont;
+}
+
+void Component::updatePathFromOwner(Path newPath)
+{
+ DomElement::updatePathFromOwner(newPath);
+ updatePathFromOwnerMultiMap(m_enumerations, newPath.field(Fields::enumerations));
+ updatePathFromOwnerQList(m_objects, newPath.field(Fields::objects));
+}
+
+Component::Component(QString name) : CommentableDomElement(Path()), m_name(name) { }
+
+Component::Component(Path pathFromOwner) : CommentableDomElement(pathFromOwner) { }
+
+bool Component::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+{
+ bool cont = CommentableDomElement::iterateDirectSubpaths(self, visitor);
+ cont = cont && self.dvValueField(visitor, Fields::name, name());
+ cont = cont && self.dvWrapField(visitor, Fields::enumerations, m_enumerations);
+ cont = cont && self.dvWrapField(visitor, Fields::objects, m_objects);
+ cont = cont && self.dvValueField(visitor, Fields::isSingleton, isSingleton());
+ cont = cont && self.dvValueField(visitor, Fields::isCreatable, isCreatable());
+ cont = cont && self.dvValueField(visitor, Fields::isComposite, isComposite());
+ cont = cont && self.dvValueField(visitor, Fields::attachedTypeName, attachedTypeName());
+ cont = cont && self.dvReferenceField(visitor, Fields::attachedType, attachedTypePath(self));
+ return cont;
+}
+
+DomItem Component::field(DomItem &self, QStringView name)
+{
+ switch (name.length()) {
+ case 4:
+ if (name == Fields::name)
+ return self.wrapField(Fields::name, m_name);
+ break;
+ case 7:
+ if (name == Fields::objects)
+ return self.wrapField(Fields::objects, m_objects);
+ break;
+ default:
+ break;
+ }
+ return DomBase::field(self, name);
+}
+
+Path Component::addObject(const QmlObject &object, QmlObject **oPtr)
+{
+ return appendUpdatableElementInQList(pathFromOwner().field(Fields::objects), m_objects, object,
+ oPtr);
+}
+
+bool QmlComponent::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+{
+ bool cont = Component::iterateDirectSubpaths(self, visitor);
+ cont = cont && self.dvWrapField(visitor, Fields::ids, m_ids);
+ cont = cont && self.dvValueLazyField(visitor, Fields::subComponents, [this, &self]() {
+ return this->subComponents(self);
+ });
+ return cont;
+}
+
+void QmlComponent::updatePathFromOwner(Path newPath)
+{
+ Component::updatePathFromOwner(newPath);
+ updatePathFromOwnerMultiMap(m_ids, newPath.field(Fields::annotations));
+}
+
+QList<QString> QmlComponent::subComponentsNames(DomItem &self) const
+{
+ DomItem components = self.owner().field(Fields::components);
+ QSet<QString> cNames = components.keys();
+ QString myNameDot = self.pathFromOwner()[1].headName();
+ if (!myNameDot.isEmpty())
+ myNameDot += QLatin1Char('.');
+ QList<QString> subNames;
+ for (QString cName : cNames)
+ if (cName.startsWith(myNameDot)
+ && !QStringView(cName).mid(myNameDot.length()).contains(QLatin1Char('.'))
+ && !cName.isEmpty())
+ subNames.append(cName);
+ std::sort(subNames.begin(), subNames.end());
+ return subNames;
+}
+
+QList<DomItem> QmlComponent::subComponents(DomItem &self) const
+{
+ DomItem components = self.owner().field(Fields::components);
+ QList<DomItem> res;
+ for (QString cName : subComponentsNames(self))
+ for (DomItem comp : components.key(cName).values())
+ res.append(comp);
+ return res;
+}
+
+Version Version::fromString(QStringView v)
+{
+ if (v.isEmpty())
+ return Version(Latest, Latest);
+ QRegularExpression r(
+ QRegularExpression::anchoredPattern(QStringLiteral(uR"(([0-9]*)(?:\.([0-9]*))?)")));
+ auto m = r.match(v.toString());
+ if (m.hasMatch()) {
+ bool ok;
+ int majorV = m.captured(1).toInt(&ok);
+ if (!ok)
+ majorV = Version::Undefined;
+ int minorV = m.captured(2).toInt(&ok);
+ if (!ok)
+ minorV = Version::Undefined;
+ return Version(majorV, minorV);
+ }
+ return {};
+}
+
+Version::Version(qint32 majorV, qint32 minorV) : majorVersion(majorV), minorVersion(minorV) { }
+
+bool Version::isLatest() const
+{
+ return majorVersion == Latest && minorVersion == Latest;
+}
+
+bool Version::isValid() const
+{
+ return majorVersion >= 0 && minorVersion >= 0;
+}
+
+QString Version::stringValue() const
+{
+ if (isLatest())
+ return QString();
+ if (minorVersion < 0) {
+ if (majorVersion < 0)
+ return QLatin1String(".");
+ else
+ return QString::number(majorVersion);
+ }
+ if (majorVersion < 0)
+ return QLatin1String(".") + QString::number(minorVersion);
+ return QString::number(majorVersion) + QChar::fromLatin1('.') + QString::number(minorVersion);
+}
+
+bool Version::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+{
+ bool cont = true;
+ cont = cont && self.dvWrapField(visitor, Fields::majorVersion, majorVersion);
+ cont = cont && self.dvWrapField(visitor, Fields::minorVersion, minorVersion);
+ cont = cont && self.dvValueField(visitor, Fields::isLatest, isLatest());
+ cont = cont && self.dvValueField(visitor, Fields::isValid, isValid());
+ cont = cont && self.dvValueLazyField(visitor, Fields::stringValue, [this]() {
+ return this->stringValue();
+ });
+ return cont;
+}
+
+QRegularExpression Import::importRe()
+{
+ static QRegularExpression res(QRegularExpression::anchoredPattern(QStringLiteral(
+ uR"((?<uri>\w+(?:\.\w+)*)(?:\W+(?<version>[0-9]+(?:\.[0-9]*)?))?(?:\W+as\W+(?<id>\w+))?$)")));
+ return res;
+}
+
+Import Import::fromUriString(QString importStr, Version v, QString importId, ErrorHandler handler)
+{
+ if (importStr.startsWith(u"http://") || importStr.startsWith(u"https://")
+ || importStr.startsWith(u"file://")) {
+ return Import(importStr, v, importId);
+ } else {
+ auto m = importRe().match(importStr);
+ if (m.hasMatch()) {
+ if (v.majorVersion == Version::Undefined && v.minorVersion == Version::Undefined)
+ v = Version::fromString(m.captured(2));
+ else if (!m.captured(u"version").isEmpty())
+ domParsingErrors()
+ .warning(tr("Version %1 in import string '%2' overridden by explicit "
+ "version %3")
+ .arg(m.captured(2), importStr, v.stringValue()))
+ .handle(handler);
+ if (importId.isEmpty())
+ importId = m.captured(u"importId");
+ else if (!m.captured(u"importId").isEmpty())
+ domParsingErrors()
+ .warning(tr("namespace %1 in import string '%2' overridden by explicit "
+ "importId %3")
+ .arg(m.captured(u"importId"), importStr, importId))
+ .handle(handler);
+ return Import(m.captured(u"uri").trimmed(), v, importId);
+ }
+ domParsingErrors()
+ .error(tr("Unexpected uri format in import '%1'").arg(importStr))
+ .handle(handler);
+ return Import();
+ }
+}
+
+Import Import::fromFileString(QString importStr, QString baseDir, QString importId,
+ ErrorHandler handler)
+{
+ Version v;
+ if (importStr.startsWith(u"http://") || importStr.startsWith(u"https://")
+ || importStr.startsWith(u"file://"))
+ return Import(importStr, v, importId);
+ QFileInfo p(importStr);
+ if (p.isRelative())
+ p = QFileInfo(QDir(baseDir).filePath(importStr));
+ QString path = p.canonicalFilePath();
+ if (path.isEmpty()) {
+ domParsingErrors()
+ .warning(tr("Non existing directory or file referred in uri of import '%1'")
+ .arg(importStr))
+ .handle(handler);
+ path = p.filePath();
+ }
+ return Import(QLatin1String("file://") + path, v, importId);
+}
+
+bool Import::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+{
+ bool cont = true;
+ cont = cont && self.dvValueField(visitor, Fields::uri, uri);
+ cont = cont && self.dvWrapField(visitor, Fields::version, version);
+ if (!importId.isEmpty())
+ cont = cont && self.dvValueField(visitor, Fields::importId, importId);
+ if (implicit)
+ cont = cont && self.dvValueField(visitor, Fields::implicit, implicit);
+ cont = cont && self.dvWrapField(visitor, Fields::comments, comments);
+ return cont;
+}
+
+Id::Id(QString idName, Path referredObject) : name(idName), referredObjectPath(referredObject) { }
+
+bool Id::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+{
+ bool cont = true;
+ cont = cont && self.dvValueField(visitor, Fields::name, name);
+ cont = cont && self.dvReferenceField(visitor, Fields::referredObject, referredObjectPath);
+ cont = cont && self.dvWrapField(visitor, Fields::comments, comments);
+ cont = cont && self.dvWrapField(visitor, Fields::annotations, annotations);
+ return cont;
+}
+
+void Id::updatePathFromOwner(Path newPath)
+{
+ updatePathFromOwnerQList(annotations, newPath.field(Fields::annotations));
+}
+
+Path Id::addAnnotation(Path selfPathFromOwner, const QmlObject &annotation, QmlObject **aPtr)
+{
+ return appendUpdatableElementInQList(selfPathFromOwner.field(Fields::annotations), annotations,
+ annotation, aPtr);
+}
+
+QmlObject::QmlObject(Path pathFromOwner) : CommentableDomElement(pathFromOwner) { }
+
+bool QmlObject::iterateBaseDirectSubpaths(DomItem &self, DirectVisitor visitor)
+{
+ bool cont = CommentableDomElement::iterateDirectSubpaths(self, visitor);
+ if (!idStr().isEmpty())
+ cont = cont && self.dvValueField(visitor, Fields::idStr, idStr());
+ cont = cont && self.dvValueField(visitor, Fields::name, name());
+ if (!prototypePaths().isEmpty())
+ cont = cont && self.dvReferencesField(visitor, Fields::prototypes, m_prototypePaths);
+ if (nextScopePath())
+ cont = cont && self.dvReferenceField(visitor, Fields::nextScope, nextScopePath());
+ cont = cont && self.dvWrapField(visitor, Fields::propertyDefs, m_propertyDefs);
+ cont = cont && self.dvWrapField(visitor, Fields::bindings, m_bindings);
+ cont = cont && self.dvWrapField(visitor, Fields::methods, m_methods);
+ cont = cont && self.dvWrapField(visitor, Fields::children, m_children);
+ cont = cont && self.dvWrapField(visitor, Fields::annotations, m_annotations);
+ cont = cont && self.dvItemField(visitor, Fields::propertyInfos, [this, &self]() {
+ return self.subMapItem(Map(
+ pathFromOwner().field(Fields::propertyInfos),
+ [&self](DomItem &map, QString k) {
+ auto pInfo = self.propertyInfoWithName(k);
+ return map.wrap(PathEls::Key(k), pInfo);
+ },
+ [&self](DomItem &) { return self.propertyInfoNames(); },
+ QLatin1String("PropertyInfo")));
+ });
+ return cont;
+}
+
+QList<QString> QmlObject::fields() const
+{
+ static QList<QString> myFields(
+ { QString::fromUtf16(Fields::comments), QString::fromUtf16(Fields::idStr),
+ QString::fromUtf16(Fields::name), QString::fromUtf16(Fields::prototypes),
+ QString::fromUtf16(Fields::nextScope), QString::fromUtf16(Fields::propertyDefs),
+ QString::fromUtf16(Fields::bindings), QString::fromUtf16(Fields::methods),
+ QString::fromUtf16(Fields::children), QString::fromUtf16(Fields::annotations),
+ QString::fromUtf16(Fields::propertyInfos) });
+ return myFields;
+}
+
+bool QmlObject::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+{
+ bool cont = iterateBaseDirectSubpaths(self, visitor);
+ cont = cont && self.dvValueLazyField(visitor, Fields::defaultPropertyName, [this, &self]() {
+ return defaultPropertyName(self);
+ });
+ return cont;
+}
+
+DomItem QmlObject::field(DomItem &self, QStringView name)
+{
+ switch (name.size()) {
+ case 4:
+ if (name == Fields::name)
+ return self.subDataItem(PathEls::Field(Fields::name), this->name());
+ break;
+ case 5:
+ if (name == Fields::idStr) {
+ if (idStr().isEmpty())
+ return DomItem();
+ return self.subDataItem(PathEls::Field(Fields::idStr), idStr());
+ }
+ break;
+ case 7:
+ if (name == Fields::methods)
+ return self.wrapField(Fields::methods, m_methods);
+ break;
+ case 8:
+ switch (name.at(1).unicode()) {
+ case u'i':
+ if (name == Fields::bindings)
+ return self.wrapField(Fields::bindings, m_bindings);
+ break;
+ case u'o':
+ if (name == Fields::comments)
+ return CommentableDomElement::field(self, name);
+ break;
+ case u'h':
+ if (name == Fields::children)
+ return self.wrapField(Fields::children, m_children);
+ break;
+ default:
+ break;
+ }
+ break;
+ case 9:
+ if (name == Fields::nextScope) {
+ if (nextScopePath())
+ return self.subReferenceItem(PathEls::Field(Fields::nextScope), nextScopePath());
+ else
+ return DomItem();
+ }
+ break;
+ case 10:
+ if (name == Fields::prototypes) {
+ if (prototypePaths().isEmpty())
+ return DomItem();
+ return self.subReferencesItem(PathEls::Field(Fields::prototypes), m_prototypePaths);
+ }
+ break;
+ case 11:
+ if (name == Fields::annotations)
+ return self.wrapField(Fields::annotations, m_annotations);
+ break;
+ case 12:
+ return self.wrapField(Fields::propertyDefs, m_propertyDefs);
+ break;
+ case 13:
+ if (name == Fields::propertyInfos)
+ return self.subMapItem(Map(
+ pathFromOwner().field(Fields::propertyInfos),
+ [self](DomItem &map, QString k) mutable {
+ auto pInfo = self.propertyInfoWithName(k);
+ return map.wrap(PathEls::Key(k), pInfo);
+ },
+ [self](DomItem &) mutable { return self.propertyInfoNames(); },
+ QLatin1String("PropertyInfo")));
+ break;
+ case 19:
+ if (name == Fields::defaultPropertyName)
+ return self.subDataItem(PathEls::Field(Fields::defaultPropertyName),
+ defaultPropertyName(self));
+ break;
+ default:
+ break;
+ }
+ static QStringList knownLookups({ QString::fromUtf16(Fields::fileLocationsTree) });
+ if (!knownLookups.contains(name))
+ qCWarning(domLog()) << "Asked non existing field " << name << " in QmlObject "
+ << pathFromOwner();
+ return DomItem();
+}
+
+void QmlObject::updatePathFromOwner(Path newPath)
+{
+ DomElement::updatePathFromOwner(newPath);
+ updatePathFromOwnerMultiMap(m_propertyDefs, newPath.field(Fields::propertyDefs));
+ updatePathFromOwnerMultiMap(m_bindings, newPath.field(Fields::bindings));
+ updatePathFromOwnerMultiMap(m_methods, newPath.field(Fields::methods));
+ updatePathFromOwnerQList(m_children, newPath.field(Fields::children));
+ updatePathFromOwnerQList(m_annotations, newPath.field(Fields::annotations));
+}
+
+QString QmlObject::localDefaultPropertyName() const
+{
+ if (!m_defaultPropertyName.isEmpty())
+ return m_defaultPropertyName;
+ for (const PropertyDefinition &pDef : m_propertyDefs)
+ if (pDef.isDefaultMember)
+ return pDef.name;
+ return QString();
+}
+
+QString QmlObject::defaultPropertyName(DomItem &self) const
+{
+ QString dProp = localDefaultPropertyName();
+ if (!dProp.isEmpty())
+ return dProp;
+ QString res = QStringLiteral(u"data");
+ self.visitPrototypeChain(
+ [&res](DomItem &obj) {
+ if (const QmlObject *objPtr = obj.as<QmlObject>()) {
+ QString dProp = objPtr->localDefaultPropertyName();
+ if (!dProp.isEmpty()) {
+ res = dProp;
+ return false;
+ }
+ }
+ return true;
+ },
+ VisitPrototypesOption::SkipFirst);
+ return res;
+}
+
+bool QmlObject::iterateSubOwners(DomItem &self, function_ref<bool(DomItem &)> visitor) const
+{
+ bool cont = self.field(Fields::bindings).visitKeys([visitor](QString, DomItem &bs) {
+ return bs.visitIndexes([visitor](DomItem &b) {
+ DomItem v = b.field(Fields::value);
+ if (std::shared_ptr<ScriptExpression> vPtr = v.ownerAs<ScriptExpression>()) {
+ if (!visitor(v))
+ return false;
+ return v.iterateSubOwners(visitor); // currently not needed, avoid?
+ }
+ return true;
+ });
+ });
+ cont = cont && self.field(Fields::children).visitIndexes([visitor](DomItem &qmlObj) {
+ if (const QmlObject *qmlObjPtr = qmlObj.as<QmlObject>()) {
+ return qmlObjPtr->iterateSubOwners(qmlObj, visitor);
+ }
+ Q_ASSERT(false);
+ return true;
+ });
+ return cont;
+}
+
+MutableDomItem QmlObject::addPropertyDef(MutableDomItem &self, PropertyDefinition propertyDef,
+ AddOption option)
+{
+ Path p = addPropertyDef(propertyDef, option);
+ if (p.last().headIndex(0) > 1)
+ self.owningItemPtr()->addErrorLocal(domParsingErrors().error(
+ tr("Repeated PropertyDefinition with name %1").arg(propertyDef.name)));
+ return self.owner().path(p);
+}
+
+MutableDomItem QmlObject::addBinding(MutableDomItem &self, Binding binding, AddOption option)
+{
+ Path p = addBinding(binding, option);
+ if (p && p.last().headIndex(0) > 1)
+ self.owningItemPtr()->addErrorLocal(
+ domParsingErrors().error(tr("Repeated binding with name %1").arg(binding.name())));
+ return self.owner().path(p);
+}
+
+MutableDomItem QmlObject::addMethod(MutableDomItem &self, MethodInfo functionDef, AddOption option)
+{
+ Path p = addMethod(functionDef, option);
+ if (p.last().headIndex(0) > 1)
+ self.owningItemPtr()->addErrorLocal(
+ domParsingErrors().error(tr("Repeated Method with name %1").arg(functionDef.name)));
+ return self.owner().path(p);
+}
+
+Binding::Binding(QString name, std::unique_ptr<BindingValue> value, BindingType bindingType)
+ : m_bindingType(bindingType), m_name(name), m_value(std::move(value))
+{
+}
+
+Binding::Binding(QString name, std::shared_ptr<ScriptExpression> value, BindingType bindingType)
+ : Binding(name, std::make_unique<BindingValue>(value), bindingType)
+{
+}
+
+Binding::Binding(QString name, QString scriptCode, BindingType bindingType)
+ : Binding(name,
+ std::make_unique<BindingValue>(std::shared_ptr<ScriptExpression>(new ScriptExpression(
+ scriptCode, ScriptExpression::ExpressionType::BindingExpression))),
+ bindingType)
+{
+}
+
+Binding::Binding(QString name, QmlObject value, BindingType bindingType)
+ : Binding(name, std::make_unique<BindingValue>(value), bindingType)
+{
+}
+
+Binding::Binding(QString name, QList<QmlObject> value, BindingType bindingType)
+ : Binding(name, std::make_unique<BindingValue>(value), bindingType)
+{
+}
+
+Binding::Binding(const Binding &o)
+ : m_bindingType(o.m_bindingType),
+ m_name(o.m_name),
+ m_annotations(o.m_annotations),
+ m_comments(o.m_comments)
+{
+ if (o.m_value) {
+ m_value = std::make_unique<BindingValue>(*o.m_value);
+ }
+}
+
+Binding::~Binding() { }
+
+Binding &Binding::operator=(const Binding &o)
+{
+ m_name = o.m_name;
+ m_bindingType = o.m_bindingType;
+ m_annotations = o.m_annotations;
+ m_comments = o.m_comments;
+ if (o.m_value) {
+ if (!m_value)
+ m_value = std::make_unique<BindingValue>(*o.m_value);
+ else
+ *m_value = *o.m_value;
+ } else {
+ m_value.reset();
+ }
+ return *this;
+}
+
+bool Binding::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+{
+ bool cont = true;
+ cont = cont && self.dvValueField(visitor, Fields::name, m_name);
+ cont = cont && self.dvValueField(visitor, Fields::isSignalHandler, isSignalHandler());
+ if (!m_value)
+ cont = cont && visitor(PathEls::Field(Fields::value), []() { return DomItem(); });
+ else
+ cont = cont && self.dvItemField(visitor, Fields::value, [this, &self]() {
+ return m_value->value(self);
+ });
+ cont = cont && self.dvValueField(visitor, Fields::bindingType, int(m_bindingType));
+ cont = cont && self.dvWrapField(visitor, Fields::comments, m_comments);
+ cont = cont && self.dvValueLazyField(visitor, Fields::preCode, [this]() {
+ return this->preCode();
+ });
+ cont = cont && self.dvValueLazyField(visitor, Fields::postCode, [this]() {
+ return this->postCode();
+ });
+ cont = cont && self.dvWrapField(visitor, Fields::annotations, m_annotations);
+ return cont;
+}
+
+DomItem Binding::valueItem(DomItem &self) const
+{
+ if (!m_value)
+ return DomItem();
+ return m_value->value(self);
+}
+
+BindingValueKind Binding::valueKind() const
+{
+ if (!m_value)
+ return BindingValueKind::Empty;
+ return m_value->kind;
+}
+
+QmlObject const *Binding::objectValue() const
+{
+ if (valueKind() == BindingValueKind::Object)
+ return &(m_value->object);
+ return nullptr;
+}
+
+QmlObject *Binding::objectValue()
+{
+ if (valueKind() == BindingValueKind::Object)
+ return &(m_value->object);
+ return nullptr;
+}
+
+QList<QmlObject> const *Binding::arrayValue() const
+{
+ if (valueKind() == BindingValueKind::Array)
+ return &(m_value->array);
+ return nullptr;
+}
+
+QList<QmlObject> *Binding::arrayValue()
+{
+ if (valueKind() == BindingValueKind::Array)
+ return &(m_value->array);
+ return nullptr;
+}
+
+std::shared_ptr<ScriptExpression> Binding::scriptExpressionValue() const
+{
+ if (valueKind() == BindingValueKind::ScriptExpression)
+ return m_value->scriptExpression;
+ return nullptr;
+}
+
+std::shared_ptr<ScriptExpression> Binding::scriptExpressionValue()
+{
+ if (valueKind() == BindingValueKind::ScriptExpression)
+ return m_value->scriptExpression;
+ return nullptr;
+}
+
+Path Binding::addAnnotation(Path selfPathFromOwner, const QmlObject &annotation, QmlObject **aPtr)
+{
+ return appendUpdatableElementInQList(selfPathFromOwner.field(Fields::annotations),
+ m_annotations, annotation, aPtr);
+}
+
+void Binding::updatePathFromOwner(Path newPath)
+{
+ Path base = newPath.field(Fields::annotations);
+ if (m_value)
+ m_value->updatePathFromOwner(newPath.field(Fields::value));
+ updatePathFromOwnerQList(m_annotations, newPath.field(Fields::annotations));
+}
+
+bool QmltypesComponent::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+{
+ bool cont = Component::iterateDirectSubpaths(self, visitor);
+ cont = cont && self.dvWrapField(visitor, Fields::exports, m_exports);
+ cont = cont && self.dvValueField(visitor, Fields::metaRevisions, m_metaRevisions);
+ if (!fileName().isEmpty())
+ cont = cont && self.dvValueField(visitor, Fields::fileName, fileName()); // remove?
+ return cont;
+}
+
+Export Export::fromString(Path source, QStringView exp, Path typePath, ErrorHandler h)
+{
+ Export res;
+ res.exportSourcePath = source;
+ res.typePath = typePath;
+ int slashIdx = exp.indexOf(QLatin1Char('/'));
+ int spaceIdx = exp.indexOf(QLatin1Char(' '));
+ if (spaceIdx == -1)
+ spaceIdx = exp.length();
+ else
+ res.version = Version::fromString(exp.mid(spaceIdx + 1));
+ if (!res.version.isValid())
+ domParsingErrors()
+ .error(tr("Expected string literal to contain 'Package/Name major.minor' "
+ "or 'Name major.minor' not '%1'.")
+ .arg(exp))
+ .handle(h);
+ QString package;
+ if (slashIdx != -1)
+ res.uri = exp.left(slashIdx).toString();
+ res.typeName = exp.mid(slashIdx + 1, spaceIdx - (slashIdx + 1)).toString();
+ return res;
+}
+
+bool AttributeInfo::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+{
+ bool cont = true;
+ cont = cont && self.dvValueField(visitor, Fields::name, name);
+ cont = cont && self.dvValueField(visitor, Fields::access, int(access));
+ cont = cont && self.dvValueField(visitor, Fields::typeName, typeName);
+ cont = cont && self.dvValueField(visitor, Fields::isReadonly, isReadonly);
+ cont = cont && self.dvValueField(visitor, Fields::isList, isList);
+ cont = cont && self.dvWrapField(visitor, Fields::comments, comments);
+ cont = cont && self.dvWrapField(visitor, Fields::annotations, annotations);
+ return cont;
+}
+
+Path AttributeInfo::addAnnotation(Path selfPathFromOwner, const QmlObject &annotation,
+ QmlObject **aPtr)
+{
+ return appendUpdatableElementInQList(selfPathFromOwner.field(Fields::annotations), annotations,
+ annotation, aPtr);
+}
+
+void AttributeInfo::updatePathFromOwner(Path newPath)
+{
+ Path base = newPath.field(Fields::annotations);
+ updatePathFromOwnerQList(annotations, newPath.field(Fields::annotations));
+}
+
+bool EnumDecl::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+{
+ bool cont = CommentableDomElement::iterateDirectSubpaths(self, visitor);
+ cont = cont && self.dvValueField(visitor, Fields::name, name());
+ cont = cont && self.dvWrapField(visitor, Fields::values, m_values);
+ cont = cont && self.dvWrapField(visitor, Fields::annotations, m_annotations);
+ return cont;
+}
+
+void EnumDecl::updatePathFromOwner(Path newPath)
+{
+ DomElement::updatePathFromOwner(newPath);
+ updatePathFromOwnerQList(m_annotations, newPath.field(Fields::annotations));
+}
+
+QList<QmlObject> EnumDecl::annotations() const
+{
+ return m_annotations;
+}
+
+void EnumDecl::setAnnotations(QList<QmlObject> annotations)
+{
+ m_annotations = annotations;
+}
+
+Path EnumDecl::addAnnotation(const QmlObject &annotation, QmlObject **aPtr)
+{
+ return appendUpdatableElementInQList(pathFromOwner().field(Fields::annotations), m_annotations,
+ annotation, aPtr);
+}
+
+QList<Path> ImportScope::allSources(DomItem &self) const
+{
+ DomItem env = self.environment();
+ Path selfPath = self.canonicalPath().field(Fields::allSources);
+ RefCacheEntry cached = RefCacheEntry::forPath(env, selfPath);
+ if (cached.cached == RefCacheEntry::Cached::All)
+ return cached.canonicalPaths;
+ QList<Path> res;
+ QSet<Path> knownPaths;
+ QList<Path> toDo(m_importSourcePaths.rbegin(), m_importSourcePaths.rend());
+ while (!toDo.isEmpty()) {
+ Path pNow = toDo.takeLast();
+ if (knownPaths.contains(pNow))
+ continue;
+ knownPaths.insert(pNow);
+ res.append(pNow);
+ DomItem sourceBase = env.path(pNow);
+ for (DomItem autoExp : sourceBase.field(Fields::autoExports).values()) {
+ if (const ModuleAutoExport *autoExpPtr = autoExp.as<ModuleAutoExport>()) {
+ Path newSource;
+ if (autoExpPtr->inheritVersion) {
+ Version v = autoExpPtr->import.version;
+ DomItem sourceVersion = sourceBase.field(Fields::version);
+ if (const Version *sourceVersionPtr = sourceVersion.as<Version>()) {
+ if (v.majorVersion < 0)
+ v.majorVersion = sourceVersionPtr->majorVersion;
+ if (v.minorVersion < 0)
+ v.minorVersion = sourceVersionPtr->minorVersion;
+ } else {
+ qWarning() << "autoExport with inherited version " << autoExp
+ << " but missing version in source" << pNow;
+ }
+ Import toImport(autoExpPtr->import.uri, v);
+ newSource = toImport.importedPath();
+ } else {
+ newSource = autoExpPtr->import.importedPath();
+ }
+ if (newSource && !knownPaths.contains(newSource))
+ toDo.append(newSource);
+ } else {
+ qWarning() << "expected ModuleAutoExport not " << autoExp.internalKindStr()
+ << "looking up autoExports of" << sourceBase;
+ Q_ASSERT(false);
+ }
+ }
+ }
+ RefCacheEntry::addForPath(env, selfPath, RefCacheEntry { RefCacheEntry::Cached::All, res });
+ return res;
+}
+
+bool ImportScope::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+{
+ bool cont = true;
+ cont = cont && self.dvReferencesField(visitor, Fields::importSources, m_importSourcePaths);
+ cont = cont && self.dvItemField(visitor, Fields::allSources, [this, &self]() -> DomItem {
+ return self.subListItem(List::fromQList<Path>(
+ self.pathFromOwner().field(Fields::allSources), allSources(self),
+ [](DomItem &list, const PathEls::PathComponent &p, const Path &el) {
+ return list.subDataItem(p, el.toString());
+ }));
+ });
+ cont = cont && self.dvWrapField(visitor, Fields::qualifiedImports, m_subImports);
+ cont = cont && self.dvItemField(visitor, Fields::imported, [this, &self]() -> DomItem {
+ return self.subMapItem(Map(
+ self.pathFromOwner().field(Fields::imported),
+ [this, &self](DomItem &map, QString key) {
+ return map.subListItem(List::fromQList<DomItem>(
+ map.pathFromOwner().key(key), importedItemsWithName(self, key),
+ [](DomItem &, const PathEls::PathComponent &, DomItem &el) {
+ return el;
+ }));
+ },
+ [this, &self](DomItem &) { return this->importedNames(self); },
+ QLatin1String("List<Export>")));
+ });
+ return cont;
+}
+
+bool PropertyInfo::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+{
+ bool cont = true;
+ cont = cont && self.dvValueField(visitor, Fields::propertyDefs, propertyDefs);
+ cont = cont && self.dvValueField(visitor, Fields::bindings, bindings);
+ return cont;
+}
+
+BindingValue::BindingValue() : kind(BindingValueKind::Empty) { }
+
+BindingValue::BindingValue(const QmlObject &o) : kind(BindingValueKind::Object)
+{
+ new (&object) QmlObject(o);
+}
+
+BindingValue::BindingValue(std::shared_ptr<ScriptExpression> o)
+ : kind(BindingValueKind::ScriptExpression)
+{
+ new (&scriptExpression) std::shared_ptr<ScriptExpression>(o);
+}
+
+BindingValue::BindingValue(const QList<QmlObject> &l) : kind(BindingValueKind::Array)
+{
+ new (&array) QList<QmlObject>(l);
+}
+
+BindingValue::~BindingValue()
+{
+ clearValue();
+}
+
+BindingValue::BindingValue(const BindingValue &o) : kind(o.kind)
+{
+ switch (o.kind) {
+ case BindingValueKind::Empty:
+ break;
+ case BindingValueKind::Object:
+ new (&object) QmlObject(o.object);
+ break;
+ case BindingValueKind::ScriptExpression:
+ new (&scriptExpression) std::shared_ptr<ScriptExpression>(o.scriptExpression);
+ break;
+ case BindingValueKind::Array:
+ new (&array) QList<QmlObject>(o.array);
+ }
+}
+
+BindingValue &BindingValue::operator=(const BindingValue &o)
+{
+ clearValue();
+ kind = o.kind;
+ switch (o.kind) {
+ case BindingValueKind::Empty:
+ break;
+ case BindingValueKind::Object:
+ new (&object) QmlObject(o.object);
+ break;
+ case BindingValueKind::ScriptExpression:
+ new (&scriptExpression) std::shared_ptr<ScriptExpression>(o.scriptExpression);
+ break;
+ case BindingValueKind::Array:
+ new (&array) QList<QmlObject>(o.array);
+ }
+ return *this;
+}
+
+DomItem BindingValue::value(DomItem &binding)
+{
+ switch (kind) {
+ case BindingValueKind::Empty:
+ break;
+ case BindingValueKind::Object:
+ return binding.copy(&object);
+ case BindingValueKind::ScriptExpression:
+ return binding.subOwnerItem(PathEls::Field(Fields::value), scriptExpression);
+ case BindingValueKind::Array:
+ return binding.subListItem(List::fromQListRef<QmlObject>(
+ binding.pathFromOwner().field(u"value"), array,
+ [binding](DomItem &self, const PathEls::PathComponent &, QmlObject &obj) {
+ return self.copy(&obj);
+ }));
+ }
+ return DomItem();
+}
+
+void BindingValue::updatePathFromOwner(Path newPath)
+{
+ switch (kind) {
+ case BindingValueKind::Empty:
+ break;
+ case BindingValueKind::Object:
+ object.updatePathFromOwner(newPath);
+ break;
+ case BindingValueKind::ScriptExpression:
+ break;
+ case BindingValueKind::Array:
+ updatePathFromOwnerQList(array, newPath);
+ break;
+ }
+}
+
+void BindingValue::clearValue()
+{
+ switch (kind) {
+ case BindingValueKind::Empty:
+ break;
+ case BindingValueKind::Object:
+ object.~QmlObject();
+ break;
+ case BindingValueKind::ScriptExpression:
+ scriptExpression.~shared_ptr();
+ break;
+ case BindingValueKind::Array:
+ array.~QList<QmlObject>();
+ break;
+ }
+ kind = BindingValueKind::Empty;
+}
+
+ScriptExpression::ScriptExpression(const ScriptExpression &e) : OwningItem(e)
+{
+ QMutexLocker l(mutex());
+ m_expressionType = e.m_expressionType;
+ m_engine = e.m_engine;
+ m_ast = e.m_ast;
+ if (m_codeStr.isEmpty()) {
+ m_code = e.m_code;
+ } else {
+ m_codeStr = e.m_codeStr;
+ m_code = m_codeStr;
+ }
+ m_localOffset = e.m_localOffset;
+ m_astComments = e.m_astComments;
+}
+
+std::shared_ptr<ScriptExpression> ScriptExpression::copyWithUpdatedCode(DomItem &self,
+ QString code) const
+{
+ std::shared_ptr<ScriptExpression> copy = makeCopy(self);
+ DomItem container = self.containingObject();
+ QString preCodeStr = container.field(Fields::preCode).value().toString(m_preCode.toString());
+ QString postCodeStr = container.field(Fields::postCode).value().toString(m_postCode.toString());
+ copy->setCode(code, preCodeStr, postCodeStr);
+ return copy;
+}
+
+bool ScriptExpression::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+{
+ bool cont = OwningItem::iterateDirectSubpaths(self, visitor);
+ cont = cont && self.dvValueField(visitor, Fields::code, code());
+ if (!preCode().isEmpty())
+ cont = cont
+ && self.dvValueField(visitor, Fields::preCode, preCode(),
+ ConstantData::Options::MapIsMap);
+ if (!postCode().isEmpty())
+ cont = cont
+ && self.dvValueField(visitor, Fields::postCode, postCode(),
+ ConstantData::Options::MapIsMap);
+ cont = cont
+ && self.dvValueLazyField(
+ visitor, Fields::localOffset,
+ [this]() { return locationToData(localOffset()); },
+ ConstantData::Options::MapIsMap);
+ cont = cont && self.dvValueLazyField(visitor, Fields::astRelocatableDump, [this]() {
+ return astRelocatableDump();
+ });
+ cont = cont && self.dvValueField(visitor, Fields::expressionType, int(expressionType()));
+ return cont;
+}
+
+class FirstNodeVisitor : public VisitAll
+{
+public:
+ quint32 minStart = 0;
+ quint32 maxEnd = ~quint32(0);
+ AST::Node *firstNodeInRange = nullptr;
+
+ FirstNodeVisitor(quint32 minStart = 0, quint32 maxEnd = ~quint32(0))
+ : minStart(minStart), maxEnd(maxEnd)
+ {
+ }
+
+ bool preVisit(AST::Node *n) override
+ {
+ if (!VisitAll::uiKinds().contains(n->kind)) {
+ quint32 start = n->firstSourceLocation().begin();
+ quint32 end = n->lastSourceLocation().end();
+ if (!firstNodeInRange && minStart <= start && end <= maxEnd && start < end)
+ firstNodeInRange = n;
+ }
+ return !firstNodeInRange;
+ }
+};
+
+AST::Node *firstNodeInRange(AST::Node *n, quint32 minStart = 0, quint32 maxEnd = ~quint32(0))
+{
+ FirstNodeVisitor visitor(minStart, maxEnd);
+ AST::Node::accept(n, &visitor);
+ return visitor.firstNodeInRange;
+}
+
+void ScriptExpression::setCode(QString code, QString preCode, QString postCode)
+{
+ m_codeStr = code;
+ if (!preCode.isEmpty() || !postCode.isEmpty())
+ m_codeStr = preCode + code + postCode;
+ m_code = QStringView(m_codeStr).mid(preCode.length(), code.length());
+ m_preCode = QStringView(m_codeStr).mid(0, preCode.length());
+ m_postCode = QStringView(m_codeStr).mid(preCode.length() + code.length(), postCode.length());
+ m_engine = nullptr;
+ m_ast = nullptr;
+ m_localOffset = SourceLocation();
+ if (!m_code.isEmpty()) {
+ IndentInfo preChange(m_preCode, 4);
+ m_localOffset.offset = m_preCode.length();
+ m_localOffset.length = m_code.length();
+ m_localOffset.startColumn = preChange.trailingString.length();
+ m_localOffset.startLine = preChange.nNewlines;
+ m_engine = std::shared_ptr<QQmlJS::Engine>(new QQmlJS::Engine);
+ m_astComments = std::shared_ptr<AstComments>(new AstComments(m_engine));
+ QQmlJS::Lexer lexer(m_engine.get());
+ lexer.setCode(m_codeStr, /*lineno = */ 1, /*qmlMode=*/true);
+ QQmlJS::Parser parser(m_engine.get());
+ if (!parser.parseScript())
+ addErrorLocal(domParsingErrors().error(tr("Parsing of code failed")));
+ for (DiagnosticMessage msg : parser.diagnosticMessages()) {
+ ErrorMessage err = domParsingErrors().errorMessage(msg);
+ err.location.offset -= m_localOffset.offset;
+ err.location.startLine -= m_localOffset.startLine;
+ if (err.location.startLine == 1)
+ err.location.startColumn -= m_localOffset.startColumn;
+ addErrorLocal(err);
+ }
+ m_ast = parser.rootNode();
+ if (AST::Program *programPtr = AST::cast<AST::Program *>(m_ast)) {
+ m_ast = programPtr->statements;
+ }
+ if (!m_preCode.isEmpty())
+ m_ast = firstNodeInRange(m_ast, m_preCode.length(),
+ m_preCode.length() + m_code.length());
+ if (m_expressionType != ExpressionType::FunctionBody) {
+ if (AST::StatementList *sList = AST::cast<AST::StatementList *>(m_ast)) {
+ if (!sList->next)
+ m_ast = sList->statement;
+ }
+ }
+ AstComments::collectComments(m_engine, m_ast, m_astComments, MutableDomItem(), nullptr);
+ }
+}
+
+void ScriptExpression::astDumper(Sink s, AstDumperOptions options) const
+{
+ astNodeDumper(s, ast(), options, 1, 0, [this](SourceLocation astL) {
+ SourceLocation l = this->locationToLocal(astL);
+ return this->code().mid(l.offset, l.length);
+ });
+}
+
+QString ScriptExpression::astRelocatableDump() const
+{
+ return dumperToString([this](Sink s) {
+ this->astDumper(s, AstDumperOption::NoLocations | AstDumperOption::SloppyCompare);
+ });
+}
+
+SourceLocation ScriptExpression::globalLocation(DomItem &self) const
+{
+ if (const FileLocations *fLocPtr = FileLocations::fileLocationsPtr(self)) {
+ return fLocPtr->regions.value(QString(), fLocPtr->fullRegion);
+ }
+ return SourceLocation();
+}
+
+bool MethodInfo::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+{
+ bool cont = AttributeInfo::iterateDirectSubpaths(self, visitor);
+ cont = cont && self.dvWrapField(visitor, Fields::parameters, parameters);
+ cont = cont && self.dvValueField(visitor, Fields::methodType, int(methodType));
+ if (!typeName.isEmpty())
+ cont = cont && self.dvReferenceField(visitor, Fields::type, typePath(self));
+ if (methodType == MethodType::Method) {
+ cont = cont && self.dvValueField(visitor, Fields::preCode, preCode(self));
+ cont = cont && self.dvValueField(visitor, Fields::postCode, postCode(self));
+ }
+ if (body)
+ cont = cont && self.dvWrapField(visitor, Fields::body, body);
+ return cont;
+}
+
+QString MethodInfo::preCode(DomItem &) const
+{
+ return QLatin1String("function(){");
+}
+
+QString MethodInfo::postCode(DomItem &) const
+{
+ return QLatin1String("\n}\n");
+}
+
+bool MethodParameter::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+{
+ bool cont = true;
+ cont = cont && self.dvValueField(visitor, Fields::name, name);
+ if (!typeName.isEmpty()) {
+ cont = cont
+ && self.dvReferenceField(visitor, Fields::type, Paths::lookupCppTypePath(typeName));
+ cont = cont && self.dvValueField(visitor, Fields::typeName, typeName);
+ }
+ cont = cont && self.dvValueField(visitor, Fields::isPointer, isPointer);
+ cont = cont && self.dvValueField(visitor, Fields::isReadonly, isReadonly);
+ cont = cont && self.dvValueField(visitor, Fields::isList, isList);
+ cont = cont && self.dvWrapField(visitor, Fields::defaultValue, defaultValue);
+ if (!annotations.isEmpty())
+ cont = cont && self.dvWrapField(visitor, Fields::annotations, annotations);
+ cont = cont && self.dvWrapField(visitor, Fields::comments, comments);
+ return cont;
+}
+
+bool EnumItem::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+{
+ bool cont = true;
+ cont = cont && self.dvValueField(visitor, Fields::name, name());
+ cont = cont && self.dvValueField(visitor, Fields::value, value());
+ cont = cont && self.dvWrapField(visitor, Fields::comments, m_comments);
+ return cont;
+}
+
+} // end namespace Dom
+} // end namespace QQmlJS
+
+QT_END_NAMESPACE