aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmldom/qqmldomscriptelements.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qmldom/qqmldomscriptelements.cpp')
-rw-r--r--src/qmldom/qqmldomscriptelements.cpp355
1 files changed, 355 insertions, 0 deletions
diff --git a/src/qmldom/qqmldomscriptelements.cpp b/src/qmldom/qqmldomscriptelements.cpp
new file mode 100644
index 0000000000..4bde2abd09
--- /dev/null
+++ b/src/qmldom/qqmldomscriptelements.cpp
@@ -0,0 +1,355 @@
+// Copyright (C) 2023 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 "qqmldom_utils_p.h"
+#include "qqmldomitem_p.h"
+#include "qqmldompath_p.h"
+#include "qqmldomscriptelements_p.h"
+#include <memory>
+#include <utility>
+#include <variant>
+
+using namespace QQmlJS::Dom::ScriptElements;
+using QQmlJS::Dom::DomType;
+using QQmlJS::Dom::ScriptElement;
+using QQmlJS::Dom::ScriptElementVariant;
+
+/*!
+ \internal
+ \class ScriptElementBase
+
+ The base class for all script elements.
+
+ Derived classes should implement createFileLocations, DomElement::updatePathFromOwner and
+ DomBase::iterateDirectSubpaths. Furthermore, they need their own DomType enum.
+
+ updatePathFromOwner and createFileLocations should be called on the script element root node
+ after it was constructed for the DomItem-wrapping to work correctly. Without it, methods like
+ iterateDirectSubpaths and all the stuff in DomItem will not work.
+
+ createFileLocations does not work without having the pathFromOwner set
+ first via updatePathFromOwner.
+
+ In derived classes, the updatePathFromOwner-implementation should call the base implementation
+ and also call recursively updatePathFromOwner on the derived class's children.
+
+ See \l ScriptElementBase::createFileLocations for the createFileLocations implementation in
+ derived classes.
+
+ Derived classes need to implement iterateDirectSubpaths to comply with the DomItem interface.
+*/
+
+/*!
+ \internal
+ \fn ScriptElementBase::createFileLocations
+
+ Usually, all the visits/recursive calls to DOM elements can be done using the DomItem interface,
+ once all the DOM has been constructed.
+
+ During construction, createFileLocations can be used to annotate the DOM representation with the
+ corresponding source locations, which are needed, e.g., to find the corresponding DOM element
+ from a certain text position. When called, createFileLocations sets an entry for itself in the
+ FileLocationsTree.
+
+ Derived classes should call the base implemenatation and recursively call createFileLocations on
+ all their children.
+
+ Usually, only the root of the script DOM element requires one createFileLocations call after
+ construction \b{and} after a pathFromOwner was set using updatePathFromOwner.
+
+*/
+
+/*!
+ \internal
+ \class ScriptList
+
+ A Helper class for writing script elements that contain lists, helps for implementing the
+ recursive calls of iterateDirectSubpaths, updatePathFromOwner and createFileLocations.
+*/
+
+/*!
+ \internal
+ Helper for fields with elements in iterateDirectSubpaths.
+ */
+static bool wrap(const QQmlJS::Dom::DomItem &self, QQmlJS::Dom::DirectVisitor visitor, QStringView field,
+ const ScriptElementVariant &value)
+{
+ if (!value)
+ return true;
+
+ const bool b =
+ self.dvItemField(visitor, field, [&self, field, &value]() -> QQmlJS::Dom::DomItem {
+ const QQmlJS::Dom::Path pathFromOwner{ self.pathFromOwner().field(field) };
+ return self.subScriptElementWrapperItem(value);
+ });
+ return b;
+}
+
+/*!
+ \internal
+ Helper for fields with lists in iterateDirectSubpaths.
+ */
+static bool wrap(const QQmlJS::Dom::DomItem &self, QQmlJS::Dom::DirectVisitor visitor, QStringView field,
+ const ScriptList &value)
+{
+ const bool b =
+ self.dvItemField(visitor, field, [&self, field, &value]() -> QQmlJS::Dom::DomItem {
+ const QQmlJS::Dom::Path pathFromOwner{ self.pathFromOwner().field(field) };
+ return self.subListItem(value.asList(pathFromOwner));
+ });
+ return b;
+}
+
+bool GenericScriptElement::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
+{
+ bool cont = true;
+ for (auto it = m_children.begin(); it != m_children.end(); ++it) {
+ cont &= std::visit(
+ [&self, &visitor, &it](auto &&e) { return wrap(self, visitor, it->first, e); },
+ it->second);
+ }
+ return cont;
+}
+
+void GenericScriptElement::updatePathFromOwner(const Path &p)
+{
+ BaseT::updatePathFromOwner(p);
+ for (auto it = m_children.begin(); it != m_children.end(); ++it) {
+ std::visit(qOverloadedVisitor{ [&p, &it](ScriptElementVariant &e) {
+ e.base()->updatePathFromOwner(p.field(it->first));
+ },
+ [&p, &it](ScriptList &list) {
+ list.updatePathFromOwner(p.field(it->first));
+ } },
+ it->second);
+ }
+}
+
+void GenericScriptElement::createFileLocations(const FileLocations::Tree &base)
+{
+ BaseT::createFileLocations(base);
+ for (auto it = m_children.begin(); it != m_children.end(); ++it) {
+ std::visit(
+ qOverloadedVisitor{
+ [&base](ScriptElementVariant &e) { e.base()->createFileLocations(base); },
+ [&base](ScriptList &list) { list.createFileLocations(base); } },
+ it->second);
+ }
+}
+
+bool BlockStatement::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
+{
+ // TODO: test me
+ bool cont = true;
+ cont &= wrap(self, visitor, Fields::statements, m_statements);
+ return cont;
+}
+
+void BlockStatement::updatePathFromOwner(const Path &p)
+{
+ BaseT::updatePathFromOwner(p);
+ m_statements.updatePathFromOwner(p.field(Fields::statements));
+}
+
+void BlockStatement::createFileLocations(const FileLocations::Tree &base)
+{
+ BaseT::createFileLocations(base);
+ m_statements.createFileLocations(base);
+}
+
+bool IdentifierExpression::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
+{
+ bool cont = true;
+ cont &= self.dvValueField(visitor, Fields::identifier, m_name);
+ return cont;
+}
+
+bool Literal::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
+{
+ bool cont = true;
+ std::visit([&cont, &visitor,
+ &self](auto &&e) { cont &= self.dvValueField(visitor, Fields::value, e); },
+ m_value);
+ return cont;
+}
+
+bool IfStatement::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
+{
+ // TODO: test me
+ bool cont = true;
+ cont &= wrap(self, visitor, Fields::condition, m_condition);
+ cont &= wrap(self, visitor, Fields::consequence, m_consequence);
+ cont &= wrap(self, visitor, Fields::alternative, m_alternative);
+ return cont;
+}
+
+void IfStatement::updatePathFromOwner(const Path &p)
+{
+ BaseT::updatePathFromOwner(p);
+ if (auto ptr = m_condition.base())
+ ptr->updatePathFromOwner(p.field(Fields::condition));
+ if (auto ptr = m_consequence.base())
+ ptr->updatePathFromOwner(p.field(Fields::consequence));
+ if (auto ptr = m_alternative.base())
+ ptr->updatePathFromOwner(p.field(Fields::alternative));
+}
+
+void IfStatement::createFileLocations(const FileLocations::Tree &base)
+{
+ BaseT::createFileLocations(base);
+ if (auto ptr = m_condition.base())
+ ptr->createFileLocations(base);
+ if (auto ptr = m_consequence.base())
+ ptr->createFileLocations(base);
+ if (auto ptr = m_alternative.base())
+ ptr->createFileLocations(base);
+}
+
+bool ForStatement::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
+{
+ bool cont = true;
+ cont &= wrap(self, visitor, Fields::initializer, m_initializer);
+ cont &= wrap(self, visitor, Fields::declarations, m_declarations);
+ cont &= wrap(self, visitor, Fields::condition, m_condition);
+ cont &= wrap(self, visitor, Fields::expression, m_expression);
+ cont &= wrap(self, visitor, Fields::body, m_body);
+ return cont;
+}
+
+void ForStatement::updatePathFromOwner(const Path &p)
+{
+ BaseT::updatePathFromOwner(p);
+ if (auto ptr = m_initializer.base())
+ ptr->updatePathFromOwner(p.field(Fields::initializer));
+ if (auto ptr = m_declarations.base())
+ ptr->updatePathFromOwner(p.field(Fields::declarations));
+ if (auto ptr = m_condition.base())
+ ptr->updatePathFromOwner(p.field(Fields::condition));
+ if (auto ptr = m_expression.base())
+ ptr->updatePathFromOwner(p.field(Fields::expression));
+ if (auto ptr = m_body.base())
+ ptr->updatePathFromOwner(p.field(Fields::body));
+}
+
+void ForStatement::createFileLocations(const FileLocations::Tree &base)
+{
+ BaseT::createFileLocations(base);
+ if (auto ptr = m_initializer.base())
+ ptr->createFileLocations(base);
+ if (auto ptr = m_declarations.base())
+ ptr->createFileLocations(base);
+ if (auto ptr = m_condition.base())
+ ptr->createFileLocations(base);
+ if (auto ptr = m_expression.base())
+ ptr->createFileLocations(base);
+ if (auto ptr = m_body.base())
+ ptr->createFileLocations(base);
+}
+
+bool BinaryExpression::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
+{
+ bool cont = true;
+ cont &= wrap(self, visitor, Fields::left, m_left);
+ cont &= self.dvValueField(visitor, Fields::operation, m_operator);
+ cont &= wrap(self, visitor, Fields::right, m_right);
+ return cont;
+}
+
+void BinaryExpression::updatePathFromOwner(const Path &p)
+{
+ BaseT::updatePathFromOwner(p);
+ if (auto ptr = m_left.base())
+ ptr->updatePathFromOwner(p.field(Fields::left));
+ if (auto ptr = m_right.base())
+ ptr->updatePathFromOwner(p.field(Fields::right));
+}
+
+void BinaryExpression::createFileLocations(const FileLocations::Tree &base)
+{
+ BaseT::createFileLocations(base);
+ if (auto ptr = m_left.base())
+ ptr->createFileLocations(base);
+ if (auto ptr = m_right.base())
+ ptr->createFileLocations(base);
+}
+
+bool VariableDeclarationEntry::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
+{
+ bool cont = true;
+ cont &= self.dvValueField(visitor, Fields::scopeType, m_scopeType);
+ cont &= wrap(self, visitor, Fields::identifier, m_identifier);
+ cont &= wrap(self, visitor, Fields::initializer, m_initializer);
+ return cont;
+}
+
+void VariableDeclarationEntry::updatePathFromOwner(const Path &p)
+{
+ BaseT::updatePathFromOwner(p);
+ if (auto ptr = m_identifier.base())
+ ptr->updatePathFromOwner(p.field(Fields::identifier));
+ if (auto ptr = m_initializer.base())
+ ptr->updatePathFromOwner(p.field(Fields::initializer));
+}
+
+void VariableDeclarationEntry::createFileLocations(const FileLocations::Tree &base)
+{
+ BaseT::createFileLocations(base);
+ if (auto ptr = m_identifier.base())
+ ptr->createFileLocations(base);
+ if (auto ptr = m_initializer.base())
+ ptr->createFileLocations(base);
+}
+
+bool VariableDeclaration::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
+{
+ bool cont = true;
+ cont &= wrap(self, visitor, Fields::declarations, m_declarations);
+ return cont;
+}
+
+void VariableDeclaration::updatePathFromOwner(const Path &p)
+{
+ BaseT::updatePathFromOwner(p);
+ m_declarations.updatePathFromOwner(p.field(Fields::declarations));
+}
+
+void VariableDeclaration::createFileLocations(const FileLocations::Tree &base)
+{
+ BaseT::createFileLocations(base);
+ m_declarations.createFileLocations(base);
+}
+
+bool ReturnStatement::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
+{
+ bool cont = true;
+ cont &= wrap(self, visitor, Fields::expression, m_expression);
+ return cont;
+}
+
+void ReturnStatement::updatePathFromOwner(const Path &p)
+{
+ BaseT::updatePathFromOwner(p);
+ if (auto ptr = m_expression.base())
+ ptr->updatePathFromOwner(p.field(Fields::expression));
+}
+
+void ReturnStatement::createFileLocations(const FileLocations::Tree &base)
+{
+ BaseT::createFileLocations(base);
+ if (auto ptr = m_expression.base())
+ ptr->createFileLocations(base);
+}
+
+void ScriptList::replaceKindForGenericChildren(DomType oldType, DomType newType)
+{
+ for (auto &it : m_list) {
+ if (auto current = it.data()) {
+ if (auto genericElement =
+ std::get_if<std::shared_ptr<ScriptElements::GenericScriptElement>>(
+ &*current)) {
+ if ((*genericElement)->kind() == oldType)
+ (*genericElement)->setKind(newType);
+ }
+ }
+ }
+}