aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmldom/qqmldomitem.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qmldom/qqmldomitem.cpp')
-rw-r--r--src/qmldom/qqmldomitem.cpp1903
1 files changed, 1030 insertions, 873 deletions
diff --git a/src/qmldom/qqmldomitem.cpp b/src/qmldom/qqmldomitem.cpp
index e3f871acf0..b885422c1d 100644
--- a/src/qmldom/qqmldomitem.cpp
+++ b/src/qmldom/qqmldomitem.cpp
@@ -1,5 +1,9 @@
// Copyright (C) 2020 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
+#include "qqmldomattachedinfo_p.h"
+#include "qqmldomconstants_p.h"
+#include "qqmldomitem_p.h"
+#include "qqmldompath_p.h"
#include "qqmldomtop_p.h"
#include "qqmldomelements_p.h"
#include "qqmldomexternalitems_p.h"
@@ -11,6 +15,8 @@
#include "qqmldomcompare_p.h"
#include "qqmldomastdumper_p.h"
#include "qqmldomlinewriter_p.h"
+#include "qqmldom_utils_p.h"
+#include "qqmldomscriptelements_p.h"
#include <QtQml/private/qqmljslexer_p.h>
#include <QtQml/private/qqmljsparser_p.h>
@@ -32,6 +38,8 @@
#include <QtCore/QScopeGuard>
#include <QtCore/QtGlobal>
#include <QtCore/QTimeZone>
+#include <optional>
+#include <type_traits>
QT_BEGIN_NAMESPACE
@@ -41,6 +49,37 @@ namespace Dom {
Q_LOGGING_CATEGORY(writeOutLog, "qt.qmldom.writeOut", QtWarningMsg);
static Q_LOGGING_CATEGORY(refLog, "qt.qmldom.ref", QtWarningMsg);
+template<class... TypeList>
+struct CheckDomElementT;
+
+template<class... Ts>
+struct CheckDomElementT<std::variant<Ts...>> : std::conjunction<IsInlineDom<Ts>...>
+{
+};
+
+/*!
+ \internal
+ \class QQmljs::Dom::ElementT
+
+ \brief A variant that contains all the Dom elements that an DomItem can contain.
+
+ Types in this variant are divided in two categories: normal Dom elements and internal Dom
+ elements.
+ The first ones are inheriting directly or indirectly from DomBase, and are the usual elements
+ that a DomItem can wrap around, like a QmlFile or an QmlObject. They should all appear in
+ ElementT as pointers, e.g. QmlFile*.
+ The internal Dom elements are a little bit special. They appear in ElementT without pointer, do
+ not inherit from DomBase \b{but} should behave like a smart DomBase-pointer. That is, they should
+ dereference as if they were a DomBase* pointing to a normal DomElement by implementing
+ operator->() and operator*().
+ Adding types here that are neither inheriting from DomBase nor implementing a smartpointer to
+ DomBase will throw compilation errors in the std::visit()-calls on this type.
+*/
+static_assert(CheckDomElementT<ElementT>::value,
+ "Types in ElementT must either be a pointer to a class inheriting "
+ "from DomBase or (for internal Dom structures) implement a smart "
+ "pointer pointing to a class inheriting from DomBase");
+
using std::shared_ptr;
/*!
\internal
@@ -59,17 +98,36 @@ The subclass *must* have a
\endcode
entry with its kind to enable casting usng the DomItem::as DomItem::ownerAs templates.
-The minimal overload set to be usable is:
+The minimal overload set to be usable consists of following methods:
+\list
+\li \c{kind()} returns the kind of the current element:
+\code
+ Kind kind() const override { return kindValue; }
+\endcode
+
+\li \c{pathFromOwner()} returns the path from the owner to the current element
\code
- Kind kind() const override { return kindValue; } // returns the kind of the current element
- Path pathFromOwner(DomItem &self) const override; // returns the path from the owner to the
-current element Path canonicalPath(DomItem &self) const override; // returns the path from virtual
-bool iterateDirectSubpaths(DomItem &self, function_ref<bool(Path, DomItem)>) const = 0; // iterates
-the *direct* subpaths, returns false if a quick end was requested \endcode But you probably want to
-subclass either DomElement of OwningItem for your element. DomElement stores its pathFromOwner, and
-computes the canonicalPath from it and its owner. OwningItem is the unit for updates to the Dom
-model, exposed changes always change at least one OwningItem. They have their lifetime handled with
-shared_ptr and own (i.e. are responsible of freeing) other items in them.
+ Path pathFromOwner(const DomItem &self) const override;
+\endcode
+
+\li \c{canonicalPath()} returns the path
+\code
+ Path canonicalPath(const DomItem &self) const override;
+\endcode
+
+\li \c{iterateDirectSubpaths} iterates the *direct* subpaths/children and returns false if a quick
+end was requested:
+\code
+bool iterateDirectSubpaths(const DomItem &self, function_ref<bool(Path, DomItem)>) const = 0;
+\endcode
+
+\endlist
+
+But you probably want to subclass either \c DomElement or \c OwningItem for your element. \c
+DomElement stores its \c pathFromOwner, and computes the \c canonicalPath from it and its owner. \c
+OwningItem is the unit for updates to the Dom model, exposed changes always change at least one \c
+OwningItem. They have their lifetime handled with \c shared_ptr and own (i.e. are responsible of
+freeing) other items in them.
\sa QQml::Dom::DomItem, QQml::Dom::DomElement, QQml::Dom::OwningItem
*/
@@ -170,20 +228,7 @@ bool domTypeIsScope(DomType k)
}
}
-QCborValue locationToData(SourceLocation loc, QStringView strValue)
-{
- QCborMap res({
- {QStringLiteral(u"offset"), loc.offset},
- {QStringLiteral(u"length"), loc.length},
- {QStringLiteral(u"startLine"), loc.startLine},
- {QStringLiteral(u"startColumn"), loc.startColumn}
- });
- if (!strValue.isEmpty())
- res.insert(QStringLiteral(u"strValue"), QCborValue(strValue));
- return res;
-}
-
-QString DomBase::canonicalFilePath(DomItem &self) const
+QString DomBase::canonicalFilePath(const DomItem &self) const
{
auto parent = containingObject(self);
if (parent)
@@ -191,21 +236,21 @@ QString DomBase::canonicalFilePath(DomItem &self) const
return QString();
}
-void DomBase::writeOut(DomItem &self, OutWriter &) const
+void DomBase::writeOut(const DomItem &self, OutWriter &) const
{
qCWarning(writeOutLog) << "Ignoring unsupported writeOut for " << domTypeToString(kind()) << ":"
<< self.canonicalPath();
}
-ConstantData::ConstantData(Path pathFromOwner, QCborValue value, Options options)
+ConstantData::ConstantData(const Path &pathFromOwner, const QCborValue &value, Options options)
: DomElement(pathFromOwner), m_value(value), m_options(options)
{}
-bool ConstantData::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool ConstantData::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
static QHash<QString, QString> knownFields;
static QBasicMutex m;
- auto toField = [](QString f) -> QStringView {
+ auto toField = [](const QString &f) -> QStringView {
QMutexLocker l(&m);
if (!knownFields.contains(f))
knownFields[f] = f;
@@ -302,6 +347,41 @@ It does not keep any pointers to internal elements, but rather the path to them,
it every time it needs.
*/
+FileToLoad::FileToLoad(const std::weak_ptr<DomEnvironment> &environment,
+ const QString &canonicalPath, const QString &logicalPath,
+ const std::optional<InMemoryContents> &content)
+ : m_environment(environment),
+ m_canonicalPath(canonicalPath),
+ m_logicalPath(logicalPath),
+ m_content(content)
+{
+}
+
+FileToLoad FileToLoad::fromMemory(const std::weak_ptr<DomEnvironment> &environment,
+ const QString &path, const QString &code)
+{
+ const QString canonicalPath = QFileInfo(path).canonicalFilePath();
+ return {
+ environment,
+ canonicalPath,
+ path,
+ InMemoryContents{ code },
+ };
+}
+
+FileToLoad FileToLoad::fromFileSystem(const std::weak_ptr<DomEnvironment> &environment,
+ const QString &path)
+{
+ // make the path canonical so the file content can be loaded from it later
+ const QString canonicalPath = QFileInfo(path).canonicalFilePath();
+ return {
+ environment,
+ canonicalPath,
+ path,
+ std::nullopt,
+ };
+}
+
ErrorGroup DomItem::domErrorGroup = NewErrorGroup("Dom");
DomItem DomItem::empty = DomItem();
@@ -317,7 +397,7 @@ ErrorGroups DomItem::myResolveErrors()
return res;
}
-Path DomItem::canonicalPath()
+Path DomItem::canonicalPath() const
{
Path res = visitEl([this](auto &&el) { return el->canonicalPath(*this); });
if (!(!res || res.headKind() == Path::Kind::Root)) {
@@ -328,14 +408,20 @@ Path DomItem::canonicalPath()
}
-DomItem DomItem::containingObject()
+DomItem DomItem::containingObject() const
{
return visitEl([this](auto &&el) { return el->containingObject(*this); });
}
-DomItem DomItem::qmlObject(GoTo options, FilterUpOptions filterOptions)
+/*!
+ \internal
+ \brief Returns the QmlObject that this belongs to.
+
+ qmlObject() might also return the object of a component if GoTo:MostLikely is used.
+ */
+DomItem DomItem::qmlObject(GoTo options, FilterUpOptions filterOptions) const
{
- if (DomItem res = filterUp([](DomType k, DomItem &) { return k == DomType::QmlObject; },
+ if (DomItem res = filterUp([](DomType k, const DomItem &) { return k == DomType::QmlObject; },
filterOptions))
return res;
if (options == GoTo::MostLikely) {
@@ -345,7 +431,7 @@ DomItem DomItem::qmlObject(GoTo options, FilterUpOptions filterOptions)
return DomItem();
}
-DomItem DomItem::fileObject(GoTo options)
+DomItem DomItem::fileObject(GoTo options) const
{
DomItem res = *this;
DomType k = res.internalKind();
@@ -368,19 +454,12 @@ DomItem DomItem::fileObject(GoTo options)
return res;
}
-DomItem DomItem::rootQmlObject(GoTo options)
+DomItem DomItem::rootQmlObject(GoTo options) const
{
- if (DomItem res = filterUp([](DomType k, DomItem &) { return k == DomType::QmlObject; },
- FilterUpOptions::ReturnInner))
- return res;
- if (options == GoTo::MostLikely) {
- if (DomItem comp = component(options))
- return comp.field(Fields::objects).index(0);
- }
- return DomItem();
+ return qmlObject(options, FilterUpOptions::ReturnInner);
}
-DomItem DomItem::container()
+DomItem DomItem::container() const
{
Path path = pathFromOwner();
if (!path)
@@ -391,7 +470,7 @@ DomItem DomItem::container()
return containingObject();
}
-DomItem DomItem::globalScope()
+DomItem DomItem::globalScope() const
{
if (internalKind() == DomType::GlobalScope)
return *this;
@@ -403,23 +482,35 @@ DomItem DomItem::globalScope()
return DomItem();
}
-DomItem DomItem::owner()
+/*!
+ \internal
+ \brief The owner of an element, for an qmlObject this is the containing qml file.
+ */
+DomItem DomItem::owner() const
{
if (domTypeIsOwningItem(m_kind) || m_kind == DomType::Empty)
return *this;
- return std::visit(
- [this](auto &&el) { return DomItem(this->m_top, el, this->m_ownerPath, el.get()); },
- *m_owner);
+ return std::visit([this](auto &&el) {
+ if constexpr (std::is_same_v<std::decay_t<decltype(el)>, std::monostate>)
+ return DomItem();
+ else
+ return DomItem(this->m_top, el, this->m_ownerPath, el.get());
+ }, m_owner);
}
-DomItem DomItem::top()
+DomItem DomItem::top() const
{
if (domTypeIsTopItem(m_kind) || m_kind == DomType::Empty)
return *this;
- return std::visit([](auto &&el) { return DomItem(el, el, Path(), el.get()); }, *m_top);
+ return std::visit([](auto &&el) {
+ if constexpr (std::is_same_v<std::decay_t<decltype(el)>, std::monostate>)
+ return DomItem();
+ else
+ return DomItem(el, el, Path(), el.get());
+ }, m_top);
}
-DomItem DomItem::environment()
+DomItem DomItem::environment() const
{
DomItem res = top();
if (res.internalKind() == DomType::DomEnvironment)
@@ -427,7 +518,7 @@ DomItem DomItem::environment()
return DomItem(); // we are in the universe, and cannot go back to the environment...
}
-DomItem DomItem::universe()
+DomItem DomItem::universe() const
{
DomItem res = top();
if (res.internalKind() == DomType::DomUniverse)
@@ -437,91 +528,169 @@ DomItem DomItem::universe()
return DomItem(); // we should be in an empty DomItem already...
}
-DomItem DomItem::filterUp(function_ref<bool(DomType k, DomItem &)> filter, FilterUpOptions options)
+/*!
+ \internal
+ Shorthand to obtain the ScriptExpression DomItem, in which this DomItem is defined.
+ Returns an empty DomItem if the item is not defined inside a ScriptExpression.
+ \sa goToFile()
+ */
+DomItem DomItem::containingScriptExpression() const
+{
+ if (DomItem res = filterUp([](DomType k, const DomItem &) { return k == DomType::ScriptExpression; },
+ FilterUpOptions::ReturnOuter))
+ return res;
+ return DomItem();
+}
+
+/*!
+ \internal
+ Shorthand to obtain the QmlFile DomItem, in which this DomItem is defined.
+ Returns an empty DomItem if the item is not defined in a QML file.
+ \sa goToFile()
+ */
+DomItem DomItem::containingFile() const
+{
+ if (DomItem res = filterUp([](DomType k, const DomItem &) { return k == DomType::QmlFile; },
+ FilterUpOptions::ReturnOuter))
+ return res;
+ return DomItem();
+}
+
+/*!
+ \internal
+ Shorthand to obtain the QmlFile DomItem from a canonicalPath.
+ \sa containingFile()
+ */
+DomItem DomItem::goToFile(const QString &canonicalPath) const
+{
+ Q_UNUSED(canonicalPath);
+ DomItem file =
+ top().field(Fields::qmlFileWithPath).key(canonicalPath).field(Fields::currentItem);
+ return file;
+}
+
+/*!
+ \internal
+ In the DomItem hierarchy, go \c n levels up.
+ */
+DomItem DomItem::goUp(int n) const
+{
+ Path path = canonicalPath();
+ // first entry of path is usually top(), and you cannot go up from top().
+ if (path.length() < n + 1)
+ return DomItem();
+
+ DomItem parent = top().path(path.dropTail(n));
+ return parent;
+}
+
+/*!
+ \internal
+ In the DomItem hierarchy, go 1 level up to get the direct parent.
+ */
+DomItem DomItem::directParent() const
{
- DomItem it = *this;
- DomType k = it.internalKind();
+ return goUp(1);
+}
+
+/*!
+\internal
+Finds the first element in the DomItem hierarchy that satisfies filter.
+Use options to set the search direction, see also \l{FilterUpOptions}.
+*/
+DomItem DomItem::filterUp(function_ref<bool(DomType k, const DomItem &)> filter, FilterUpOptions options) const
+{
+ if (options == FilterUpOptions::ReturnOuter && filter(internalKind(), *this)) {
+ return *this;
+ }
+
switch (options) {
case FilterUpOptions::ReturnOuter:
case FilterUpOptions::ReturnOuterNoSelf: {
- bool checkTop = (options == FilterUpOptions::ReturnOuter);
- while (k != DomType::Empty) {
- if (checkTop && filter(k, it))
- return it;
- checkTop = true;
- if (!domTypeIsOwningItem(k)) {
- DomItem el = it.owner();
- DomItem res;
- k = DomType::Empty;
- Path pp = it.pathFromOwner();
- DomType k2 = el.internalKind();
- if (filter(k2, el)) {
- k = k2;
- res = el;
- }
- for (Path p : pp.mid(0, pp.length() - 1)) {
- el = el.path(p);
- DomType k2 = el.internalKind();
- if (filter(k2, el)) {
- k = k2;
- res = el;
- }
- }
- if (k != DomType::Empty)
- return res;
- it = it.owner();
+ for (DomItem current = *this, previous = DomItem(); current;
+ previous = current, current = current.directParent()) {
+ if (filter(current.internalKind(), current)) {
+ if (options != FilterUpOptions::ReturnOuterNoSelf || current != *this)
+ return current;
}
- it = it.containingObject();
- k = it.internalKind();
}
- } break;
+ break;
+ }
case FilterUpOptions::ReturnInner:
- while (k != DomType::Empty) {
- if (!domTypeIsOwningItem(k)) {
- DomItem el = owner();
- Path pp = pathFromOwner();
- for (Path p : pp) {
- DomItem child = el.path(p);
- DomType k2 = child.internalKind();
- if (filter(k2, child))
- return child;
- el = child;
- }
- it = it.owner();
- }
- it = it.containingObject();
- k = it.internalKind();
+ DomItem current = top();
+ for (const Path &currentPath : canonicalPath()) {
+ current = current.path(currentPath);
+ if (filter(current.internalKind(), current))
+ return current;
}
break;
}
+
return DomItem();
}
-DomItem DomItem::scope(FilterUpOptions options)
+DomItem DomItem::scope(FilterUpOptions options) const
{
- DomItem res = filterUp([](DomType, DomItem &el) { return el.isScope(); }, options);
+ DomItem res = filterUp([](DomType, const DomItem &el) { return el.isScope(); }, options);
return res;
}
-DomItem DomItem::get(ErrorHandler h, QList<Path> *visitedRefs)
+QQmlJSScope::ConstPtr DomItem::nearestSemanticScope() const
+{
+ QQmlJSScope::ConstPtr scope;
+ visitUp([&scope](const DomItem &item) {
+ scope = item.semanticScope();
+ return !scope; // stop when scope was true
+ });
+ return scope;
+}
+
+QQmlJSScope::ConstPtr DomItem::semanticScope() const
+{
+ QQmlJSScope::ConstPtr scope = std::visit(
+ [](auto &&e) -> QQmlJSScope::ConstPtr {
+ using T = std::remove_cv_t<std::remove_reference_t<decltype(e)>>;
+ if constexpr (std::is_same_v<T, const QmlObject *>) {
+ return e->semanticScope();
+ } else if constexpr (std::is_same_v<T, const QmlComponent *>) {
+ return e->semanticScope();
+ } else if constexpr (std::is_same_v<T, const QmltypesComponent *>) {
+ return e->semanticScope();
+ } else if constexpr (std::is_same_v<T, SimpleObjectWrap>) {
+ if (const MethodInfo *mi = e->template as<MethodInfo>()) {
+ return mi->semanticScope();
+ }
+ if (const auto *propertyDefinition = e->template as<PropertyDefinition>()) {
+ return propertyDefinition->semanticScope();
+ }
+ } else if constexpr (std::is_same_v<T, ScriptElementDomWrapper>) {
+ return e.element().base()->semanticScope();
+ }
+ return {};
+ },
+ m_element);
+ return scope;
+}
+
+DomItem DomItem::get(const ErrorHandler &h, QList<Path> *visitedRefs) const
{
if (const Reference *refPtr = as<Reference>())
return refPtr->get(*this, h, visitedRefs);
return DomItem();
}
-QList<DomItem> DomItem::getAll(ErrorHandler h, QList<Path> *visitedRefs)
+QList<DomItem> DomItem::getAll(const ErrorHandler &h, QList<Path> *visitedRefs) const
{
if (const Reference *refPtr = as<Reference>())
return refPtr->getAll(*this, h, visitedRefs);
return {};
}
-PropertyInfo DomItem::propertyInfoWithName(QString name)
+PropertyInfo DomItem::propertyInfoWithName(const QString &name) const
{
PropertyInfo pInfo;
- visitPrototypeChain([&pInfo, name](DomItem &obj) {
- return obj.visitLocalSymbolsNamed(name, [&pInfo, name](DomItem &el) {
+ visitPrototypeChain([&pInfo, name](const DomItem &obj) {
+ return obj.visitLocalSymbolsNamed(name, [&pInfo, name](const DomItem &el) {
switch (el.internalKind()) {
case DomType::Binding:
pInfo.bindings.append(el);
@@ -538,10 +707,10 @@ PropertyInfo DomItem::propertyInfoWithName(QString name)
return pInfo;
}
-QSet<QString> DomItem::propertyInfoNames()
+QSet<QString> DomItem::propertyInfoNames() const
{
QSet<QString> res;
- visitPrototypeChain([&res](DomItem &obj) {
+ visitPrototypeChain([&res](const DomItem &obj) {
res += obj.propertyDefs().keys();
res += obj.bindings().keys();
return true;
@@ -549,10 +718,10 @@ QSet<QString> DomItem::propertyInfoNames()
return res;
}
-DomItem DomItem::component(GoTo options)
+DomItem DomItem::component(GoTo options) const
{
if (DomItem res = filterUp(
- [](DomType kind, DomItem &) {
+ [](DomType kind, const DomItem &) {
return kind == DomType::QmlComponent || kind == DomType::QmltypesComponent
|| kind == DomType::GlobalComponent;
},
@@ -597,8 +766,8 @@ static QMap<LookupType, QString> lookupTypeToStringMap()
return map;
}
-bool DomItem::resolve(Path path, DomItem::Visitor visitor, ErrorHandler errorHandler,
- ResolveOptions options, Path fullPath, QList<Path> *visitedRefs)
+bool DomItem::resolve(const Path &path, DomItem::Visitor visitor, const ErrorHandler &errorHandler,
+ ResolveOptions options, const Path &fullPath, QList<Path> *visitedRefs) const
{
QList<Path> vRefs;
Path fPath = fullPath;
@@ -635,13 +804,12 @@ bool DomItem::resolve(Path path, DomItem::Visitor visitor, ErrorHandler errorHan
myResolveErrors().error(tr("Root context %1 is not known").arg(path.headName())).handle(errorHandler);
return false;
}
- toDos[0] = {root, 1};
+ toDos[0] = {std::move(root), 1};
} else {
toDos[0] = {*this, 0};
}
while (!toDos.isEmpty()) {
- auto toDo = toDos.last();
- toDos.removeLast();
+ const ResolveToDo toDo = toDos.takeLast();
{
auto idNow = toDo.item.id();
if (idNow == quintptr(0) && toDo.item == *this)
@@ -678,7 +846,7 @@ bool DomItem::resolve(Path path, DomItem::Visitor visitor, ErrorHandler errorHan
}
if (visitedRefs->contains(refRef)) {
myResolveErrors()
- .error([visitedRefs, refRef](Sink sink) {
+ .error([visitedRefs, refRef](const Sink &sink) {
const QString msg = tr("Circular reference:") + QLatin1Char('\n');
sink(QStringView{msg});
for (const Path &vPath : *visitedRefs) {
@@ -695,7 +863,7 @@ bool DomItem::resolve(Path path, DomItem::Visitor visitor, ErrorHandler errorHan
DomItem resolveRes;
it.resolve(
toResolve,
- [&resolveRes](Path, DomItem &r) {
+ [&resolveRes](Path, const DomItem &r) {
resolveRes = r;
return false;
},
@@ -732,11 +900,11 @@ bool DomItem::resolve(Path path, DomItem::Visitor visitor, ErrorHandler errorHan
if (!branchExhausted)
visitTree(
Path(),
- [toFind, &toDos, iPath](Path, DomItem &item, bool) {
+ [&toFind, &toDos, iPath](Path, const DomItem &item, bool) {
// avoid non directly attached?
DomItem newItem = item[toFind];
if (newItem)
- toDos.append({ newItem, iPath });
+ toDos.append({ std::move(newItem), iPath });
return true;
},
VisitOption::VisitSelf | VisitOption::Recurse
@@ -760,7 +928,7 @@ bool DomItem::resolve(Path path, DomItem::Visitor visitor, ErrorHandler errorHan
break;
case PathCurrent::ObjChain: {
bool cont = it.visitPrototypeChain(
- [&toDos, iPath](DomItem &subEl) {
+ [&toDos, iPath](const DomItem &subEl) {
toDos.append({ subEl, iPath });
return true;
},
@@ -773,7 +941,7 @@ bool DomItem::resolve(Path path, DomItem::Visitor visitor, ErrorHandler errorHan
}
case PathCurrent::ScopeChain: {
bool cont = it.visitScopeChain(
- [&toDos, iPath](DomItem &subEl) {
+ [&toDos, iPath](const DomItem &subEl) {
toDos.append({ subEl, iPath });
return true;
},
@@ -903,7 +1071,7 @@ bool DomItem::resolve(Path path, DomItem::Visitor visitor, ErrorHandler errorHan
}
it.visitLookup(
target,
- [&toDos, iPath](DomItem &subEl) {
+ [&toDos, iPath](const DomItem &subEl) {
toDos.append({ subEl, iPath });
return true;
},
@@ -917,7 +1085,7 @@ bool DomItem::resolve(Path path, DomItem::Visitor visitor, ErrorHandler errorHan
case Path::Kind::Any:
visitTree(
Path(),
- [&toDos, iPath](Path, DomItem &item, bool) {
+ [&toDos, iPath](Path, const DomItem &item, bool) {
toDos.append({ item, iPath });
return true;
},
@@ -937,49 +1105,49 @@ bool DomItem::resolve(Path path, DomItem::Visitor visitor, ErrorHandler errorHan
return true;
}
-DomItem DomItem::path(Path p, ErrorHandler errorHandler)
+DomItem DomItem::path(const Path &p, const ErrorHandler &errorHandler) const
{
if (!p)
return *this;
DomItem res;
- resolve(p, [&res](Path, DomItem it) {
+ resolve(p, [&res](const Path &, const DomItem &it) {
res = it;
return false;
}, errorHandler);
return res;
}
-DomItem DomItem::path(QString p, ErrorHandler errorHandler)
+DomItem DomItem::path(const QString &p, const ErrorHandler &errorHandler) const
{
return path(Path::fromString(p, errorHandler));
}
-DomItem DomItem::path(QStringView p, ErrorHandler errorHandler)
+DomItem DomItem::path(QStringView p, const ErrorHandler &errorHandler) const
{
return path(Path::fromString(p, errorHandler));
}
-QList<QString> DomItem::fields()
+QList<QString> DomItem::fields() const
{
return visitEl([this](auto &&el) { return el->fields(*this); });
}
-DomItem DomItem::field(QStringView name)
+DomItem DomItem::field(QStringView name) const
{
return visitEl([this, name](auto &&el) { return el->field(*this, name); });
}
-index_type DomItem::indexes()
+index_type DomItem::indexes() const
{
return visitEl([this](auto &&el) { return el->indexes(*this); });
}
-DomItem DomItem::index(index_type i)
+DomItem DomItem::index(index_type i) const
{
return visitEl([this, i](auto &&el) { return el->index(*this, i); });
}
-bool DomItem::visitIndexes(function_ref<bool(DomItem &)> visitor)
+bool DomItem::visitIndexes(function_ref<bool(const DomItem &)> visitor) const
{
// use iterateDirectSubpathsConst instead?
int nIndexes = indexes();
@@ -991,12 +1159,12 @@ bool DomItem::visitIndexes(function_ref<bool(DomItem &)> visitor)
return true;
}
-QSet<QString> DomItem::keys()
+QSet<QString> DomItem::keys() const
{
return visitEl([this](auto &&el) { return el->keys(*this); });
}
-QStringList DomItem::sortedKeys()
+QStringList DomItem::sortedKeys() const
{
QSet<QString> ks = keys();
QStringList sortedKs(ks.begin(), ks.end());
@@ -1004,15 +1172,16 @@ QStringList DomItem::sortedKeys()
return sortedKs;
}
-DomItem DomItem::key(QString name)
+DomItem DomItem::key(const QString &name) const
{
return visitEl([this, name](auto &&el) { return el->key(*this, name); });
}
-bool DomItem::visitKeys(function_ref<bool(QString, DomItem &)> visitor)
+bool DomItem::visitKeys(function_ref<bool(const QString &, const DomItem &)> visitor) const
{
// use iterateDirectSubpathsConst instead?
- for (auto k : sortedKeys()) {
+ const QStringList keys = sortedKeys();
+ for (const QString &k : keys) {
DomItem v = key(k);
if (!visitor(k, v))
return false;
@@ -1020,10 +1189,10 @@ bool DomItem::visitKeys(function_ref<bool(QString, DomItem &)> visitor)
return true;
}
-QList<DomItem> DomItem::values()
+QList<DomItem> DomItem::values() const
{
QList<DomItem> res;
- visitEl([this, &res](auto &&el) {
+ visitEl([this, &res](const auto &el) {
return el->iterateDirectSubpathsConst(
*this, [&res](const PathEls::PathComponent &, function_ref<DomItem()> item) {
res.append(item());
@@ -1033,11 +1202,11 @@ QList<DomItem> DomItem::values()
return res;
}
-void DomItem::writeOutPre(OutWriter &ow)
+void DomItem::writeOutPre(OutWriter &ow) const
{
if (hasAnnotations()) {
DomItem anns = field(Fields::annotations);
- for (auto ann : anns.values()) {
+ for (const auto &ann : anns.values()) {
if (ann.annotations().indexes() == 0) {
ow.ensureNewline();
ann.writeOut(ow);
@@ -1052,172 +1221,198 @@ void DomItem::writeOutPre(OutWriter &ow)
ow.itemStart(*this);
}
-void DomItem::writeOut(OutWriter &ow)
+void DomItem::writeOut(OutWriter &ow) const
{
writeOutPre(ow);
visitEl([this, &ow](auto &&el) { el->writeOut(*this, ow); });
writeOutPost(ow);
}
-void DomItem::writeOutPost(OutWriter &ow)
+void DomItem::writeOutPost(OutWriter &ow) const
{
ow.itemEnd(*this);
}
-DomItem DomItem::writeOutForFile(OutWriter &ow, WriteOutChecks extraChecks)
+DomItem::WriteOutCheckResult DomItem::performWriteOutChecks(const DomItem &original, const DomItem &reformatted,
+ OutWriter &ow,
+ WriteOutChecks extraChecks) const
+{
+ QStringList dumped;
+ auto maybeDump = [&ow, extraChecks, &dumped](const DomItem &obj, QStringView objName) {
+ QString objDumpPath;
+ if (extraChecks & WriteOutCheck::DumpOnFailure) {
+ objDumpPath = QDir(QDir::tempPath())
+ .filePath(objName.toString()
+ + QFileInfo(ow.lineWriter.fileName()).baseName()
+ + QLatin1String(".dump.json"));
+ obj.dump(objDumpPath);
+ dumped.append(objDumpPath);
+ }
+ return objDumpPath;
+ };
+ auto dumpedDumper = [&dumped](const Sink &s) {
+ if (dumped.isEmpty())
+ return;
+ s(u"\ndump: ");
+ for (const auto &dumpPath : dumped) {
+ s(u" ");
+ sinkEscaped(s, dumpPath);
+ }
+ };
+ auto compare = [&maybeDump, &dumpedDumper, this](const DomItem &obj1, QStringView obj1Name,
+ const DomItem &obj2, QStringView obj2Name,
+ const FieldFilter &filter) {
+ const auto diffList = domCompareStrList(obj1, obj2, filter, DomCompareStrList::AllDiffs);
+ if (!diffList.isEmpty()) {
+ maybeDump(obj1, obj1Name);
+ maybeDump(obj2, obj2Name);
+ qCWarning(writeOutLog).noquote().nospace()
+ << obj2Name << " writeOut of " << this->canonicalFilePath() << " has changes:\n"
+ << diffList.join(QString()) << dumpedDumper;
+ return false;
+ }
+ return true;
+ };
+ auto checkStability = [&maybeDump, &dumpedDumper, &dumped, &ow,
+ this](const QString &expected, const DomItem &obj, QStringView objName) {
+ LineWriter lw2([](QStringView) {}, ow.lineWriter.fileName(), ow.lineWriter.options());
+ OutWriter ow2(lw2);
+ ow2.indentNextlines = true;
+ obj.writeOut(ow2);
+ ow2.eof();
+ if (ow2.writtenStr != expected) {
+ DomItem fObj = this->fileObject();
+ maybeDump(fObj, u"initial");
+ maybeDump(obj, objName);
+ qCWarning(writeOutLog).noquote().nospace()
+ << objName << " non stable writeOut of " << this->canonicalFilePath() << ":"
+ << lineDiff(ow2.writtenStr, expected, 2) << dumpedDumper;
+ dumped.clear();
+ return false;
+ }
+ return true;
+ };
+
+ if ((extraChecks & WriteOutCheck::UpdatedDomCompare)
+ && !compare(original, u"initial", reformatted, u"reformatted",
+ FieldFilter::noLocationFilter()))
+ return WriteOutCheckResult::Failed;
+
+ if (extraChecks & WriteOutCheck::UpdatedDomStable) {
+ checkStability(ow.writtenStr, reformatted, u"reformatted");
+ }
+
+ if (extraChecks
+ & (WriteOutCheck::Reparse | WriteOutCheck::ReparseCompare | WriteOutCheck::ReparseStable)) {
+ DomItem newEnv = environment().makeCopy().item();
+ std::shared_ptr<DomEnvironment> newEnvPtr = newEnv.ownerAs<DomEnvironment>();
+ if (!newEnvPtr)
+ return WriteOutCheckResult::Failed;
+
+ auto newFilePtr = std::make_shared<QmlFile>(canonicalFilePath(), ow.writtenStr);
+ if (!newFilePtr)
+ return WriteOutCheckResult::Failed;
+ newEnvPtr->addQmlFile(newFilePtr, AddOption::Overwrite);
+
+ DomItem newFile = newEnv.copy(newFilePtr, Path());
+ if (newFilePtr->isValid()) {
+ if (extraChecks & (WriteOutCheck::ReparseCompare | WriteOutCheck::ReparseStable)) {
+ newEnvPtr->populateFromQmlFile(newFile);
+ if ((extraChecks & WriteOutCheck::ReparseCompare)
+ && !compare(reformatted, u"reformatted", newFile, u"reparsed",
+ FieldFilter::compareNoCommentsFilter()))
+ return WriteOutCheckResult::Failed;
+ if ((extraChecks & WriteOutCheck::ReparseStable))
+ checkStability(ow.writtenStr, newFile, u"reparsed");
+ }
+ } else {
+ const auto iterateErrors = [&newFile](const Sink &s) {
+ newFile.iterateErrors(
+ [s](const DomItem &, const ErrorMessage &msg) {
+ s(u"\n ");
+ msg.dump(s);
+ return true;
+ },
+ true);
+ s(u"\n"); // extra empty line at the end...
+ };
+ qCWarning(writeOutLog).noquote().nospace()
+ << "writeOut of " << canonicalFilePath()
+ << " created invalid code:\n----------\n"
+ << ow.writtenStr << "\n----------" << iterateErrors;
+ return WriteOutCheckResult::Failed;
+ }
+ }
+ return WriteOutCheckResult::Success;
+}
+
+/*!
+ \internal
+ Performes WriteOut of the FileItem and verifies the consistency of the DOM structure.
+
+ OutWriter is essentially a visitor traversing the DOM structure, starting from
+ the current item representing a FileItem.
+ While traversing it might be saving some intermediate information, used later for restoring
+ written out item. Restoration is needed to validate that the DOM structure of the written item
+ has not changed.
+*/
+bool DomItem::writeOutForFile(OutWriter &ow, WriteOutChecks extraChecks) const
{
ow.indentNextlines = true;
writeOut(ow);
ow.eof();
- DomItem fObj = fileObject();
- DomItem copy = ow.updatedFile(fObj);
- if (extraChecks & WriteOutCheck::All) {
- QStringList dumped;
- auto maybeDump = [&ow, extraChecks, &dumped](DomItem &obj, QStringView objName) {
- QString objDumpPath;
- if (extraChecks & WriteOutCheck::DumpOnFailure) {
- objDumpPath = QDir(QDir::tempPath())
- .filePath(objName.toString()
- + QFileInfo(ow.lineWriter.fileName()).baseName()
- + QLatin1String(".dump.json"));
- obj.dump(objDumpPath);
- dumped.append(objDumpPath);
- }
- return objDumpPath;
- };
- auto dumpedDumper = [&dumped](Sink s) {
- if (dumped.isEmpty())
- return;
- s(u"\ndump: ");
- for (auto dumpPath : dumped) {
- s(u" ");
- sinkEscaped(s, dumpPath);
- }
- };
- auto compare = [&maybeDump, &dumpedDumper, this](DomItem &obj1, QStringView obj1Name,
- DomItem &obj2, QStringView obj2Name,
- const FieldFilter &filter) {
- if (!domCompareStrList(obj1, obj2, filter).isEmpty()) {
- maybeDump(obj1, obj1Name);
- maybeDump(obj2, obj2Name);
- qCWarning(writeOutLog).noquote().nospace()
- << obj2Name << " writeOut of " << this->canonicalFilePath()
- << " has changes:\n"
- << domCompareStrList(obj1, obj2, filter, DomCompareStrList::AllDiffs)
- .join(QString())
- << dumpedDumper;
- return false;
- }
- return true;
- };
- auto checkStability = [&maybeDump, &dumpedDumper, &dumped, &ow,
- this](QString expected, DomItem &obj, QStringView objName) {
- LineWriter lw2([](QStringView) {}, ow.lineWriter.fileName(), ow.lineWriter.options());
- OutWriter ow2(lw2);
- ow2.indentNextlines = true;
- obj.writeOut(ow2);
- ow2.eof();
- if (ow2.writtenStr != expected) {
- DomItem fObj = this->fileObject();
- maybeDump(fObj, u"initial");
- maybeDump(obj, objName);
- qCWarning(writeOutLog).noquote().nospace()
- << objName << " non stable writeOut of " << this->canonicalFilePath() << ":"
- << lineDiff(ow2.writtenStr, expected, 2) << dumpedDumper;
- dumped.clear();
- return false;
- }
- return true;
- };
- if ((extraChecks & WriteOutCheck::UpdatedDomCompare)
- && !compare(fObj, u"initial", copy, u"reformatted", FieldFilter::noLocationFilter()))
- return DomItem();
- if (extraChecks & WriteOutCheck::UpdatedDomStable)
- checkStability(ow.writtenStr, copy, u"reformatted");
- if (extraChecks
- & (WriteOutCheck::Reparse | WriteOutCheck::ReparseCompare
- | WriteOutCheck::ReparseStable)) {
- DomItem newEnv = environment().makeCopy().item();
- if (std::shared_ptr<DomEnvironment> newEnvPtr = newEnv.ownerAs<DomEnvironment>()) {
- auto newFilePtr = std::make_shared<QmlFile>(
- canonicalFilePath(), ow.writtenStr);
- newEnvPtr->addQmlFile(newFilePtr, AddOption::Overwrite);
- DomItem newFile = newEnv.copy(newFilePtr, Path());
- if (newFilePtr->isValid()) {
- if (extraChecks
- & (WriteOutCheck::ReparseCompare | WriteOutCheck::ReparseStable)) {
- MutableDomItem newFileMutable(newFile);
- createDom(newFileMutable);
- if ((extraChecks & WriteOutCheck::ReparseCompare)
- && !compare(copy, u"reformatted", newFile, u"reparsed",
- FieldFilter::compareNoCommentsFilter()))
- return DomItem();
- if ((extraChecks & WriteOutCheck::ReparseStable))
- checkStability(ow.writtenStr, newFile, u"reparsed");
- }
- } else {
- qCWarning(writeOutLog).noquote().nospace()
- << "writeOut of " << canonicalFilePath()
- << " created invalid code:\n----------\n"
- << ow.writtenStr << "\n----------" << [&newFile](Sink s) {
- newFile.iterateErrors(
- [s](DomItem, ErrorMessage msg) {
- s(u"\n ");
- msg.dump(s);
- return true;
- },
- true);
- s(u"\n"); // extra empty line at the end...
- };
- return DomItem();
- }
- }
- }
- }
- return copy;
+
+ auto currentFileItem = fileObject();
+ auto writtenFileItem = ow.restoreWrittenFileItem(currentFileItem);
+ WriteOutCheckResult result = WriteOutCheckResult::Success;
+ if (extraChecks & WriteOutCheck::All)
+ result = performWriteOutChecks(currentFileItem, writtenFileItem, ow, extraChecks);
+ return result == WriteOutCheckResult::Success ? bool(writtenFileItem) : false;
}
-DomItem DomItem::writeOut(QString path, int nBackups, const LineWriterOptions &options,
- FileWriter *fw, WriteOutChecks extraChecks)
+bool DomItem::writeOut(const QString &path, int nBackups, const LineWriterOptions &options,
+ FileWriter *fw, WriteOutChecks extraChecks) const
{
- DomItem res = *this;
- DomItem copy;
FileWriter localFw;
if (!fw)
fw = &localFw;
- switch (fw->write(
+ auto status = fw->write(
path,
- [this, path, &copy, &options, extraChecks](QTextStream &ts) {
+ [this, path, &options, extraChecks](QTextStream &ts) {
LineWriter lw([&ts](QStringView s) { ts << s; }, path, options);
OutWriter ow(lw);
- copy = writeOutForFile(ow, extraChecks);
- return bool(copy);
+ return writeOutForFile(ow, extraChecks);
},
- nBackups)) {
+ nBackups);
+ switch (status) {
+ case FileWriter::Status::DidWrite:
+ case FileWriter::Status::SkippedEqual:
+ return true;
case FileWriter::Status::ShouldWrite:
case FileWriter::Status::SkippedDueToFailure:
qCWarning(writeOutLog) << "failure reformatting " << path;
- break;
- case FileWriter::Status::DidWrite:
- case FileWriter::Status::SkippedEqual:
- res = copy;
- break;
+ return false;
+ default:
+ qCWarning(writeOutLog) << "Unknown FileWriter::Status ";
+ Q_ASSERT(false);
+ return false;
}
- return res;
}
-bool DomItem::isCanonicalChild(DomItem &item)
+bool DomItem::isCanonicalChild(const DomItem &item) const
{
+ bool isChild = false;
if (item.isOwningItem()) {
- return canonicalPath() == item.canonicalPath().dropTail();
+ isChild = canonicalPath() == item.canonicalPath().dropTail();
} else {
DomItem itemOw = item.owner();
DomItem selfOw = owner();
- return itemOw == selfOw && item.pathFromOwner().dropTail() == pathFromOwner();
+ isChild = itemOw == selfOw && item.pathFromOwner().dropTail() == pathFromOwner();
}
+ return isChild;
}
-bool DomItem::hasAnnotations()
+bool DomItem::hasAnnotations() const
{
bool hasAnnotations = false;
DomType iKind = internalKind();
@@ -1248,28 +1443,56 @@ bool DomItem::hasAnnotations()
return hasAnnotations;
}
-bool DomItem::visitTree(Path basePath, DomItem::ChildrenVisitor visitor, VisitOptions options,
- DomItem::ChildrenVisitor openingVisitor,
- DomItem::ChildrenVisitor closingVisitor)
+/*!
+ \internal
+ \brief Visits recursively all the children of this item using the given visitors.
+
+ First, the visitor is called and can continue or exit the visit by returning true or false.
+
+ Second, the openingVisitor is called and controls if the children of the current item needs to
+ be visited or not by returning true or false. In either case, the visitation of all the other
+ siblings is not affected. If both visitor and openingVisitor returned true, then the childrens of
+ the current item will be recursively visited.
+
+ Finally, after all the children were visited by visitor and openingVisitor, the closingVisitor
+ is called. Its return value is currently ignored.
+
+ Compared to the AST::Visitor*, openingVisitor and closingVisitor are called in the same order as
+ the visit() and endVisit()-calls.
+
+ Filtering allows to not visit certain part of the trees, and is checked before(!) the lazy child
+ is instantiated via its lambda. For example, visiting propertyInfos or defaultPropertyname takes
+ a lot of time because it resolves and collects all properties inherited from base types, and
+ might not even be relevant for the visitors.
+ */
+bool DomItem::visitTree(const Path &basePath, DomItem::ChildrenVisitor visitor,
+ VisitOptions options, DomItem::ChildrenVisitor openingVisitor,
+ DomItem::ChildrenVisitor closingVisitor, const FieldFilter &filter) const
{
if (!*this)
return true;
if (options & VisitOption::VisitSelf && !visitor(basePath, *this, true))
return false;
- if (!openingVisitor(basePath, *this, true))
+ if (options & VisitOption::VisitSelf && !openingVisitor(basePath, *this, true))
return true;
- auto atEnd = qScopeGuard(
- [closingVisitor, basePath, this]() { closingVisitor(basePath, *this, true); });
- return visitEl([this, basePath, visitor, openingVisitor, closingVisitor, options](auto &&el) {
+ auto atEnd = qScopeGuard([closingVisitor, basePath, this, options]() {
+ if (options & VisitOption::VisitSelf) {
+ closingVisitor(basePath, *this, true);
+ }
+ });
+ return visitEl([this, basePath, visitor, openingVisitor, closingVisitor, options,
+ &filter](auto &&el) {
return el->iterateDirectSubpathsConst(
*this,
- [this, basePath, visitor, openingVisitor, closingVisitor,
- options](const PathEls::PathComponent &c, function_ref<DomItem()> itemF) {
+ [this, basePath, visitor, openingVisitor, closingVisitor, options,
+ &filter](const PathEls::PathComponent &c, function_ref<DomItem()> itemF) {
Path pNow;
if (!(options & VisitOption::NoPath)) {
pNow = basePath;
pNow = pNow.appendComponent(c);
}
+ if (!filter(*this, c, DomItem{}))
+ return true;
DomItem item = itemF();
bool directChild = isCanonicalChild(item);
if (!directChild && !(options & VisitOption::VisitAdopted))
@@ -1285,16 +1508,81 @@ bool DomItem::visitTree(Path basePath, DomItem::ChildrenVisitor visitor, VisitOp
closingVisitor(pNow, item, directChild);
} else {
return item.visitTree(pNow, visitor, options | VisitOption::VisitSelf,
- openingVisitor, closingVisitor);
+ openingVisitor, closingVisitor, filter);
}
return true;
});
});
}
+static bool visitPrototypeIndex(QList<DomItem> &toDo, const DomItem &current,
+ const DomItem &derivedFromPrototype, const ErrorHandler &h,
+ QList<Path> *visitedRefs, VisitPrototypesOptions options,
+ const DomItem &prototype)
+{
+ Path elId = prototype.canonicalPath();
+ if (visitedRefs->contains(elId))
+ return true;
+ else
+ visitedRefs->append(elId);
+ QList<DomItem> protos = prototype.getAll(h, visitedRefs);
+ if (protos.isEmpty()) {
+ if (std::shared_ptr<DomEnvironment> envPtr =
+ derivedFromPrototype.environment().ownerAs<DomEnvironment>())
+ if (!(envPtr->options() & DomEnvironment::Option::NoDependencies))
+ derivedFromPrototype.myErrors()
+ .warning(derivedFromPrototype.tr("could not resolve prototype %1 (%2)")
+ .arg(current.canonicalPath().toString(),
+ prototype.field(Fields::referredObjectPath)
+ .value()
+ .toString()))
+ .withItem(derivedFromPrototype)
+ .handle(h);
+ } else {
+ if (protos.size() > 1) {
+ QStringList protoPaths;
+ for (const DomItem &p : protos)
+ protoPaths.append(p.canonicalPath().toString());
+ derivedFromPrototype.myErrors()
+ .warning(derivedFromPrototype
+ .tr("Multiple definitions found, using first only, resolving "
+ "prototype %1 (%2): %3")
+ .arg(current.canonicalPath().toString(),
+ prototype.field(Fields::referredObjectPath)
+ .value()
+ .toString(),
+ protoPaths.join(QLatin1String(", "))))
+ .withItem(derivedFromPrototype)
+ .handle(h);
+ }
+ int nProtos = 1; // change to protos.length() to use all prototypes
+ // (sloppier)
+ for (int i = nProtos; i != 0;) {
+ DomItem proto = protos.at(--i);
+ if (proto.internalKind() == DomType::Export) {
+ if (!(options & VisitPrototypesOption::ManualProceedToScope))
+ proto = proto.proceedToScope(h, visitedRefs);
+ toDo.append(proto);
+ } else if (proto.internalKind() == DomType::QmlObject
+ || proto.internalKind() == DomType::QmlComponent) {
+ toDo.append(proto);
+ } else {
+ derivedFromPrototype.myErrors()
+ .warning(derivedFromPrototype.tr("Unexpected prototype type %1 (%2)")
+ .arg(current.canonicalPath().toString(),
+ prototype.field(Fields::referredObjectPath)
+ .value()
+ .toString()))
+ .withItem(derivedFromPrototype)
+ .handle(h);
+ }
+ }
+ }
+ return true;
+}
-bool DomItem::visitPrototypeChain(function_ref<bool(DomItem &)> visitor,
- VisitPrototypesOptions options, ErrorHandler h,
- QSet<quintptr> *visited, QList<Path> *visitedRefs)
+bool DomItem::visitPrototypeChain(function_ref<bool(const DomItem &)> visitor,
+ VisitPrototypesOptions options, const ErrorHandler &h,
+ QSet<quintptr> *visited, QList<Path> *visitedRefs) const
{
QSet<quintptr> visitedLocal;
if (!visited)
@@ -1330,72 +1618,16 @@ bool DomItem::visitPrototypeChain(function_ref<bool(DomItem &)> visitor,
return false;
shouldVisit = true;
current.field(Fields::prototypes)
- .visitIndexes([&toDo, &current, this, &h, visitedRefs, options](DomItem &el) {
- Path elId = el.canonicalPath();
- if (visitedRefs->contains(elId))
- return true;
- else
- visitedRefs->append(elId);
- QList<DomItem> protos = el.getAll(h, visitedRefs);
- if (protos.isEmpty()) {
- if (std::shared_ptr<DomEnvironment> envPtr =
- environment().ownerAs<DomEnvironment>())
- if (!(envPtr->options() & DomEnvironment::Option::NoDependencies))
- myErrors()
- .warning(tr("could not resolve prototype %1 (%2)")
- .arg(current.canonicalPath().toString(),
- el.field(Fields::referredObjectPath)
- .value()
- .toString()))
- .withItem(*this)
- .handle(h);
- } else {
- if (protos.size() > 1) {
- QStringList protoPaths;
- for (DomItem &p : protos)
- protoPaths.append(p.canonicalPath().toString());
- myErrors()
- .warning(tr("Multiple definitions found, using first only, "
- "resolving prototype %1 (%2): %3")
- .arg(current.canonicalPath().toString(),
- el.field(Fields::referredObjectPath)
- .value()
- .toString(),
- protoPaths.join(QLatin1String(", "))))
- .withItem(*this)
- .handle(h);
- }
- int nProtos = 1; // change to protos.length() to us all prototypes found
- // (sloppier)
- for (int i = nProtos; i != 0;) {
- DomItem proto = protos.at(--i);
- if (proto.internalKind() == DomType::Export) {
- if (!(options & VisitPrototypesOption::ManualProceedToScope))
- proto = proto.proceedToScope(h, visitedRefs);
- toDo.append(proto);
- } else if (proto.internalKind() == DomType::QmlObject) {
- toDo.append(proto);
- } else {
- myErrors()
- .warning(tr("Unexpected prototype type %1 (%2)")
- .arg(current.canonicalPath().toString(),
- el.field(Fields::referredObjectPath)
- .value()
- .toString()))
- .withItem(*this)
- .handle(h);
- }
- }
- }
- return true;
+ .visitIndexes([&toDo, &current, this, &h, visitedRefs, options](const DomItem &el) {
+ return visitPrototypeIndex(toDo, current, *this, h, visitedRefs, options, el);
});
}
return true;
}
-bool DomItem::visitDirectAccessibleScopes(function_ref<bool(DomItem &)> visitor,
- VisitPrototypesOptions options, ErrorHandler h,
- QSet<quintptr> *visited, QList<Path> *visitedRefs)
+bool DomItem::visitDirectAccessibleScopes(
+ function_ref<bool(const DomItem &)> visitor, VisitPrototypesOptions options,
+ const ErrorHandler &h, QSet<quintptr> *visited, QList<Path> *visitedRefs) const
{
// these are the scopes one can access with the . operator from the current location
// but currently not the attached types, which we should
@@ -1440,9 +1672,9 @@ bool DomItem::visitDirectAccessibleScopes(function_ref<bool(DomItem &)> visitor,
* visit the values JS reaches accessing a type directly: the values if it is a singleton or the
* attached type
*/
-bool DomItem::visitStaticTypePrototypeChains(function_ref<bool(DomItem &)> visitor,
- VisitPrototypesOptions options, ErrorHandler h,
- QSet<quintptr> *visited, QList<Path> *visitedRefs)
+bool DomItem::visitStaticTypePrototypeChains(
+ function_ref<bool(const DomItem &)> visitor, VisitPrototypesOptions options,
+ const ErrorHandler &h, QSet<quintptr> *visited, QList<Path> *visitedRefs) const
{
QSet<quintptr> visitedLocal;
if (!visited)
@@ -1460,8 +1692,27 @@ bool DomItem::visitStaticTypePrototypeChains(function_ref<bool(DomItem &)> visit
return true;
}
-bool DomItem::visitScopeChain(function_ref<bool(DomItem &)> visitor, LookupOptions options,
- ErrorHandler h, QSet<quintptr> *visited, QList<Path> *visitedRefs)
+/*!
+ \brief Let the visitor visit the Dom Tree hierarchy of this DomItem.
+ */
+bool DomItem::visitUp(function_ref<bool(const DomItem &)> visitor) const
+{
+ Path p = canonicalPath();
+ while (p.length() > 0) {
+ DomItem current = top().path(p);
+ if (!visitor(current))
+ return false;
+ p = p.dropTail();
+ }
+ return true;
+}
+
+/*!
+ \brief Let the visitor visit the QML scope hierarchy of this DomItem.
+ */
+bool DomItem::visitScopeChain(
+ function_ref<bool(const DomItem &)> visitor, LookupOptions options, const ErrorHandler &h,
+ QSet<quintptr> *visited, QList<Path> *visitedRefs) const
{
QSet<quintptr> visitedLocal;
if (!visited)
@@ -1478,6 +1729,7 @@ bool DomItem::visitScopeChain(function_ref<bool(DomItem &)> visitor, LookupOptio
bool visitFirst = !(options & LookupOption::SkipFirstScope);
bool visitCurrent = visitFirst;
bool first = true;
+ QSet<quintptr> alreadyAddedComponentMaps;
while (!toDo.isEmpty()) {
DomItem current = toDo.takeLast();
if (visited->contains(current.id()))
@@ -1505,7 +1757,7 @@ bool DomItem::visitScopeChain(function_ref<bool(DomItem &)> visitor, LookupOptio
if (DomItem next = current.scope(FilterUpOptions::ReturnOuterNoSelf))
toDo.append(next);
break;
- case DomType::QmlComponent: // ids/attached type
+ case DomType::QmlComponent: { // ids/attached type
if ((options & LookupOption::Strict) == 0) {
if (DomItem comp = current.field(Fields::nextComponent))
toDo.append(comp);
@@ -1517,8 +1769,25 @@ bool DomItem::visitScopeChain(function_ref<bool(DomItem &)> visitor, LookupOptio
}
if (DomItem next = current.scope(FilterUpOptions::ReturnOuterNoSelf))
toDo.append(next);
+
+ DomItem owner = current.owner();
+ Path pathToComponentMap = current.pathFromOwner().dropTail(2);
+ DomItem componentMap = owner.path(pathToComponentMap);
+ if (alreadyAddedComponentMaps.contains(componentMap.id()))
+ break;
+ alreadyAddedComponentMaps.insert(componentMap.id());
+ const auto keys = componentMap.keys();
+ for (const QString &x : keys) {
+ DomItem componentList = componentMap.key(x);
+ for (int i = 0; i < componentList.indexes(); ++i) {
+ DomItem component = componentList.index(i);
+ if (component != current && !visited->contains(component.id()))
+ toDo.append(component);
+ }
+ }
first = false;
break;
+ }
case DomType::QmlFile: // subComponents, imported types
if (DomItem iScope =
current.field(Fields::importScope)) // treat file as a separate scope?
@@ -1558,118 +1827,14 @@ bool DomItem::visitScopeChain(function_ref<bool(DomItem &)> visitor, LookupOptio
return true;
}
-QSet<QString> DomItem::localSymbolNames(LocalSymbolsTypes typeFilter)
+bool DomItem::visitLookup1(
+ const QString &symbolName, function_ref<bool(const DomItem &)> visitor, LookupOptions opts,
+ const ErrorHandler &h, QSet<quintptr> *visited, QList<Path> *visitedRefs) const
{
- QSet<QString> res;
- if (typeFilter == LocalSymbolsType::None)
- return res;
- switch (internalKind()) {
- case DomType::QmlObject:
- if (typeFilter & LocalSymbolsType::Attributes) {
- res += propertyDefs().keys();
- res += bindings().keys();
- }
- if (typeFilter & LocalSymbolsType::Methods) {
- if ((typeFilter & LocalSymbolsType::Methods) == LocalSymbolsType::Methods) {
- res += methods().keys();
- } else {
- bool shouldAddSignals = bool(typeFilter & LocalSymbolsType::Signals);
- if (const QmlObject *objPtr = as<QmlObject>()) {
- auto methods = objPtr->methods();
- for (auto it = methods.cbegin(); it != methods.cend(); ++it) {
- if (bool(it.value().methodType == MethodInfo::MethodType::Signal)
- == shouldAddSignals)
- res += it.key();
- }
- }
- }
- }
- break;
- case DomType::ScriptExpression:
- // to do
- break;
- case DomType::QmlComponent:
- if (typeFilter & LocalSymbolsType::Ids)
- res += ids().keys();
- break;
- case DomType::QmlFile: // subComponents, imported types
- if (typeFilter & LocalSymbolsType::Components) {
- DomItem comps = field(Fields::components);
- for (auto k : comps.keys())
- if (!k.isEmpty())
- res.insert(k);
- }
- break;
- case DomType::ImportScope: {
- const ImportScope *currentPtr = as<ImportScope>();
- if (typeFilter & LocalSymbolsType::Types) {
- if ((typeFilter & LocalSymbolsType::Types) == LocalSymbolsType::Types) {
- res += currentPtr->importedNames(*this);
- } else {
- bool qmlTypes = bool(typeFilter & LocalSymbolsType::QmlTypes);
- for (const QString &typeName : currentPtr->importedNames(*this)) {
- if ((!typeName.isEmpty() && typeName.at(0).isUpper()) == qmlTypes)
- res += typeName;
- }
- }
- }
- if (typeFilter & LocalSymbolsType::Namespaces) {
- for (const auto &k : currentPtr->subImports().keys())
- res.insert(k);
- }
- break;
- }
- case DomType::QmltypesComponent:
- case DomType::JsResource:
- case DomType::GlobalComponent:
- if (typeFilter & LocalSymbolsType::Globals)
- res += enumerations().keys();
- break;
- case DomType::MethodInfo: {
- if (typeFilter & LocalSymbolsType::MethodParameters) {
- DomItem params = field(Fields::parameters);
- params.visitIndexes([&res](DomItem &p) {
- const MethodParameter *pPtr = p.as<MethodParameter>();
- res.insert(pPtr->name);
- return true;
- });
- }
- break;
- }
- default:
- break;
- }
- return res;
-}
-
-bool DomItem::visitLookup1(QString symbolName, function_ref<bool(DomItem &)> visitor,
- LookupOptions opts, ErrorHandler h, QSet<quintptr> *visited,
- QList<Path> *visitedRefs)
-{
- bool typeLookupInQmlFile = symbolName.size() > 1 && symbolName.at(0).isUpper()
- && fileObject().internalKind() == DomType::QmlFile;
- if (typeLookupInQmlFile) {
- // shortcut to lookup types (scope chain would find them too, but after looking
- // the prototype chain)
- DomItem importScope = fileObject().field(Fields::importScope);
- if (const ImportScope *importScopePtr = importScope.as<ImportScope>()) {
- if (importScopePtr->subImports().contains(symbolName)) {
- DomItem subItem = importScope.field(Fields::qualifiedImports).key(symbolName);
- if (!visitor(subItem))
- return false;
- }
- QList<DomItem> types = importScopePtr->importedItemsWithName(importScope, symbolName);
- for (DomItem &t : types) {
- if (!visitor(t))
- return false;
- }
- }
- return true;
- }
return visitScopeChain(
- [symbolName, visitor](DomItem &obj) {
+ [symbolName, visitor](const DomItem &obj) {
return obj.visitLocalSymbolsNamed(symbolName,
- [visitor](DomItem &el) { return visitor(el); });
+ [visitor](const DomItem &el) { return visitor(el); });
},
opts, h, visited, visitedRefs);
}
@@ -1680,7 +1845,7 @@ class CppTypeInfo
public:
CppTypeInfo() = default;
- static CppTypeInfo fromString(QStringView target, ErrorHandler h = nullptr)
+ static CppTypeInfo fromString(QStringView target, const ErrorHandler &h = nullptr)
{
CppTypeInfo res;
QRegularExpression reTarget = QRegularExpression(QRegularExpression::anchoredPattern(
@@ -1719,9 +1884,95 @@ public:
bool isList = false;
};
-bool DomItem::visitLookup(QString target, function_ref<bool(DomItem &)> visitor,
- LookupType lookupType, LookupOptions opts, ErrorHandler errorHandler,
- QSet<quintptr> *visited, QList<Path> *visitedRefs)
+static bool visitForLookupType(const DomItem &el, LookupType lookupType,
+ function_ref<bool(const DomItem &)> visitor)
+{
+ bool correctType = false;
+ DomType iType = el.internalKind();
+ switch (lookupType) {
+ case LookupType::Binding:
+ correctType = (iType == DomType::Binding);
+ break;
+ case LookupType::Method:
+ correctType = (iType == DomType::MethodInfo);
+ break;
+ case LookupType::Property:
+ correctType = (iType == DomType::PropertyDefinition || iType == DomType::Binding);
+ break;
+ case LookupType::PropertyDef:
+ correctType = (iType == DomType::PropertyDefinition);
+ break;
+ case LookupType::Type:
+ correctType = (iType == DomType::Export); // accept direct QmlObject ref?
+ break;
+ default:
+ Q_ASSERT(false);
+ break;
+ }
+ if (correctType)
+ return visitor(el);
+ return true;
+}
+
+static bool visitQualifiedNameLookup(
+ const DomItem &newIt, const QStringList &subpath,
+ function_ref<bool(const DomItem &)> visitor, LookupType lookupType,
+ const ErrorHandler &errorHandler, QList<Path> *visitedRefs)
+{
+ QVector<ResolveToDo> lookupToDos(
+ { ResolveToDo{ newIt, 1 } }); // invariant: always increase pathIndex to guarantee
+ // end even with only partial visited match
+ QList<QSet<quintptr>> lookupVisited(subpath.size() + 1);
+ while (!lookupToDos.isEmpty()) {
+ ResolveToDo tNow = lookupToDos.takeFirst();
+ auto vNow = qMakePair(tNow.item.id(), tNow.pathIndex);
+ DomItem subNow = tNow.item;
+ int iSubPath = tNow.pathIndex;
+ Q_ASSERT(iSubPath < subpath.size());
+ QString subPathNow = subpath[iSubPath++];
+ DomItem scope = subNow.proceedToScope();
+ if (iSubPath < subpath.size()) {
+ if (vNow.first != 0) {
+ if (lookupVisited[vNow.second].contains(vNow.first))
+ continue;
+ else
+ lookupVisited[vNow.second].insert(vNow.first);
+ }
+ if (scope.internalKind() == DomType::QmlObject)
+ scope.visitDirectAccessibleScopes(
+ [&lookupToDos, &subPathNow, iSubPath](const DomItem &el) {
+ return el.visitLocalSymbolsNamed(
+ subPathNow, [&lookupToDos, iSubPath](const DomItem &subEl) {
+ lookupToDos.append({ subEl, iSubPath });
+ return true;
+ });
+ },
+ VisitPrototypesOption::Normal, errorHandler, &(lookupVisited[vNow.second]),
+ visitedRefs);
+ } else {
+ bool cont = scope.visitDirectAccessibleScopes(
+ [&visitor, &subPathNow, lookupType](const DomItem &el) -> bool {
+ if (lookupType == LookupType::Symbol)
+ return el.visitLocalSymbolsNamed(subPathNow, visitor);
+ else
+ return el.visitLocalSymbolsNamed(
+ subPathNow, [lookupType, &visitor](const DomItem &el) -> bool {
+ return visitForLookupType(el, lookupType, visitor);
+ });
+ },
+ VisitPrototypesOption::Normal, errorHandler, &(lookupVisited[vNow.second]),
+ visitedRefs);
+ if (!cont)
+ return false;
+ }
+ }
+ return true;
+}
+
+bool DomItem::visitLookup(
+ const QString &target, function_ref<bool(const DomItem &)> visitor, LookupType lookupType,
+ LookupOptions opts, const ErrorHandler &errorHandler, QSet<quintptr> *visited,
+ QList<Path> *visitedRefs) const
{
if (target.isEmpty())
return true;
@@ -1738,101 +1989,10 @@ bool DomItem::visitLookup(QString target, function_ref<bool(DomItem &)> visitor,
} else {
return visitLookup1(
subpath.at(0),
- [&subpath, visitor, lookupType, &errorHandler, visitedRefs](DomItem &newIt) {
- QVector<ResolveToDo> lookupToDos({ ResolveToDo {
- newIt, 1 } }); // invariant: always increase pathIndex to guarantee
- // end even with only partial visited match
- QList<QSet<quintptr>> lookupVisited(subpath.size() + 1);
- while (!lookupToDos.isEmpty()) {
- ResolveToDo tNow = lookupToDos.takeFirst();
- auto vNow = qMakePair(tNow.item.id(), tNow.pathIndex);
- DomItem subNow = tNow.item;
- int iSubPath = tNow.pathIndex;
- Q_ASSERT(iSubPath < subpath.size());
- QString subPathNow = subpath[iSubPath++];
- DomItem scope = subNow.proceedToScope();
- if (iSubPath < subpath.size()) {
- if (vNow.first != 0) {
- if (lookupVisited[vNow.second].contains(vNow.first))
- continue;
- else
- lookupVisited[vNow.second].insert(vNow.first);
- }
- if (scope.internalKind() == DomType::QmlObject)
- scope.visitDirectAccessibleScopes(
- [&lookupToDos, subPathNow, iSubPath](DomItem &el) {
- return el.visitLocalSymbolsNamed(
- subPathNow,
- [&lookupToDos, iSubPath](DomItem &subEl) {
- lookupToDos.append({ subEl, iSubPath });
- return true;
- });
- },
- VisitPrototypesOption::Normal, errorHandler,
- &(lookupVisited[vNow.second]), visitedRefs);
- } else {
- bool cont = scope.visitDirectAccessibleScopes(
- [&visitor, subPathNow, lookupType](DomItem &el) -> bool {
- if (lookupType == LookupType::Symbol)
- return el.visitLocalSymbolsNamed(subPathNow,
- visitor);
- else
- return el.visitLocalSymbolsNamed(
- subPathNow,
- [lookupType,
- &visitor](DomItem &el) -> bool {
- bool correctType = false;
- DomType iType = el.internalKind();
- switch (lookupType) {
- case LookupType::Binding:
- correctType =
- (iType == DomType::Binding);
- break;
- case LookupType::Method:
- correctType =
- (iType
- == DomType::MethodInfo);
- break;
- case LookupType::Property:
- correctType =
- (iType
- == DomType::
- PropertyDefinition
- || iType
- == DomType::
- Binding);
- break;
- case LookupType::PropertyDef:
- correctType =
- (iType
- == DomType::
- PropertyDefinition);
- break;
- case LookupType::Type:
- correctType =
- (iType
- == DomType::
- Export); // accept
- // direct
- // QmlObject
- // ref?
- break;
- default:
- Q_ASSERT(false);
- break;
- }
- if (correctType)
- return visitor(el);
- return true;
- });
- },
- VisitPrototypesOption::Normal, errorHandler,
- &(lookupVisited[vNow.second]), visitedRefs);
- if (!cont)
- return false;
- }
- }
- return true;
+ [&subpath, visitor, lookupType, &errorHandler,
+ visitedRefs](const DomItem &newIt) -> bool {
+ return visitQualifiedNameLookup(newIt, subpath, visitor, lookupType,
+ errorHandler, visitedRefs);
},
opts, errorHandler, visited, visitedRefs);
}
@@ -1847,8 +2007,8 @@ bool DomItem::visitLookup(QString target, function_ref<bool(DomItem &)> visitor,
}
if (localQmltypes) {
if (DomItem localTypes = localQmltypes.field(Fields::components).key(baseTarget)) {
- bool cont = localTypes.visitIndexes([&visitor](DomItem &els) {
- return els.visitIndexes([&visitor](DomItem &el) {
+ bool cont = localTypes.visitIndexes([&visitor](const DomItem &els) {
+ return els.visitIndexes([&visitor](const DomItem &el) {
if (DomItem obj = el.field(Fields::objects).index(0))
return visitor(obj);
return true;
@@ -1859,10 +2019,10 @@ bool DomItem::visitLookup(QString target, function_ref<bool(DomItem &)> visitor,
}
}
DomItem qmltypes = environment().field(Fields::qmltypesFileWithPath);
- return qmltypes.visitKeys([baseTarget, &visitor](QString, DomItem &els) {
+ return qmltypes.visitKeys([baseTarget, &visitor](const QString &, const DomItem &els) {
DomItem comps =
els.field(Fields::currentItem).field(Fields::components).key(baseTarget);
- return comps.visitIndexes([&visitor](DomItem &el) {
+ return comps.visitIndexes([&visitor](const DomItem &el) {
if (DomItem obj = el.field(Fields::objects).index(0))
return visitor(obj);
return true;
@@ -1875,7 +2035,15 @@ bool DomItem::visitLookup(QString target, function_ref<bool(DomItem &)> visitor,
return true;
}
-DomItem DomItem::proceedToScope(ErrorHandler h, QList<Path> *visitedRefs)
+/*!
+ \internal
+ \brief Dereference DomItems pointing to other DomItems.
+
+ Dereferences DomItems with internalKind being References, Export and Id.
+ Also does multiple rounds of resolving for nested DomItems.
+ Prefer this over \l {DomItem::get}.
+ */
+DomItem DomItem::proceedToScope(const ErrorHandler &h, QList<Path> *visitedRefs) const
{
// follow references, resolve exports
DomItem current = *this;
@@ -1900,13 +2068,13 @@ DomItem DomItem::proceedToScope(ErrorHandler h, QList<Path> *visitedRefs)
return DomItem();
}
-QList<DomItem> DomItem::lookup(QString symbolName, LookupType type, LookupOptions opts,
- ErrorHandler errorHandler)
+QList<DomItem> DomItem::lookup(const QString &symbolName, LookupType type, LookupOptions opts,
+ const ErrorHandler &errorHandler) const
{
QList<DomItem> res;
visitLookup(
symbolName,
- [&res](DomItem &el) {
+ [&res](const DomItem &el) {
res.append(el);
return true;
},
@@ -1914,13 +2082,13 @@ QList<DomItem> DomItem::lookup(QString symbolName, LookupType type, LookupOption
return res;
}
-DomItem DomItem::lookupFirst(QString symbolName, LookupType type, LookupOptions opts,
- ErrorHandler errorHandler)
+DomItem DomItem::lookupFirst(const QString &symbolName, LookupType type, LookupOptions opts,
+ const ErrorHandler &errorHandler) const
{
DomItem res;
visitLookup(
symbolName,
- [&res](DomItem &el) {
+ [&res](const DomItem &el) {
res = el;
return false;
},
@@ -1928,75 +2096,81 @@ DomItem DomItem::lookupFirst(QString symbolName, LookupType type, LookupOptions
return res;
}
-quintptr DomItem::id()
+quintptr DomItem::id() const
{
return visitEl([](auto &&b) { return b->id(); });
}
-Path DomItem::pathFromOwner()
+Path DomItem::pathFromOwner() const
{
return visitEl([this](auto &&e) { return e->pathFromOwner(*this); });
}
-QString DomItem::canonicalFilePath()
+QString DomItem::canonicalFilePath() const
{
return visitEl([this](auto &&e) { return e->canonicalFilePath(*this); });
}
-DomItem DomItem::fileLocationsTree()
+DomItem DomItem::fileLocationsTree() const
{
if (DomItem l = field(Fields::fileLocationsTree))
return l;
- auto res = FileLocations::findAttachedInfo(*this, AttachedInfo::FindOption::SetFoundTreePath);
- if (res && res.foundTreePath.value()) {
- return copy(res.foundTree, res.foundTreePath.value());
+ auto res = FileLocations::findAttachedInfo(*this);
+ if (res && res.foundTreePath) {
+ return copy(res.foundTree, res.foundTreePath);
}
return DomItem();
}
-DomItem DomItem::fileLocations()
+DomItem DomItem::fileLocations() const
{
return fileLocationsTree().field(Fields::infoItem);
}
-MutableDomItem DomItem::makeCopy(DomItem::CopyOption option)
+MutableDomItem DomItem::makeCopy(DomItem::CopyOption option) const
{
if (m_kind == DomType::Empty)
return MutableDomItem();
DomItem o = owner();
if (option == CopyOption::EnvDisconnected) {
- DomItem newItem = std::visit(
- [this, &o](auto &&el) {
- auto copyPtr = el->makeCopy(o);
- return DomItem(m_top, copyPtr, m_ownerPath, copyPtr.get());
- },
- *m_owner);
+ DomItem newItem = std::visit([this, &o](auto &&el) {
+ if constexpr (std::is_same_v<std::decay_t<decltype(el)>, std::monostate>) {
+ return DomItem();
+ } else {
+ auto copyPtr = el->makeCopy(o);
+ return DomItem(m_top, copyPtr, m_ownerPath, copyPtr.get());
+ }
+ }, m_owner);
return MutableDomItem(newItem.path(pathFromOwner()));
}
DomItem env = environment();
std::shared_ptr<DomEnvironment> newEnvPtr;
if (std::shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>()) {
- newEnvPtr = std::make_shared<DomEnvironment>(
- envPtr, envPtr->loadPaths(), envPtr->options());
+ newEnvPtr = std::make_shared<DomEnvironment>(envPtr, envPtr->loadPaths(), envPtr->options(),
+ envPtr->domCreationOptions());
DomBase *eBase = envPtr.get();
- if (std::holds_alternative<DomEnvironment *>(m_element) && eBase
- && std::get<DomEnvironment *>(m_element) == eBase)
+ if (std::holds_alternative<const DomEnvironment *>(m_element) && eBase
+ && std::get<const DomEnvironment *>(m_element) == eBase)
return MutableDomItem(DomItem(newEnvPtr));
} else if (std::shared_ptr<DomUniverse> univPtr = top().ownerAs<DomUniverse>()) {
newEnvPtr = std::make_shared<DomEnvironment>(
QStringList(),
DomEnvironment::Option::SingleThreaded | DomEnvironment::Option::NoDependencies,
- univPtr);
+ DomCreationOption::None, univPtr);
} else {
Q_ASSERT(false);
return {};
}
DomItem newItem = std::visit(
[this, newEnvPtr, &o](auto &&el) {
- auto copyPtr = el->makeCopy(o);
- return DomItem(newEnvPtr, copyPtr, m_ownerPath, copyPtr.get());
+ if constexpr (std::is_same_v<std::decay_t<decltype(el)>, std::monostate>) {
+ return DomItem();
+ } else {
+ auto copyPtr = el->makeCopy(o);
+ return DomItem(newEnvPtr, copyPtr, m_ownerPath, copyPtr.get());
+ }
},
- *m_owner);
+ m_owner);
switch (o.internalKind()) {
case DomType::QmlDirectory:
@@ -2037,7 +2211,7 @@ MutableDomItem DomItem::makeCopy(DomItem::CopyOption option)
return MutableDomItem(newItem.path(pathFromOwner()));
}
-bool DomItem::commitToBase(std::shared_ptr<DomEnvironment> validEnvPtr)
+bool DomItem::commitToBase(const std::shared_ptr<DomEnvironment> &validEnvPtr) const
{
DomItem env = environment();
if (std::shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>()) {
@@ -2046,7 +2220,7 @@ bool DomItem::commitToBase(std::shared_ptr<DomEnvironment> validEnvPtr)
return false;
}
-bool DomItem::visitLocalSymbolsNamed(QString name, function_ref<bool(DomItem &)> visitor)
+bool DomItem::visitLocalSymbolsNamed(const QString &name, function_ref<bool(const DomItem &)> visitor) const
{
if (name.isEmpty()) // no empty symbol
return true;
@@ -2089,7 +2263,7 @@ bool DomItem::visitLocalSymbolsNamed(QString name, function_ref<bool(DomItem &)>
break;
case DomType::MethodInfo: {
DomItem params = field(Fields::parameters);
- if (!params.visitIndexes([name, visitor](DomItem &p) {
+ if (!params.visitIndexes([name, visitor](const DomItem &p) {
const MethodParameter *pPtr = p.as<MethodParameter>();
if (pPtr->name == name && !visitor(p))
return false;
@@ -2123,33 +2297,31 @@ bool DomItem::visitLocalSymbolsNamed(QString name, function_ref<bool(DomItem &)>
return true;
}
-DomItem DomItem::operator[](const QString &cName)
+DomItem DomItem::operator[](const QString &cName) const
{
if (internalKind() == DomType::Map)
return key(cName);
return field(cName);
}
-DomItem DomItem::operator[](QStringView cName)
+DomItem DomItem::operator[](QStringView cName) const
{
if (internalKind() == DomType::Map)
return key(cName.toString());
return field(cName);
}
-DomItem DomItem::operator[](Path p)
+DomItem DomItem::operator[](const Path &p) const
{
return path(p);
}
-QCborValue DomItem::value()
+QCborValue DomItem::value() const
{
- if (internalKind() == DomType::ConstantData)
- return std::get<ConstantData>(m_element).value();
- return QCborValue();
+ return base()->value();
}
-void DomItem::dumpPtr(Sink sink)
+void DomItem::dumpPtr(const Sink &sink) const
{
sink(u"DomItem{ topPtr:");
sink(QString::number((quintptr)topPtr().get(), 16));
@@ -2162,16 +2334,17 @@ void DomItem::dumpPtr(Sink sink)
sink(u"}");
}
-void DomItem::dump(Sink s, int indent,
- function_ref<bool(DomItem &, const PathEls::PathComponent &, DomItem &)> filter)
+void DomItem::dump(
+ const Sink &s, int indent,
+ function_ref<bool(const DomItem &, const PathEls::PathComponent &, const DomItem &)> filter) const
{
visitEl([this, s, indent, filter](auto &&e) { e->dump(*this, s, indent, filter); });
}
FileWriter::Status
-DomItem::dump(QString path,
- function_ref<bool(DomItem &, const PathEls::PathComponent &, DomItem &)> filter,
- int nBackups, int indent, FileWriter *fw)
+DomItem::dump(const QString &path,
+ function_ref<bool(const DomItem &, const PathEls::PathComponent &, const DomItem &)> filter,
+ int nBackups, int indent, FileWriter *fw) const
{
FileWriter localFw;
if (!fw)
@@ -2194,122 +2367,140 @@ DomItem::dump(QString path,
return fw->status;
}
-QString DomItem::toString()
+QString DomItem::toString() const
{
- return dumperToString([this](Sink s){ dump(s); });
+ return dumperToString([this](const Sink &s){ dump(s); });
}
-int DomItem::derivedFrom()
+int DomItem::derivedFrom() const
{
- if (m_owner)
- return std::visit([](auto &&ow) { return ow->derivedFrom(); }, *m_owner);
- return 0;
+ return std::visit([](auto &&ow) {
+ if constexpr (std::is_same_v<std::decay_t<decltype(ow)>, std::monostate>)
+ return 0;
+ else
+ return ow->derivedFrom();
+ }, m_owner);
}
-int DomItem::revision()
+int DomItem::revision() const
{
- if (m_owner)
- return std::visit([](auto &&ow) { return ow->revision(); }, *m_owner);
- else
- return -1;
+ return std::visit([](auto &&ow) {
+ if constexpr (std::is_same_v<std::decay_t<decltype(ow)>, std::monostate>)
+ return -1;
+ else
+ return ow->revision();
+ }, m_owner);
}
-QDateTime DomItem::createdAt()
+QDateTime DomItem::createdAt() const
{
- if (m_owner)
- return std::visit([](auto &&ow) { return ow->createdAt(); }, *m_owner);
- else
- return QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC);
+ return std::visit([](auto &&ow) {
+ if constexpr (std::is_same_v<std::decay_t<decltype(ow)>, std::monostate>)
+ return QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC);
+ else
+ return ow->createdAt();
+ }, m_owner);
}
-QDateTime DomItem::frozenAt()
+QDateTime DomItem::frozenAt() const
{
- if (m_owner)
- return std::visit([](auto &&ow) { return ow->frozenAt(); }, *m_owner);
- else
- return QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC);
+ return std::visit([](auto &&ow) {
+ if constexpr (std::is_same_v<std::decay_t<decltype(ow)>, std::monostate>)
+ return QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC);
+ else
+ return ow->frozenAt();
+ }, m_owner);
}
-QDateTime DomItem::lastDataUpdateAt()
+QDateTime DomItem::lastDataUpdateAt() const
{
- if (m_owner)
- return std::visit([](auto &&ow) { return ow->lastDataUpdateAt(); }, *m_owner);
- else
- return QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC);
+ return std::visit([](auto &&ow) {
+ if constexpr (std::is_same_v<std::decay_t<decltype(ow)>, std::monostate>)
+ return QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC);
+ else
+ return ow->lastDataUpdateAt();
+ }, m_owner);
}
-void DomItem::addError(ErrorMessage msg)
+void DomItem::addError(ErrorMessage &&msg) const
{
- if (m_owner) {
- DomItem myOwner = owner();
- std::visit(
- [this, &myOwner, &msg](auto &&ow) { ow->addError(myOwner, msg.withItem(*this)); },
- *m_owner);
- } else
- defaultErrorHandler(msg.withItem(*this));
+ std::visit([this, &msg](auto &&ow) {
+ if constexpr (std::is_same_v<std::decay_t<decltype(ow)>, std::monostate>)
+ defaultErrorHandler(msg.withItem(*this));
+ else
+ ow->addError(owner(), std::move(msg.withItem(*this)));
+ }, m_owner);
}
-ErrorHandler DomItem::errorHandler()
+ErrorHandler DomItem::errorHandler() const
{
- DomItem self = *this;
- return [self](ErrorMessage m) mutable { self.addError(m); };
+ // We need a copy here. Error handlers may be called when this is gone.
+ return [self = *this](const ErrorMessage &m) { self.addError(ErrorMessage(m)); };
}
-void DomItem::clearErrors(ErrorGroups groups, bool iterate)
+void DomItem::clearErrors(const ErrorGroups &groups, bool iterate) const
{
- if (m_owner) {
- std::visit([&groups](auto &&ow) { ow->clearErrors(groups); }, *m_owner);
- if (iterate)
- iterateSubOwners([groups](DomItem i){
- i.clearErrors(groups, true);
- return true;
- });
+ std::visit([&groups](auto &&ow) {
+ if constexpr (!std::is_same_v<std::decay_t<decltype(ow)>, std::monostate>)
+ ow->clearErrors(groups);
+ }, m_owner);
+
+ if (iterate) {
+ iterateSubOwners([groups](const DomItem &i){
+ i.clearErrors(groups, true);
+ return true;
+ });
}
}
-bool DomItem::iterateErrors(function_ref<bool(DomItem, ErrorMessage)> visitor, bool iterate,
- Path inPath)
+bool DomItem::iterateErrors(
+ function_ref<bool(const DomItem &, const ErrorMessage &)> visitor, bool iterate,
+ Path inPath) const
{
- if (m_owner) {
- DomItem ow = owner();
- if (!std::visit([&ow, visitor,
- inPath](auto &&el) { return el->iterateErrors(ow, visitor, inPath); },
- *m_owner))
- return false;
- if (iterate && !iterateSubOwners([inPath, visitor](DomItem &i) {
- return i.iterateErrors(visitor, true, inPath);
- }))
- return false;
+ if (!std::visit([this, visitor, inPath](auto &&el) {
+ if constexpr (std::is_same_v<std::decay_t<decltype(el)>, std::monostate>)
+ return true;
+ else
+ return el->iterateErrors(owner(), visitor, inPath);
+ }, m_owner)) {
+ return false;
+ }
+
+ if (iterate && !iterateSubOwners([inPath, visitor](const DomItem &i) {
+ return i.iterateErrors(visitor, true, inPath);
+ })) {
+ return false;
}
+
return true;
}
-bool DomItem::iterateSubOwners(function_ref<bool(DomItem &)> visitor)
+bool DomItem::iterateSubOwners(function_ref<bool(const DomItem &)> visitor) const
{
- if (m_owner) {
- DomItem ow = owner();
- return std::visit([&ow, visitor](auto &&o) { return o->iterateSubOwners(ow, visitor); },
- *m_owner);
- }
- return true;
+ return std::visit([this, visitor](auto &&o) {
+ if constexpr (std::is_same_v<std::decay_t<decltype(o)>, std::monostate>)
+ return true;
+ else
+ return o->iterateSubOwners(owner(), visitor);
+ }, m_owner);
}
-bool DomItem::iterateDirectSubpaths(DirectVisitor v)
+bool DomItem::iterateDirectSubpaths(DirectVisitor v) const
{
- return visitMutableEl(
- [this, v](auto &&el) mutable { return el->iterateDirectSubpaths(*this, v); });
+ return visitEl(
+ [this, v](auto &&el) { return el->iterateDirectSubpaths(*this, v); });
}
-DomItem DomItem::subReferencesItem(const PathEls::PathComponent &c, QList<Path> paths)
+DomItem DomItem::subReferencesItem(const PathEls::PathComponent &c, const QList<Path> &paths) const
{
return subListItem(
List::fromQList<Path>(pathFromOwner().appendComponent(c), paths,
- [](DomItem &list, const PathEls::PathComponent &p, Path &el) {
+ [](const DomItem &list, const PathEls::PathComponent &p, const Path &el) {
return list.subReferenceItem(p, el);
}));
}
-DomItem DomItem::subReferenceItem(const PathEls::PathComponent &c, Path referencedObject)
+DomItem DomItem::subReferenceItem(const PathEls::PathComponent &c, const Path &referencedObject) const
{
if (domTypeIsOwningItem(internalKind())) {
return DomItem(m_top, m_owner, m_ownerPath, Reference(referencedObject, Path(c)));
@@ -2319,126 +2510,45 @@ DomItem DomItem::subReferenceItem(const PathEls::PathComponent &c, Path referenc
}
}
-shared_ptr<DomTop> DomItem::topPtr()
-{
- if (m_top)
- return std::visit([](auto &&el) -> shared_ptr<DomTop> { return el; }, *m_top);
- return {};
-}
-
-shared_ptr<OwningItem> DomItem::owningItemPtr()
+shared_ptr<DomTop> DomItem::topPtr() const
{
- if (m_owner)
- return std::visit([](auto &&el) -> shared_ptr<OwningItem> { return el; }, *m_owner);
- return {};
+ return std::visit([](auto &&el) -> shared_ptr<DomTop> {
+ if constexpr (std::is_same_v<std::decay_t<decltype(el)>, std::monostate>)
+ return {};
+ else
+ return el;
+ }, m_top);
}
-const DomBase *DomItem::base()
+shared_ptr<OwningItem> DomItem::owningItemPtr() const
{
- return visitEl([](auto &&el) { return static_cast<const DomBase *>(&(*el)); });
+ return std::visit([](auto &&el) -> shared_ptr<OwningItem> {
+ if constexpr (std::is_same_v<std::decay_t<decltype(el)>, std::monostate>)
+ return {};
+ else
+ return el;
+ }, m_owner);
}
-DomBase *DomItem::mutableBase()
+/*!
+ \internal
+ Returns a pointer to the virtual base pointer to a DomBase.
+*/
+const DomBase *DomItem::base() const
{
- return visitMutableEl([](auto &&el) { return static_cast<DomBase *>(&(*el)); });
+ return visitEl([](auto &&el) -> const DomBase * { return el->domBase(); });
}
-DomItem::DomItem(std::shared_ptr<DomEnvironment> envPtr):
+DomItem::DomItem(const std::shared_ptr<DomEnvironment> &envPtr):
DomItem(envPtr, envPtr, Path(), envPtr.get())
{
}
-DomItem::DomItem(std::shared_ptr<DomUniverse> universePtr):
+DomItem::DomItem(const std::shared_ptr<DomUniverse> &universePtr):
DomItem(universePtr, universePtr, Path(), universePtr.get())
{
}
-void DomItem::loadFile(QString canonicalFilePath, QString logicalPath, QString code,
- QDateTime codeDate, DomTop::Callback callback, LoadOptions loadOptions,
- std::optional<DomType> fileType)
-{
- DomItem topEl = top();
- if (topEl.internalKind() == DomType::DomEnvironment
- || topEl.internalKind() == DomType::DomUniverse) {
- if (auto univ = topEl.ownerAs<DomUniverse>())
- univ->loadFile(*this, canonicalFilePath, logicalPath, code, codeDate, callback,
- loadOptions, fileType);
- else if (auto env = topEl.ownerAs<DomEnvironment>()) {
- if (env->options() & DomEnvironment::Option::NoDependencies)
- env->loadFile(topEl, canonicalFilePath, logicalPath, code, codeDate, callback,
- DomTop::Callback(), DomTop::Callback(), loadOptions, fileType);
- else
- env->loadFile(topEl, canonicalFilePath, logicalPath, code, codeDate,
- DomTop::Callback(), DomTop::Callback(), callback, loadOptions,
- fileType);
- } else
- Q_ASSERT(false && "expected either DomUniverse or DomEnvironment cast to succeed");
- } else {
- addError(myErrors().warning(tr("loadFile called without DomEnvironment or DomUniverse.")));
- callback(Paths::qmlFileInfoPath(canonicalFilePath), DomItem::empty, DomItem::empty);
- }
-}
-
-void DomItem::loadFile(QString filePath, QString logicalPath, DomTop::Callback callback,
- LoadOptions loadOptions, std::optional<DomType> fileType)
-{
- DomItem topEl = top();
- if (topEl.internalKind() == DomType::DomEnvironment
- || topEl.internalKind() == DomType::DomUniverse) {
- if (auto univ = topEl.ownerAs<DomUniverse>())
- univ->loadFile(*this, filePath, logicalPath, callback, loadOptions);
- else if (auto env = topEl.ownerAs<DomEnvironment>()) {
- if (env->options() & DomEnvironment::Option::NoDependencies)
- env->loadFile(topEl, filePath, logicalPath, callback, DomTop::Callback(),
- DomTop::Callback(), loadOptions, fileType);
- else
- env->loadFile(topEl, filePath, logicalPath, DomTop::Callback(), DomTop::Callback(),
- callback, loadOptions, fileType);
- } else
- Q_ASSERT(false && "expected either DomUniverse or DomEnvironment cast to succeed");
- } else {
- addError(myErrors().warning(tr("loadFile called without DomEnvironment or DomUniverse.")));
- callback(Paths::qmlFileInfoPath(filePath), DomItem::empty, DomItem::empty);
- }
-}
-
-void DomItem::loadModuleDependency(QString uri, Version version,
- std::function<void(Path, DomItem &, DomItem &)> callback,
- ErrorHandler errorHandler)
-{
- DomItem topEl = top();
- if (topEl.internalKind() == DomType::DomEnvironment) {
- if (auto envPtr = topEl.ownerAs<DomEnvironment>()) {
- if (envPtr->options() & DomEnvironment::Option::NoDependencies)
- envPtr->loadModuleDependency(topEl, uri, version, callback, nullptr, errorHandler);
- else
- envPtr->loadModuleDependency(topEl, uri, version, nullptr, callback, errorHandler);
- } else
- Q_ASSERT(false && "loadDependency expected the DomEnvironment cast to succeed");
- } else {
- addError(myErrors().warning(tr("loadModuleDependency called without DomEnvironment.")));
- callback(Paths::moduleScopePath(uri, version), DomItem::empty, DomItem::empty);
- }
-}
-
-void DomItem::loadBuiltins(std::function<void(Path, DomItem &, DomItem &)> callback, ErrorHandler h)
-{
- DomItem env = environment();
- if (std::shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>())
- envPtr->loadBuiltins(env, callback, h);
- else
- myErrors().error(tr("Cannot load builtins without DomEnvironment")).handle(h);
-}
-
-void DomItem::loadPendingDependencies()
-{
- DomItem env = environment();
- if (std::shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>())
- envPtr->loadPendingDependencies(env);
- else
- myErrors().error(tr("Called loadPendingDependencies without environment")).handle();
-}
-
/*!
\brief Creates a new document with the given code
@@ -2447,54 +2557,57 @@ The fileType should normally be QmlFile, but you might want to load a qmltypes f
example and interpret it as qmltypes file (not plain Qml), or as JsFile. In those case
set the file type accordingly.
*/
-DomItem DomItem::fromCode(QString code, DomType fileType)
+DomItem DomItem::fromCode(const QString &code, DomType fileType)
{
if (code.isEmpty())
return DomItem();
- DomItem env =
+ auto env =
DomEnvironment::create(QStringList(),
QQmlJS::Dom::DomEnvironment::Option::SingleThreaded
| QQmlJS::Dom::DomEnvironment::Option::NoDependencies);
DomItem tFile;
- env.loadFile(
- QString(), QString(), code, QDateTime::currentDateTimeUtc(),
+
+ env->loadFile(
+ FileToLoad::fromMemory(env, QString(), code),
[&tFile](Path, const DomItem &, const DomItem &newIt) { tFile = newIt; },
- LoadOption::DefaultLoad, fileType);
- env.loadPendingDependencies();
+ std::make_optional(fileType));
+ env->loadPendingDependencies();
return tFile.fileObject();
}
Empty::Empty()
{}
-Path Empty::pathFromOwner(DomItem &) const
+Path Empty::pathFromOwner(const DomItem &) const
{
return Path();
}
-Path Empty::canonicalPath(DomItem &) const
+Path Empty::canonicalPath(const DomItem &) const
{
return Path();
}
-bool Empty::iterateDirectSubpaths(DomItem &, DirectVisitor)
+bool Empty::iterateDirectSubpaths(const DomItem &, DirectVisitor) const
{
return true;
}
-DomItem Empty::containingObject(DomItem &self) const
+DomItem Empty::containingObject(const DomItem &self) const
{
return self;
}
-void Empty::dump(DomItem &, Sink s, int,
- function_ref<bool(DomItem &, const PathEls::PathComponent &, DomItem &)>) const
+void Empty::dump(
+ const DomItem &, const Sink &s, int,
+ function_ref<bool(const DomItem &, const PathEls::PathComponent &, const DomItem &)>) const
{
s(u"null");
}
-Map::Map(Path pathFromOwner, Map::LookupFunction lookup, Keys keys, QString targetType)
+Map::Map(const Path &pathFromOwner, const Map::LookupFunction &lookup,
+ const Keys &keys, const QString &targetType)
: DomElement(pathFromOwner), m_lookup(lookup), m_keys(keys), m_targetType(targetType)
{}
@@ -2503,31 +2616,31 @@ quintptr Map::id() const
return quintptr(0);
}
-bool Map::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool Map::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
QSet<QString> ksSet = keys(self);
QStringList ksList = QStringList(ksSet.begin(), ksSet.end());
std::sort(ksList.begin(), ksList.end());
- for (QString k : ksList) {
+ for (const QString &k : std::as_const(ksList)) {
if (!visitor(PathEls::Key(k), [&self, this, k]() { return key(self, k); }))
return false;
}
return true;
}
-const QSet<QString> Map::keys(DomItem &self) const
+const QSet<QString> Map::keys(const DomItem &self) const
{
return m_keys(self);
}
-DomItem Map::key(DomItem &self, QString name) const
+DomItem Map::key(const DomItem &self, const QString &name) const
{
return m_lookup(self, name);
}
void DomBase::dump(
- DomItem &self, Sink sink, int indent,
- function_ref<bool(DomItem &, const PathEls::PathComponent &, DomItem &)> filter) const
+ const DomItem &self, const Sink &sink, int indent,
+ function_ref<bool(const DomItem &, const PathEls::PathComponent &, const DomItem &)> filter) const
{
bool comma = false;
DomKind dK = self.domKind();
@@ -2566,6 +2679,9 @@ void DomBase::dump(
case DomKind::Map:
sink(u"{");
break;
+ case DomKind::ScriptElement:
+ // nothing to print
+ break;
}
auto closeParens = qScopeGuard(
[dK, sink, indent]{
@@ -2586,6 +2702,9 @@ void DomBase::dump(
sinkNewline(sink, indent);
sink(u"}");
break;
+ case DomKind::ScriptElement:
+ // nothing to print
+ break;
}
});
index_type idx = 0;
@@ -2639,8 +2758,9 @@ void DomBase::dump(
});
}
-List::List(Path pathFromOwner, List::LookupFunction lookup, List::Length length,
- List::IteratorFunction iterator, QString elType):
+List::List(const Path &pathFromOwner, const List::LookupFunction &lookup,
+ const List::Length &length, const List::IteratorFunction &iterator,
+ const QString &elType):
DomElement(pathFromOwner), m_lookup(lookup), m_length(length), m_iterator(iterator),
m_elType(elType)
{}
@@ -2651,12 +2771,12 @@ quintptr List::id() const
}
void List::dump(
- DomItem &self, Sink sink, int indent,
- function_ref<bool(DomItem &, const PathEls::PathComponent &, DomItem &)> filter) const
+ const DomItem &self, const Sink &sink, int indent,
+ function_ref<bool(const DomItem &, const PathEls::PathComponent &, const DomItem &)> filter) const
{
bool first = true;
sink(u"[");
- const_cast<List *>(this)->iterateDirectSubpaths(
+ iterateDirectSubpaths(
self,
[&self, indent, &first, sink, filter](const PathEls::PathComponent &c,
function_ref<DomItem()> itemF) {
@@ -2674,7 +2794,7 @@ void List::dump(
sink(u"]");
}
-bool List::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool List::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
if (m_iterator) {
return m_iterator(self, [visitor](index_type i, function_ref<DomItem()> itemF) {
@@ -2689,22 +2809,22 @@ bool List::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
return true;
}
-index_type List::indexes(DomItem &self) const
+index_type List::indexes(const DomItem &self) const
{
return m_length(self);
}
-DomItem List::index(DomItem &self, index_type index) const
+DomItem List::index(const DomItem &self, index_type index) const
{
return m_lookup(self, index);
}
-void List::writeOut(DomItem &self, OutWriter &ow, bool compact) const
+void List::writeOut(const DomItem &self, OutWriter &ow, bool compact) const
{
- ow.writeRegion(u"leftSquareBrace", u"[");
+ ow.writeRegion(LeftBracketRegion);
int baseIndent = ow.increaseIndent(1);
bool first = true;
- const_cast<List *>(this)->iterateDirectSubpaths(
+ iterateDirectSubpaths(
self,
[&ow, &first, compact](const PathEls::PathComponent &, function_ref<DomItem()> elF) {
if (first)
@@ -2720,30 +2840,30 @@ void List::writeOut(DomItem &self, OutWriter &ow, bool compact) const
if (!compact && !first)
ow.newline();
ow.decreaseIndent(1, baseIndent);
- ow.writeRegion(u"rightSquareBrace", u"]");
+ ow.writeRegion(RightBracketRegion);
}
-DomElement::DomElement(Path pathFromOwner) : m_pathFromOwner(pathFromOwner) { }
+DomElement::DomElement(const Path &pathFromOwner) : m_pathFromOwner(pathFromOwner) { }
-Path DomElement::pathFromOwner(DomItem &) const
+Path DomElement::pathFromOwner(const DomItem &) const
{
Q_ASSERT(m_pathFromOwner && "uninitialized DomElement");
return m_pathFromOwner;
}
-Path DomElement::canonicalPath(DomItem &self) const
+Path DomElement::canonicalPath(const DomItem &self) const
{
Q_ASSERT(m_pathFromOwner && "uninitialized DomElement");
return self.owner().canonicalPath().path(m_pathFromOwner);
}
-DomItem DomElement::containingObject(DomItem &self) const
+DomItem DomElement::containingObject(const DomItem &self) const
{
Q_ASSERT(m_pathFromOwner && "uninitialized DomElement");
return DomBase::containingObject(self);
}
-void DomElement::updatePathFromOwner(Path newPath)
+void DomElement::updatePathFromOwner(const Path &newPath)
{
//if (!domTypeCanBeInline(kind()))
m_pathFromOwner = newPath;
@@ -2751,7 +2871,7 @@ void DomElement::updatePathFromOwner(Path newPath)
bool Reference::shouldCache() const
{
- for (Path p : referredObjectPath) {
+ for (const Path &p : referredObjectPath) {
switch (p.headKind()) {
case Path::Kind::Current:
switch (p.headCurrent()) {
@@ -2776,7 +2896,7 @@ bool Reference::shouldCache() const
return false;
}
-Reference::Reference(Path referredObject, Path pathFromOwner, const SourceLocation &)
+Reference::Reference(const Path &referredObject, const Path &pathFromOwner, const SourceLocation &)
: DomElement(pathFromOwner), referredObjectPath(referredObject)
{
}
@@ -2786,7 +2906,7 @@ quintptr Reference::id() const
return quintptr(0);
}
-bool Reference::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool Reference::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = true;
cont = cont && self.dvValueLazyField(visitor, Fields::referredObjectPath, [this]() {
@@ -2797,7 +2917,7 @@ bool Reference::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
return cont;
}
-DomItem Reference::field(DomItem &self, QStringView name) const
+DomItem Reference::field(const DomItem &self, QStringView name) const
{
if (Fields::referredObjectPath == name)
return self.subDataItemField(Fields::referredObjectPath, referredObjectPath.toString());
@@ -2806,22 +2926,22 @@ DomItem Reference::field(DomItem &self, QStringView name) const
return DomItem();
}
-QList<QString> Reference::fields(DomItem &) const
+QList<QString> Reference::fields(const DomItem &) const
{
return QList<QString>({QString::fromUtf16(Fields::referredObjectPath), QString::fromUtf16(Fields::get)});
}
-DomItem Reference::index(DomItem &, index_type) const
+DomItem Reference::index(const DomItem &, index_type) const
{
return DomItem();
}
-DomItem Reference::key(DomItem &, QString) const
+DomItem Reference::key(const DomItem &, const QString &) const
{
return DomItem();
}
-DomItem Reference::get(DomItem &self, ErrorHandler h, QList<Path> *visitedRefs) const
+DomItem Reference::get(const DomItem &self, const ErrorHandler &h, QList<Path> *visitedRefs) const
{
DomItem res;
if (referredObjectPath) {
@@ -2857,7 +2977,7 @@ DomItem Reference::get(DomItem &self, ErrorHandler h, QList<Path> *visitedRefs)
QList<Path> visitedRefsLocal;
self.resolve(
referredObjectPath,
- [&res](Path, DomItem &el) {
+ [&res](Path, const DomItem &el) {
res = el;
return false;
},
@@ -2870,7 +2990,8 @@ DomItem Reference::get(DomItem &self, ErrorHandler h, QList<Path> *visitedRefs)
return res;
}
-QList<DomItem> Reference::getAll(DomItem &self, ErrorHandler h, QList<Path> *visitedRefs) const
+QList<DomItem> Reference::getAll(
+ const DomItem &self, const ErrorHandler &h, QList<Path> *visitedRefs) const
{
QList<DomItem> res;
if (referredObjectPath) {
@@ -2893,7 +3014,7 @@ QList<DomItem> Reference::getAll(DomItem &self, ErrorHandler h, QList<Path> *vis
}
if (!cachedPaths.isEmpty()) {
bool outdated = false;
- for (Path p : cachedPaths) {
+ for (const Path &p : cachedPaths) {
DomItem newEl = env.path(p);
if (!newEl) {
outdated = true;
@@ -2912,22 +3033,23 @@ QList<DomItem> Reference::getAll(DomItem &self, ErrorHandler h, QList<Path> *vis
}
self.resolve(
referredObjectPath,
- [&res](Path, DomItem &el) {
+ [&res](Path, const DomItem &el) {
res.append(el);
return true;
},
h, ResolveOption::None, referredObjectPath, visitedRefs);
if (env) {
QList<Path> canonicalPaths;
- for (DomItem i : res) {
+ for (const DomItem &i : res) {
if (i)
canonicalPaths.append(i.canonicalPath());
else
qCWarning(refLog)
<< "getAll of reference at " << selfPath << " visits empty items.";
}
- RefCacheEntry::addForPath(env, selfPath,
- RefCacheEntry { RefCacheEntry::Cached::All, canonicalPaths });
+ RefCacheEntry::addForPath(
+ env, selfPath,
+ RefCacheEntry { RefCacheEntry::Cached::All, std::move(canonicalPaths) });
}
}
return res;
@@ -2958,7 +3080,7 @@ OwningItem::OwningItem(int derivedFrom)
m_frozenAt(QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC))
{}
-OwningItem::OwningItem(int derivedFrom, QDateTime lastDataUpdateAt)
+OwningItem::OwningItem(int derivedFrom, const QDateTime &lastDataUpdateAt)
: m_derivedFrom(derivedFrom),
m_revision(nextRevision()),
m_createdAt(QDateTime::currentDateTimeUtc()),
@@ -2992,14 +3114,14 @@ int OwningItem::nextRevision()
return ++nextRev;
}
-bool OwningItem::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool OwningItem::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = true;
cont = cont && self.dvItemField(visitor, Fields::errors, [&self, this]() {
QMultiMap<Path, ErrorMessage> myErrors = localErrors();
return self.subMapItem(Map(
self.pathFromOwner().field(Fields::errors),
- [myErrors](DomItem &map, QString key) {
+ [myErrors](const DomItem &map, const QString &key) {
auto it = myErrors.find(Path::fromString(key));
if (it != myErrors.end())
return map.subDataItem(PathEls::Key(key), it->toCbor(),
@@ -3007,7 +3129,7 @@ bool OwningItem::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
else
return DomItem();
},
- [myErrors](DomItem &) {
+ [myErrors](const DomItem &) {
QSet<QString> res;
auto it = myErrors.keyBegin();
auto end = myErrors.keyEnd();
@@ -3020,7 +3142,7 @@ bool OwningItem::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
return cont;
}
-DomItem OwningItem::containingObject(DomItem &self) const
+DomItem OwningItem::containingObject(const DomItem &self) const
{
Source s = self.canonicalPath().split();
if (s.pathFromSource) {
@@ -3078,12 +3200,12 @@ void OwningItem::refreshedDataAt(QDateTime tNew)
m_lastDataUpdateAt = tNew;
}
-void OwningItem::addError(DomItem &, ErrorMessage msg)
+void OwningItem::addError(const DomItem &, ErrorMessage &&msg)
{
- addErrorLocal(msg);
+ addErrorLocal(std::move(msg));
}
-void OwningItem::addErrorLocal(ErrorMessage msg)
+void OwningItem::addErrorLocal(ErrorMessage &&msg)
{
QMutexLocker l(mutex());
quint32 &c = m_errorsCounts[msg];
@@ -3092,7 +3214,7 @@ void OwningItem::addErrorLocal(ErrorMessage msg)
m_errors.insert(msg.path, msg);
}
-void OwningItem::clearErrors(ErrorGroups groups)
+void OwningItem::clearErrors(const ErrorGroups &groups)
{
QMutexLocker l(mutex());
auto it = m_errors.begin();
@@ -3104,8 +3226,9 @@ void OwningItem::clearErrors(ErrorGroups groups)
}
}
-bool OwningItem::iterateErrors(DomItem &self, function_ref<bool(DomItem, ErrorMessage)> visitor,
- Path inPath)
+bool OwningItem::iterateErrors(
+ const DomItem &self, function_ref<bool(const DomItem &, const ErrorMessage &)> visitor,
+ const Path &inPath)
{
QMultiMap<Path, ErrorMessage> myErrors;
{
@@ -3121,7 +3244,7 @@ bool OwningItem::iterateErrors(DomItem &self, function_ref<bool(DomItem, ErrorMe
return true;
}
-bool OwningItem::iterateSubOwners(DomItem &self, function_ref<bool(DomItem &owner)> visitor)
+bool OwningItem::iterateSubOwners(const DomItem &self, function_ref<bool(const DomItem &owner)> visitor)
{
return self.iterateDirectSubpaths(
[&self, visitor](const PathEls::PathComponent &, function_ref<DomItem()> iF) {
@@ -3135,13 +3258,11 @@ bool OwningItem::iterateSubOwners(DomItem &self, function_ref<bool(DomItem &owne
});
}
-bool operator==(const DomItem &o1c, const DomItem &o2c)
+bool operator==(const DomItem &o1, const DomItem &o2)
{
- DomItem &o1 = *const_cast<DomItem *>(&o1c);
- DomItem &o2 = *const_cast<DomItem *>(&o2c);
if (o1.m_kind != o2.m_kind)
return false;
- return o1.visitMutableEl([&o1, &o2](auto &&el1) {
+ return o1.visitEl([&o1, &o2](auto &&el1) {
auto &&el2 = std::get<std::decay_t<decltype(el1)>>(o2.m_element);
auto id1 = el1->id();
auto id2 = el2->id();
@@ -3162,10 +3283,10 @@ bool operator==(const DomItem &o1c, const DomItem &o2c)
ErrorHandler MutableDomItem::errorHandler()
{
MutableDomItem self;
- return [&self](ErrorMessage m) { self.addError(m); };
+ return [&self](const ErrorMessage &m) { self.addError(ErrorMessage(m)); };
}
-MutableDomItem MutableDomItem::addPrototypePath(Path prototypePath)
+MutableDomItem MutableDomItem::addPrototypePath(const Path &prototypePath)
{
if (QmlObject *el = mutableAs<QmlObject>()) {
return path(el->addPrototypePath(prototypePath));
@@ -3175,7 +3296,7 @@ MutableDomItem MutableDomItem::addPrototypePath(Path prototypePath)
}
}
-MutableDomItem MutableDomItem::setNextScopePath(Path nextScopePath)
+MutableDomItem MutableDomItem::setNextScopePath(const Path &nextScopePath)
{
if (QmlObject *el = mutableAs<QmlObject>()) {
el->setNextScopePath(nextScopePath);
@@ -3217,7 +3338,7 @@ MutableDomItem MutableDomItem::setMethods(QMultiMap<QString, MethodInfo> functio
return {};
}
-MutableDomItem MutableDomItem::setChildren(QList<QmlObject> children)
+MutableDomItem MutableDomItem::setChildren(const QList<QmlObject> &children)
{
if (QmlObject *el = mutableAs<QmlObject>()) {
el->setChildren(children);
@@ -3227,7 +3348,7 @@ MutableDomItem MutableDomItem::setChildren(QList<QmlObject> children)
return {};
}
-MutableDomItem MutableDomItem::setAnnotations(QList<QmlObject> annotations)
+MutableDomItem MutableDomItem::setAnnotations(const QList<QmlObject> &annotations)
{
if (QmlObject *el = mutableAs<QmlObject>())
el->setAnnotations(annotations);
@@ -3248,7 +3369,7 @@ MutableDomItem MutableDomItem::setAnnotations(QList<QmlObject> annotations)
}
return field(Fields::annotations);
}
-MutableDomItem MutableDomItem::setScript(std::shared_ptr<ScriptExpression> exp)
+MutableDomItem MutableDomItem::setScript(const std::shared_ptr<ScriptExpression> &exp)
{
switch (internalKind()) {
case DomType::Binding:
@@ -3265,8 +3386,14 @@ MutableDomItem MutableDomItem::setScript(std::shared_ptr<ScriptExpression> exp)
break;
case DomType::MethodParameter:
if (MethodParameter *p = mutableAs<MethodParameter>()) {
- p->defaultValue = exp;
- return field(Fields::body);
+ if (exp->expressionType() == ScriptExpression::ExpressionType::ArgInitializer) {
+ p->defaultValue = exp;
+ return field(Fields::defaultValue);
+ }
+ if (exp->expressionType() == ScriptExpression::ExpressionType::ArgumentStructure) {
+ p->value = exp;
+ return field(Fields::value);
+ }
}
break;
case DomType::ScriptExpression:
@@ -3280,7 +3407,7 @@ MutableDomItem MutableDomItem::setScript(std::shared_ptr<ScriptExpression> exp)
return MutableDomItem();
}
-MutableDomItem MutableDomItem::setCode(QString code)
+MutableDomItem MutableDomItem::setCode(const QString &code)
{
DomItem it = item();
switch (it.internalKind()) {
@@ -3323,7 +3450,8 @@ MutableDomItem MutableDomItem::setCode(QString code)
return MutableDomItem();
}
-MutableDomItem MutableDomItem::addPropertyDef(PropertyDefinition propertyDef, AddOption option)
+MutableDomItem MutableDomItem::addPropertyDef(
+ const PropertyDefinition &propertyDef, AddOption option)
{
if (QmlObject *el = mutableAs<QmlObject>())
return el->addPropertyDef(*this, propertyDef, option);
@@ -3341,7 +3469,7 @@ MutableDomItem MutableDomItem::addBinding(Binding binding, AddOption option)
return MutableDomItem();
}
-MutableDomItem MutableDomItem::addMethod(MethodInfo functionDef, AddOption option)
+MutableDomItem MutableDomItem::addMethod(const MethodInfo &functionDef, AddOption option)
{
if (QmlObject *el = mutableAs<QmlObject>())
return el->addMethod(*this, functionDef, option);
@@ -3394,17 +3522,17 @@ MutableDomItem MutableDomItem::addAnnotation(QmlObject annotation)
return MutableDomItem(owner().item(), res);
}
-MutableDomItem MutableDomItem::addPreComment(const Comment &comment, QString regionName)
+MutableDomItem MutableDomItem::addPreComment(const Comment &comment, FileLocationRegion region)
{
index_type idx;
MutableDomItem rC = field(Fields::comments);
if (auto rcPtr = rC.mutableAs<RegionComments>()) {
- auto &preList = rcPtr->regionComments[regionName].preComments;
- idx = preList.size();
- preList.append(comment);
+ auto commentedElement = rcPtr->regionComments()[region];
+ idx = commentedElement.preComments().size();
+ commentedElement.addComment(comment);
MutableDomItem res = path(Path::Field(Fields::comments)
.field(Fields::regionComments)
- .key(regionName)
+ .key(fileLocationRegionName(region))
.field(Fields::preComments)
.index(idx));
Q_ASSERT(res);
@@ -3413,17 +3541,17 @@ MutableDomItem MutableDomItem::addPreComment(const Comment &comment, QString reg
return MutableDomItem();
}
-MutableDomItem MutableDomItem::addPostComment(const Comment &comment, QString regionName)
+MutableDomItem MutableDomItem::addPostComment(const Comment &comment, FileLocationRegion region)
{
index_type idx;
MutableDomItem rC = field(Fields::comments);
if (auto rcPtr = rC.mutableAs<RegionComments>()) {
- auto &postList = rcPtr->regionComments[regionName].postComments;
- idx = postList.size();
- postList.append(comment);
+ auto commentedElement = rcPtr->regionComments()[region];
+ idx = commentedElement.postComments().size();
+ commentedElement.addComment(comment);
MutableDomItem res = path(Path::Field(Fields::comments)
.field(Fields::regionComments)
- .key(regionName)
+ .key(fileLocationRegionName(region))
.field(Fields::postComments)
.index(idx));
Q_ASSERT(res);
@@ -3434,7 +3562,7 @@ MutableDomItem MutableDomItem::addPostComment(const Comment &comment, QString re
QDebug operator<<(QDebug debug, const DomItem &c)
{
- dumperToQDebug([&c](Sink s) { const_cast<DomItem *>(&c)->dump(s); }, debug);
+ dumperToQDebug([&c](const Sink &s) { c.dump(s); }, debug);
return debug;
}
@@ -3445,7 +3573,7 @@ QDebug operator<<(QDebug debug, const MutableDomItem &c)
<< ", " << cc.canonicalPath().toString() << ")";
}
-bool ListPBase::iterateDirectSubpaths(DomItem &self, DirectVisitor v)
+bool ListPBase::iterateDirectSubpaths(const DomItem &self, DirectVisitor v) const
{
index_type len = index_type(m_pList.size());
for (index_type i = 0; i < len; ++i) {
@@ -3455,9 +3583,9 @@ bool ListPBase::iterateDirectSubpaths(DomItem &self, DirectVisitor v)
return true;
}
-void ListPBase::writeOut(DomItem &self, OutWriter &ow, bool compact) const
+void ListPBase::writeOut(const DomItem &self, OutWriter &ow, bool compact) const
{
- ow.writeRegion(u"leftSquareBrace", u"[");
+ ow.writeRegion(LeftBracketRegion);
int baseIndent = ow.increaseIndent(1);
bool first = true;
index_type len = index_type(m_pList.size());
@@ -3474,7 +3602,36 @@ void ListPBase::writeOut(DomItem &self, OutWriter &ow, bool compact) const
if (!compact && !first)
ow.newline();
ow.decreaseIndent(1, baseIndent);
- ow.writeRegion(u"rightSquareBrace", u"]");
+ ow.writeRegion(RightBracketRegion);
+}
+
+QQmlJSScope::ConstPtr ScriptElement::semanticScope()
+{
+ return m_scope;
+}
+void ScriptElement::setSemanticScope(const QQmlJSScope::ConstPtr &scope)
+{
+ m_scope = scope;
+}
+
+/*!
+ \internal
+ \brief Returns a pointer to the virtual base for virtual method calls.
+
+ A helper to call virtual methods without having to call std::visit(...).
+ */
+ScriptElement::PointerType<ScriptElement> ScriptElementVariant::base() const
+{
+ if (!m_data)
+ return nullptr;
+
+ return std::visit(
+ [](auto &&e) {
+ // std::reinterpret_pointer_cast does not exist on qnx it seems...
+ return std::shared_ptr<ScriptElement>(
+ e, static_cast<ScriptElement *>(e.get()));
+ },
+ *m_data);
}
} // end namespace Dom