aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmldom
diff options
context:
space:
mode:
Diffstat (limited to 'src/qmldom')
-rw-r--r--src/qmldom/CMakeLists.txt4
-rw-r--r--src/qmldom/qqmldom_fwd_p.h20
-rw-r--r--src/qmldom/qqmldom_utils.cpp63
-rw-r--r--src/qmldom/qqmldom_utils_p.h53
-rw-r--r--src/qmldom/qqmldomastcreator.cpp3739
-rw-r--r--src/qmldom/qqmldomastcreator_p.h718
-rw-r--r--src/qmldom/qqmldomastdumper.cpp23
-rw-r--r--src/qmldom/qqmldomastdumper_p.h2
-rw-r--r--src/qmldom/qqmldomattachedinfo.cpp210
-rw-r--r--src/qmldom/qqmldomattachedinfo_p.h175
-rw-r--r--src/qmldom/qqmldomcodeformatter.cpp5
-rw-r--r--src/qmldom/qqmldomcomments.cpp585
-rw-r--r--src/qmldom/qqmldomcomments_p.h127
-rw-r--r--src/qmldom/qqmldomcompare.cpp19
-rw-r--r--src/qmldom/qqmldomcompare_p.h18
-rw-r--r--src/qmldom/qqmldomconstants_p.h195
-rw-r--r--src/qmldom/qqmldomelements.cpp756
-rw-r--r--src/qmldom/qqmldomelements_p.h474
-rw-r--r--src/qmldom/qqmldomerrormessage.cpp94
-rw-r--r--src/qmldom/qqmldomerrormessage_p.h62
-rw-r--r--src/qmldom/qqmldomexternalitems.cpp280
-rw-r--r--src/qmldom/qqmldomexternalitems_p.h339
-rw-r--r--src/qmldom/qqmldomfieldfilter.cpp13
-rw-r--r--src/qmldom/qqmldomfieldfilter_p.h15
-rw-r--r--src/qmldom/qqmldomfilewriter.cpp2
-rw-r--r--src/qmldom/qqmldomfilewriter_p.h7
-rw-r--r--src/qmldom/qqmldomfunctionref_p.h30
-rw-r--r--src/qmldom/qqmldomindentinglinewriter.cpp2
-rw-r--r--src/qmldom/qqmldomindentinglinewriter_p.h4
-rw-r--r--src/qmldom/qqmldomitem.cpp1905
-rw-r--r--src/qmldom/qqmldomitem_p.h1290
-rw-r--r--src/qmldom/qqmldomlinewriter.cpp9
-rw-r--r--src/qmldom/qqmldomlinewriter_p.h19
-rw-r--r--src/qmldom/qqmldommock.cpp14
-rw-r--r--src/qmldom/qqmldommock_p.h16
-rw-r--r--src/qmldom/qqmldommoduleindex.cpp80
-rw-r--r--src/qmldom/qqmldommoduleindex_p.h33
-rw-r--r--src/qmldom/qqmldomoutwriter.cpp366
-rw-r--r--src/qmldom/qqmldomoutwriter_p.h42
-rw-r--r--src/qmldom/qqmldompath.cpp85
-rw-r--r--src/qmldom/qqmldompath_p.h402
-rw-r--r--src/qmldom/qqmldomreformatter.cpp1991
-rw-r--r--src/qmldom/qqmldomreformatter_p.h190
-rw-r--r--src/qmldom/qqmldomscanner.cpp2
-rw-r--r--src/qmldom/qqmldomscanner_p.h4
-rw-r--r--src/qmldom/qqmldomscriptelements.cpp358
-rw-r--r--src/qmldom/qqmldomscriptelements_p.h423
-rw-r--r--src/qmldom/qqmldomstringdumper.cpp16
-rw-r--r--src/qmldom/qqmldomstringdumper_p.h28
-rw-r--r--src/qmldom/qqmldomtop.cpp1626
-rw-r--r--src/qmldom/qqmldomtop_p.h730
-rw-r--r--src/qmldom/qqmldomtypesreader.cpp53
-rw-r--r--src/qmldom/qqmldomtypesreader_p.h23
-rw-r--r--src/qmldom/standalone/CMakeLists.txt80
-rw-r--r--src/qmldom/standalone/private/qtqmlcompilerexports_p.h20
55 files changed, 11654 insertions, 6185 deletions
diff --git a/src/qmldom/CMakeLists.txt b/src/qmldom/CMakeLists.txt
index 3edb917836..f0fffea605 100644
--- a/src/qmldom/CMakeLists.txt
+++ b/src/qmldom/CMakeLists.txt
@@ -14,6 +14,7 @@ qt_internal_add_module(QmlDomPrivate
SOURCES
qqmldom_fwd_p.h
qqmldom_global.h
+ qqmldom_utils_p.h qqmldom_utils.cpp
qqmldomastcreator.cpp qqmldomastcreator_p.h
qqmldomastdumper.cpp qqmldomastdumper_p.h
qqmldomattachedinfo.cpp qqmldomattachedinfo_p.h
@@ -39,11 +40,14 @@ qt_internal_add_module(QmlDomPrivate
qqmldomscanner.cpp qqmldomscanner_p.h
qqmldomtop.cpp qqmldomtop_p.h
qqmldomtypesreader.cpp qqmldomtypesreader_p.h
+ qqmldomscriptelements_p.h qqmldomscriptelements.cpp
DEFINES
QMLDOM_LIBRARY
PUBLIC_LIBRARIES
Qt::QmlPrivate
Qt::QmlCompilerPrivate
+ NO_UNITY_BUILD
+ NO_GENERATE_CPP_EXPORTS
)
#### Keys ignored in scope 1:.:.:qmldom.pro:<TRUE>:
diff --git a/src/qmldom/qqmldom_fwd_p.h b/src/qmldom/qqmldom_fwd_p.h
index 25cba4f8dd..9b8603b33e 100644
--- a/src/qmldom/qqmldom_fwd_p.h
+++ b/src/qmldom/qqmldom_fwd_p.h
@@ -30,6 +30,7 @@ class Comment;
class CommentedElement;
class ConstantData;
class DomBase;
+enum DomCreationOption : char;
class DomEnvironment;
class DomItem;
class DomTop;
@@ -41,6 +42,7 @@ class ExternalItemInfoBase;
class ExternalItemPairBase;
class ExternalOwningItem;
class FileLocations;
+enum FileLocationRegion : int;
class FileWriter;
class GlobalComponent;
class GlobalScope;
@@ -65,7 +67,7 @@ class Path;
class Pragma;
class PropertyDefinition;
class PropertyInfo;
-class QmlDomAstCreator;
+class QQmlDomAstCreator;
class QmlComponent;
class QmlDirectory;
class QmldirFile;
@@ -80,6 +82,22 @@ class Source;
class TestDomItem;
class Version;
+namespace ScriptElements {
+class BlockStatement;
+class IdentifierExpression;
+class Literal;
+class ForStatement;
+class IfStatement;
+class BinaryExpression;
+class VariableDeclaration;
+class VariableDeclarationEntry;
+class GenericScriptElement;
+// TODO: add new script classes here, as qqmldomitem_p.h cannot include qqmldomscriptelements_p.h
+// without creating circular dependencies
+class ReturnStatement;
+
+} // end namespace ScriptElements
+
} // end namespace Dom
} // end namespace QQmlJS
QT_END_NAMESPACE
diff --git a/src/qmldom/qqmldom_utils.cpp b/src/qmldom/qqmldom_utils.cpp
new file mode 100644
index 0000000000..a7c985644a
--- /dev/null
+++ b/src/qmldom/qqmldom_utils.cpp
@@ -0,0 +1,63 @@
+// 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 <QtCore/qdir.h>
+#include <QtCore/qdiriterator.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qcbormap.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(QQmlJSDomImporting, "qt.qqmljsdom.importing")
+
+namespace QQmlJS {
+namespace Dom {
+
+using namespace Qt::StringLiterals;
+
+QStringList resourceFilesFromBuildFolders(const QStringList &buildFolders)
+{
+ QStringList result;
+ for (const QString &path : buildFolders) {
+ QDir dir(path);
+ if (!dir.cd(u".rcc"_s))
+ continue;
+
+ QDirIterator it(dir.canonicalPath(), QStringList{ u"*.qrc"_s }, QDir::Files,
+ QDirIterator::Subdirectories);
+ while (it.hasNext()) {
+ result.append(it.next());
+ }
+ }
+ return result;
+}
+
+static QMetaEnum regionEnum = QMetaEnum::fromType<FileLocationRegion>();
+
+QString fileLocationRegionName(FileLocationRegion region)
+{
+ return QString::fromLatin1(regionEnum.key(region));
+}
+
+FileLocationRegion fileLocationRegionValue(QStringView region)
+{
+ return static_cast<FileLocationRegion>(regionEnum.keyToValue(region.toLatin1()));
+}
+
+QCborValue sourceLocationToQCborValue(QQmlJS::SourceLocation loc)
+{
+ QCborMap res({
+ {QStringLiteral(u"offset"), loc.offset},
+ {QStringLiteral(u"length"), loc.length},
+ {QStringLiteral(u"startLine"), loc.startLine},
+ {QStringLiteral(u"startColumn"), loc.startColumn}
+ });
+ return res;
+}
+
+} // namespace Dom
+}; // namespace QQmlJS
+
+QT_END_NAMESPACE
diff --git a/src/qmldom/qqmldom_utils_p.h b/src/qmldom/qqmldom_utils_p.h
new file mode 100644
index 0000000000..6fcdb5fe10
--- /dev/null
+++ b/src/qmldom/qqmldom_utils_p.h
@@ -0,0 +1,53 @@
+// 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
+
+#ifndef QQMLDOM_UTILS_P_H
+#define QQMLDOM_UTILS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include "qqmldom_fwd_p.h"
+#include "qqmldomconstants_p.h"
+#include <QtQml/private/qqmljssourcelocation_p.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qcborvalue.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QQmlJSDomImporting);
+
+template<class... Ts>
+struct qOverloadedVisitor : Ts...
+{
+ using Ts::operator()...;
+};
+template<class... Ts>
+qOverloadedVisitor(Ts...) -> qOverloadedVisitor<Ts...>;
+
+namespace QQmlJS {
+namespace Dom {
+
+QStringList resourceFilesFromBuildFolders(const QStringList &buildFolders);
+
+QString fileLocationRegionName(FileLocationRegion region);
+FileLocationRegion fileLocationRegionValue(QStringView region);
+
+QCborValue sourceLocationToQCborValue(SourceLocation loc);
+
+} // namespace Dom
+}; // namespace QQmlJS
+
+QT_END_NAMESPACE
+
+#endif // QQMLDOM_UTILS_P_H
diff --git a/src/qmldom/qqmldomastcreator.cpp b/src/qmldom/qqmldomastcreator.cpp
index 40665845fc..b070b0ea6d 100644
--- a/src/qmldom/qqmldomastcreator.cpp
+++ b/src/qmldom/qqmldomastcreator.cpp
@@ -1,12 +1,21 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qqmldomastcreator_p.h"
+#include "qqmldomconstants_p.h"
#include "qqmldomelements_p.h"
+#include "qqmldomitem_p.h"
+#include "qqmldompath_p.h"
+#include "qqmldomscriptelements_p.h"
#include "qqmldomtop_p.h"
#include "qqmldomerrormessage_p.h"
#include "qqmldomastdumper_p.h"
#include "qqmldomattachedinfo_p.h"
+#include "qqmldomastcreator_p.h"
+#include "qqmldom_utils_p.h"
#include <QtQml/private/qqmljsast_p.h>
+#include <QtQmlCompiler/private/qqmljsutils_p.h>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
@@ -14,9 +23,31 @@
#include <QtCore/QLoggingCategory>
#include <memory>
+#include <optional>
+#include <type_traits>
#include <variant>
-
-static Q_LOGGING_CATEGORY(creatorLog, "qt.qmldom.astcreator", QtWarningMsg);
+#include <vector>
+
+Q_STATIC_LOGGING_CATEGORY(creatorLog, "qt.qmldom.astcreator", QtWarningMsg);
+
+/*
+ Avoid crashing on files with JS-elements that are not implemented yet.
+ Might be removed (definition + usages) once all script elements are implemented.
+*/
+#define Q_SCRIPTELEMENT_DISABLE() \
+ do { \
+ qDebug() << "Could not construct the JS DOM at" << __FILE__ << ":" << __LINE__ \
+ << ", skipping JS elements..."; \
+ disableScriptElements(); \
+ } while (false)
+
+#define Q_SCRIPTELEMENT_EXIT_IF(check) \
+ do { \
+ if (m_enableScriptExpressions && (check)) { \
+ Q_SCRIPTELEMENT_DISABLE(); \
+ return; \
+ } \
+ } while (false)
QT_BEGIN_NAMESPACE
namespace QQmlJS {
@@ -46,7 +77,7 @@ V *valueFromMultimap(QMultiMap<K, V> &mmap, const K &key, index_type idx)
return &(*it);
}
-static ErrorGroups myParseErrors()
+static ErrorGroups astParseErrors()
{
static ErrorGroups errs = { { NewErrorGroup("Dom"), NewErrorGroup("QmlFile"),
NewErrorGroup("Parsing") } };
@@ -88,879 +119,2981 @@ SourceLocation combineLocations(Node *n)
return combineLocations(n->firstSourceLocation(), n->lastSourceLocation());
}
-class DomValue
+static ScriptElementVariant wrapIntoFieldMemberExpression(const ScriptElementVariant &left,
+ const SourceLocation &dotToken,
+ const ScriptElementVariant &right)
{
-public:
- template<typename T>
- DomValue(const T &obj) : kind(T::kindValue), value(obj)
- {
- }
- DomType kind;
- std::variant<QmlObject, MethodInfo, QmlComponent, PropertyDefinition, Binding, EnumDecl,
- EnumItem, ConstantData, Id>
- value;
+ SourceLocation s1, s2;
+ left.visitConst([&s1](auto &&el) { s1 = el->mainRegionLocation(); });
+ right.visitConst([&s2](auto &&el) { s2 = el->mainRegionLocation(); });
+
+ auto result = std::make_shared<ScriptElements::BinaryExpression>(s1, s2);
+ result->addLocation(OperatorTokenRegion, dotToken);
+ result->setOp(ScriptElements::BinaryExpression::FieldMemberAccess);
+ result->setLeft(left);
+ result->setRight(right);
+ return ScriptElementVariant::fromElement(result);
};
-class StackEl
+/*!
+ \internal
+ Creates a FieldMemberExpression if the qualified id has dots.
+*/
+static ScriptElementVariant
+fieldMemberExpressionForQualifiedId(const AST::UiQualifiedId *qualifiedId)
{
-public:
- Path path;
- DomValue item;
- FileLocations::Tree fileLocations;
-};
+ ScriptElementVariant bindable;
+ bool first = true;
+ for (auto exp = qualifiedId; exp; exp = exp->next) {
+ const SourceLocation identifierLoc = exp->identifierToken;
+ auto id = std::make_shared<ScriptElements::IdentifierExpression>(identifierLoc);
+ id->setName(exp->name);
+ if (first) {
+ first = false;
+ bindable = ScriptElementVariant::fromElement(id);
+ continue;
+ }
+ bindable = wrapIntoFieldMemberExpression(bindable, exp->dotToken,
+ ScriptElementVariant::fromElement(id));
+ }
+
+ return bindable;
+}
-class QmlDomAstCreator final : public AST::Visitor
+QQmlDomAstCreator::QmlStackElement &QQmlDomAstCreator::currentQmlObjectOrComponentEl(int idx)
{
- Q_DECLARE_TR_FUNCTIONS(QmlDomAstCreator)
+ Q_ASSERT_X(idx < nodeStack.size() && idx >= 0, "currentQmlObjectOrComponentEl",
+ "Stack does not contain enough elements!");
+ int i = nodeStack.size() - idx;
+ while (i-- > 0) {
+ DomType k = nodeStack.at(i).item.kind;
+ if (k == DomType::QmlObject || k == DomType::QmlComponent)
+ return nodeStack[i];
+ }
+ Q_ASSERT_X(false, "currentQmlObjectEl", "No QmlObject or component in stack");
+ return nodeStack.last();
+}
- static constexpr const auto className = "QmlDomAstCreator";
+QQmlDomAstCreator::QmlStackElement &QQmlDomAstCreator::currentNodeEl(int i)
+{
+ Q_ASSERT_X(i < nodeStack.size() && i >= 0, "currentNode", "Stack does not contain element!");
+ return nodeStack[nodeStack.size() - i - 1];
+}
- MutableDomItem qmlFile;
- std::shared_ptr<QmlFile> qmlFilePtr;
- QVector<StackEl> nodeStack;
- QVector<int> arrayBindingLevels;
- FileLocations::Tree rootMap;
+QQmlDomAstCreator::ScriptStackElement &QQmlDomAstCreator::currentScriptNodeEl(int i)
+{
+ Q_ASSERT_X(i < scriptNodeStack.size() && i >= 0, "currentNode",
+ "Stack does not contain element!");
+ return scriptNodeStack[scriptNodeStack.size() - i - 1];
+}
- template<typename T>
- StackEl &currentEl(int idx = 0)
- {
- Q_ASSERT_X(idx < nodeStack.size() && idx >= 0, "currentQmlObjectOrComponentEl",
- "Stack does not contain enough elements!");
- int i = nodeStack.size() - idx;
- while (i-- > 0) {
- DomType k = nodeStack.at(i).item.kind;
- if (k == T::kindValue)
- return nodeStack[i];
+QQmlDomAstCreator::DomValue &QQmlDomAstCreator::currentNode(int i)
+{
+ Q_ASSERT_X(i < nodeStack.size() && i >= 0, "currentNode",
+ "Stack does not contain element!");
+ return nodeStack[nodeStack.size() - i - 1].item;
+}
+
+void QQmlDomAstCreator::removeCurrentNode(std::optional<DomType> expectedType)
+{
+ Q_ASSERT_X(!nodeStack.isEmpty(), className, "popCurrentNode() without any node");
+ if (expectedType)
+ Q_ASSERT(nodeStack.last().item.kind == *expectedType);
+ nodeStack.removeLast();
+}
+
+void QQmlDomAstCreator::removeCurrentScriptNode(std::optional<DomType> expectedType)
+{
+ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
+ Q_ASSERT_X(!scriptNodeStack.isEmpty(), className,
+ "popCurrentScriptNode() without any node");
+ if (expectedType)
+ Q_ASSERT(scriptNodeStack.last().kind == *expectedType);
+ scriptNodeStack.removeLast();
+}
+
+/*!
+ \internal
+ Prepares a script element DOM representation such that it can be used inside a QML DOM element.
+ This recursively sets the pathFromOwner and creates the FileLocations::Tree for all children of
+ element.
+
+ Beware that pathFromOwner is appended to ownerFileLocations when creating the FileLocations!
+
+ Make sure to add, for each of its use, a test in tst_qmldomitem:finalizeScriptExpressions, as
+ using a wrong pathFromOwner and/or a wrong base might lead to bugs hard to debug and spurious
+ crashes.
+ */
+const ScriptElementVariant &
+QQmlDomAstCreator::finalizeScriptExpression(const ScriptElementVariant &element, const Path &pathFromOwner,
+ const FileLocations::Tree &ownerFileLocations)
+{
+ auto e = element.base();
+ Q_ASSERT(e);
+
+ qCDebug(creatorLog) << "Finalizing script expression with path:"
+ << ownerFileLocations->canonicalPathForTesting().append(
+ pathFromOwner.toString());
+ e->updatePathFromOwner(pathFromOwner);
+ e->createFileLocations(ownerFileLocations);
+ return element;
+}
+
+FileLocations::Tree QQmlDomAstCreator::createMap(const FileLocations::Tree &base, const Path &p, AST::Node *n)
+{
+ FileLocations::Tree res = FileLocations::ensure(base, p, AttachedInfo::PathType::Relative);
+ if (n)
+ FileLocations::addRegion(res, MainRegion, combineLocations(n));
+ return res;
+}
+
+FileLocations::Tree QQmlDomAstCreator::createMap(DomType k, const Path &p, AST::Node *n)
+{
+ Path relative;
+ FileLocations::Tree base;
+ switch (k) {
+ case DomType::QmlObject:
+ switch (currentNode().kind) {
+ case DomType::QmlObject:
+ case DomType::QmlComponent:
+ case DomType::PropertyDefinition:
+ case DomType::Binding:
+ case DomType::Id:
+ case DomType::MethodInfo:
+ break;
+ default:
+ qCWarning(domLog) << "unexpected type" << domTypeToString(currentNode().kind);
+ Q_UNREACHABLE();
}
- Q_ASSERT_X(false, "currentEl", "Stack does not contan object of type ");
- return nodeStack.last();
- }
+ base = currentNodeEl().fileLocations;
+ if (p.length() > 2) {
+ Path p2 = p[p.length() - 2];
+ if (p2.headKind() == Path::Kind::Field
+ && (p2.checkHeadName(Fields::children) || p2.checkHeadName(Fields::objects)
+ || p2.checkHeadName(Fields::value) || p2.checkHeadName(Fields::annotations)
+ || p2.checkHeadName(Fields::children)))
+ relative = p.mid(p.length() - 2, 2);
+ else if (p.last().checkHeadName(Fields::value)
+ && p.last().headKind() == Path::Kind::Field)
+ relative = p.last();
+ else {
+ qCWarning(domLog) << "unexpected path to QmlObject in createMap" << p;
+ Q_UNREACHABLE();
+ }
+ } else {
+ qCWarning(domLog) << "unexpected path to QmlObject in createMap" << p;
+ Q_UNREACHABLE();
+ }
+ break;
+ case DomType::EnumItem:
+ relative = p;
+ base = currentNodeEl().fileLocations;
+ break;
+ case DomType::QmlComponent:
+ case DomType::Pragma:
+ case DomType::Import:
+ case DomType::Id:
+ case DomType::EnumDecl:
+ relative = p;
+ base = rootMap;
+ break;
+ case DomType::Binding:
+ case DomType::PropertyDefinition:
+ case DomType::MethodInfo:
+ base = currentEl<QmlObject>().fileLocations;
+ if (p.length() > 3)
+ relative = p.mid(p.length() - 3, 3);
+ else
+ relative = p;
+ break;
- template<typename T>
- T &current(int idx = 0)
- {
- return std::get<T>(currentEl<T>(idx).item.value);
+ default:
+ qCWarning(domLog) << "Unexpected type in createMap:" << domTypeToString(k);
+ Q_UNREACHABLE();
+ break;
}
+ return createMap(base, relative, n);
+}
- index_type currentIndex() { return currentNodeEl().path.last().headIndex(); }
+QQmlDomAstCreator::QQmlDomAstCreator(const MutableDomItem &qmlFile)
+ : qmlFile(qmlFile),
+ qmlFilePtr(qmlFile.ownerAs<QmlFile>()),
+ rootMap(qmlFilePtr->fileLocationsTree())
+{
+}
- StackEl &currentQmlObjectOrComponentEl(int idx = 0)
- {
- Q_ASSERT_X(idx < nodeStack.size() && idx >= 0, "currentQmlObjectOrComponentEl",
- "Stack does not contain enough elements!");
- int i = nodeStack.size() - idx;
- while (i-- > 0) {
- DomType k = nodeStack.at(i).item.kind;
- if (k == DomType::QmlObject || k == DomType::QmlComponent)
- return nodeStack[i];
+bool QQmlDomAstCreator::visit(UiProgram *program)
+{
+ QFileInfo fInfo(qmlFile.canonicalFilePath());
+ QString componentName = fInfo.baseName();
+ QmlComponent *cPtr;
+ Path p = qmlFilePtr->addComponent(QmlComponent(componentName), AddOption::KeepExisting,
+ &cPtr);
+ MutableDomItem newC(qmlFile.item(), p);
+ Q_ASSERT_X(newC.item(), className, "could not recover component added with addComponent");
+ // QmlFile region == Component region == program span
+ // we hide the component span because the component s written after the imports
+ FileLocations::addRegion(rootMap, MainRegion, combineLocations(program));
+ pushEl(p, *cPtr, program);
+
+ auto envPtr = qmlFile.environment().ownerAs<DomEnvironment>();
+ const bool loadDependencies =
+ !envPtr->options().testFlag(DomEnvironment::Option::NoDependencies);
+ // add implicit directory import and load them in the Dom
+ if (!fInfo.canonicalPath().isEmpty()) {
+ Import selfDirImport(QmlUri::fromDirectoryString(fInfo.canonicalPath()));
+ selfDirImport.implicit = true;
+ qmlFilePtr->addImport(selfDirImport);
+
+ if (loadDependencies) {
+ const QString currentFileDir =
+ QFileInfo(qmlFile.canonicalFilePath()).dir().canonicalPath();
+ envPtr->loadFile(FileToLoad::fromFileSystem(
+ envPtr, selfDirImport.uri.absoluteLocalPath(currentFileDir)),
+ DomItem::Callback(), DomType::QmlDirectory);
}
- Q_ASSERT_X(false, "currentQmlObjectEl", "No QmlObject or component in stack");
- return nodeStack.last();
}
+ // add implicit imports from the environment (QML, QtQml for example) and load them in the Dom
+ for (Import i : qmlFile.environment().ownerAs<DomEnvironment>()->implicitImports()) {
+ i.implicit = true;
+ qmlFilePtr->addImport(i);
- StackEl &currentNodeEl(int i = 0)
- {
- Q_ASSERT_X(i < nodeStack.size() && i >= 0, "currentNode",
- "Stack does not contain element!");
- return nodeStack[nodeStack.size() - i - 1];
+ if (loadDependencies)
+ envPtr->loadModuleDependency(i.uri.moduleUri(), i.version, DomItem::Callback());
}
-
- DomValue &currentNode(int i = 0)
- {
- Q_ASSERT_X(i < nodeStack.size() && i >= 0, "currentNode",
- "Stack does not contain element!");
- return nodeStack[nodeStack.size() - i - 1].item;
+ if (m_loadFileLazily && loadDependencies) {
+ envPtr->loadPendingDependencies();
+ envPtr->commitToBase(qmlFile.environment().item());
}
- void removeCurrentNode(std::optional<DomType> expectedType)
- {
- Q_ASSERT_X(!nodeStack.isEmpty(), className, "popCurrentNode() without any node");
- if (expectedType)
- Q_ASSERT(nodeStack.last().item.kind == *expectedType);
- nodeStack.removeLast();
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::UiProgram *)
+{
+ MutableDomItem newC = qmlFile.path(currentNodeEl().path);
+ QmlComponent &comp = current<QmlComponent>();
+ for (const Pragma &p : qmlFilePtr->pragmas()) {
+ if (p.name.compare(u"singleton", Qt::CaseInsensitive) == 0) {
+ comp.setIsSingleton(true);
+ comp.setIsCreatable(false); // correct?
+ }
}
+ *newC.mutableAs<QmlComponent>() = comp;
+ removeCurrentNode(DomType::QmlComponent);
+ Q_ASSERT_X(nodeStack.isEmpty(), className, "ui program did not finish node stack");
+}
- void pushEl(Path p, DomValue it, AST::Node *n)
- {
- nodeStack.append({ p, it, createMap(it.kind, p, n) });
+bool QQmlDomAstCreator::visit(UiPragma *el)
+{
+ QStringList valueList;
+ for (auto t = el->values; t; t = t->next)
+ valueList << t->value.toString();
+
+ auto fileLocation = createMap(
+ DomType::Pragma, qmlFilePtr->addPragma(Pragma(el->name.toString(), valueList)), el);
+ FileLocations::addRegion(fileLocation, PragmaKeywordRegion, el->pragmaToken);
+ FileLocations::addRegion(fileLocation, IdentifierRegion, el->pragmaIdToken);
+ if (el->colonToken.isValid()) {
+ FileLocations::addRegion(fileLocation, ColonTokenRegion, el->colonToken);
}
+ int i = 0;
+ for (auto t = el->values; t; t = t->next) {
+ auto subMap = createMap(fileLocation, Path().field(Fields::values).index(i), t);
+ FileLocations::addRegion(subMap, PragmaValuesRegion, t->location);
+ ++i;
+ }
+
+ return true;
+}
- FileLocations::Tree createMap(FileLocations::Tree base, Path p, AST::Node *n)
- {
- FileLocations::Tree res = FileLocations::ensure(base, p, AttachedInfo::PathType::Relative);
- if (n)
- FileLocations::addRegion(res, QString(), combineLocations(n));
- return res;
+bool QQmlDomAstCreator::visit(UiImport *el)
+{
+ Version v(Version::Latest, Version::Latest);
+ if (el->version && el->version->version.hasMajorVersion())
+ v.majorVersion = el->version->version.majorVersion();
+ if (el->version && el->version->version.hasMinorVersion())
+ v.minorVersion = el->version->version.minorVersion();
+
+ auto envPtr = qmlFile.environment().ownerAs<DomEnvironment>();
+ const bool loadDependencies =
+ !envPtr->options().testFlag(DomEnvironment::Option::NoDependencies);
+ FileLocations::Tree fileLocation;
+ if (el->importUri != nullptr) {
+ const Import import =
+ Import::fromUriString(toString(el->importUri), v, el->importId.toString());
+ fileLocation = createMap(DomType::Import, qmlFilePtr->addImport(import), el);
+
+ if (loadDependencies) {
+ envPtr->loadModuleDependency(import.uri.moduleUri(), import.version,
+ DomItem::Callback());
+ }
+ FileLocations::addRegion(fileLocation, ImportUriRegion, combineLocations(el->importUri));
+ } else {
+ const Import import =
+ Import::fromFileString(el->fileName.toString(), el->importId.toString());
+ fileLocation = createMap(DomType::Import, qmlFilePtr->addImport(import), el);
+
+ if (loadDependencies) {
+ const QString currentFileDir =
+ QFileInfo(qmlFile.canonicalFilePath()).dir().canonicalPath();
+ envPtr->loadFile(FileToLoad::fromFileSystem(
+ envPtr, import.uri.absoluteLocalPath(currentFileDir)),
+ DomItem::Callback(), DomType::QmlDirectory);
+ }
+ FileLocations::addRegion(fileLocation, ImportUriRegion, el->fileNameToken);
+ }
+ if (m_loadFileLazily && loadDependencies) {
+ envPtr->loadPendingDependencies();
+ envPtr->commitToBase(qmlFile.environment().item());
}
- FileLocations::Tree createMap(DomType k, Path p, AST::Node *n)
- {
- FileLocations::Tree base;
- switch (k) {
- case DomType::QmlObject:
- switch (currentNode().kind) {
- case DomType::QmlObject:
- case DomType::QmlComponent:
- case DomType::PropertyDefinition:
- case DomType::Binding:
- case DomType::Id:
- case DomType::MethodInfo:
- break;
- default:
- qCWarning(domLog) << "unexpected type" << domTypeToString(currentNode().kind);
- Q_UNREACHABLE();
- }
- base = currentNodeEl().fileLocations;
- if (p.length() > 2) {
- Path p2 = p[p.length() - 2];
- if (p2.headKind() == Path::Kind::Field
- && (p2.checkHeadName(Fields::children) || p2.checkHeadName(Fields::objects)
- || p2.checkHeadName(Fields::value) || p2.checkHeadName(Fields::annotations)
- || p2.checkHeadName(Fields::children)))
- p = p.mid(p.length() - 2, 2);
- else if (p.last().checkHeadName(Fields::value)
- && p.last().headKind() == Path::Kind::Field)
- p = p.last();
- else {
- qCWarning(domLog) << "unexpected path to QmlObject in createMap" << p;
- Q_UNREACHABLE();
- }
- } else {
- qCWarning(domLog) << "unexpected path to QmlObject in createMap" << p;
- Q_UNREACHABLE();
- }
- break;
- case DomType::EnumItem:
- base = currentNodeEl().fileLocations;
- break;
- case DomType::QmlComponent:
- case DomType::Pragma:
- case DomType::Import:
- case DomType::Id:
- case DomType::EnumDecl:
- base = rootMap;
- break;
- case DomType::Binding:
- case DomType::PropertyDefinition:
- case DomType::MethodInfo:
- base = currentEl<QmlObject>().fileLocations;
- if (p.length() > 3)
- p = p.mid(p.length() - 3, 3);
- break;
- default:
- qCWarning(domLog) << "Unexpected type in createMap:" << domTypeToString(k);
- Q_UNREACHABLE();
- break;
+ if (el->importToken.isValid())
+ FileLocations::addRegion(fileLocation, ImportTokenRegion, el->importToken);
+
+ if (el->asToken.isValid())
+ FileLocations::addRegion(fileLocation, AsTokenRegion, el->asToken);
+
+ if (el->importIdToken.isValid())
+ FileLocations::addRegion(fileLocation, IdNameRegion, el->importIdToken);
+
+ if (el->version)
+ FileLocations::addRegion(fileLocation, VersionRegion, combineLocations(el->version));
+
+
+ return true;
+}
+
+bool QQmlDomAstCreator::visit(AST::UiPublicMember *el)
+{
+ switch (el->type) {
+ case AST::UiPublicMember::Signal: {
+ MethodInfo m;
+ m.name = el->name.toString();
+ m.typeName = toString(el->memberType);
+ m.isReadonly = el->isReadonly();
+ m.access = MethodInfo::Public;
+ m.methodType = MethodInfo::Signal;
+ m.isList = el->typeModifier == QLatin1String("list");
+ MethodInfo *mPtr;
+ Path p = current<QmlObject>().addMethod(m, AddOption::KeepExisting, &mPtr);
+ pushEl(p, *mPtr, el);
+ FileLocations::addRegion(nodeStack.last().fileLocations, SignalKeywordRegion,
+ el->propertyToken());
+ FileLocations::addRegion(nodeStack.last().fileLocations, IdentifierRegion,
+ el->identifierToken);
+ MethodInfo &mInfo = std::get<MethodInfo>(currentNode().value);
+ AST::UiParameterList *args = el->parameters;
+ while (args) {
+ MethodParameter param;
+ param.name = args->name.toString();
+ param.typeName = args->type ? args->type->toString() : QString();
+ index_type idx = index_type(mInfo.parameters.size());
+ mInfo.parameters.append(param);
+ auto argLocs = FileLocations::ensure(nodeStack.last().fileLocations,
+ Path::Field(Fields::parameters).index(idx),
+ AttachedInfo::PathType::Relative);
+ FileLocations::addRegion(argLocs, MainRegion, combineLocations(args));
+ FileLocations::addRegion(argLocs, IdentifierRegion, args->identifierToken);
+ if (args->type)
+ FileLocations::addRegion(argLocs, TypeIdentifierRegion, args->propertyTypeToken);
+ args = args->next;
}
- return createMap(base, p, n);
- }
-
-public:
- QmlDomAstCreator(MutableDomItem qmlFile)
- : qmlFile(qmlFile),
- qmlFilePtr(qmlFile.ownerAs<QmlFile>()),
- rootMap(qmlFilePtr->fileLocationsTree())
- {
- }
-
- bool visit(UiProgram *program) override
- {
- QFileInfo fInfo(qmlFile.canonicalFilePath());
- QString componentName = fInfo.baseName();
- QmlComponent *cPtr;
- Path p = qmlFilePtr->addComponent(QmlComponent(componentName), AddOption::KeepExisting,
- &cPtr);
- MutableDomItem newC(qmlFile.item(), p);
- Q_ASSERT_X(newC.item(), className, "could not recover component added with addComponent");
- // QmlFile region == Component region == program span
- // we hide the component span because the component s written after the imports
- FileLocations::addRegion(rootMap, QString(), combineLocations(program));
- pushEl(p, *cPtr, program);
- // implicit imports
- // add implicit directory import
- if (!fInfo.canonicalPath().isEmpty()) {
- Import selfDirImport(QmlUri::fromDirectoryString(fInfo.canonicalPath()));
- selfDirImport.implicit = true;
- qmlFilePtr->addImport(selfDirImport);
- }
- for (Import i : qmlFile.environment().ownerAs<DomEnvironment>()->implicitImports()) {
- i.implicit = true;
- qmlFilePtr->addImport(i);
- }
- return true;
- }
-
- void endVisit(AST::UiProgram *) override
- {
- MutableDomItem newC = qmlFile.path(currentNodeEl().path);
- QmlComponent &comp = current<QmlComponent>();
- for (const Pragma &p : qmlFilePtr->pragmas()) {
- if (p.name.compare(u"singleton", Qt::CaseInsensitive) == 0) {
- comp.setIsSingleton(true);
- comp.setIsCreatable(false); // correct?
- }
+ break;
+ }
+ case AST::UiPublicMember::Property: {
+ PropertyDefinition p;
+ p.name = el->name.toString();
+ p.typeName = toString(el->memberType);
+ p.isReadonly = el->isReadonly();
+ p.isDefaultMember = el->isDefaultMember();
+ p.isRequired = el->isRequired();
+ p.isList = el->typeModifier == QLatin1String("list");
+ if (!el->typeModifier.isEmpty())
+ p.typeName = el->typeModifier.toString() + QChar(u'<') + p.typeName + QChar(u'>');
+ PropertyDefinition *pPtr;
+ Path pPathFromOwner =
+ current<QmlObject>().addPropertyDef(p, AddOption::KeepExisting, &pPtr);
+ if (m_enableScriptExpressions) {
+ auto qmlObjectType = makeGenericScriptElement(el->memberType, DomType::ScriptType);
+ qmlObjectType->insertChild(Fields::typeName,
+ fieldMemberExpressionForQualifiedId(el->memberType));
+ pPtr->setNameIdentifiers(finalizeScriptExpression(
+ ScriptElementVariant::fromElement(qmlObjectType),
+ pPathFromOwner.field(Fields::nameIdentifiers), rootMap));
+ // skip binding identifiers of the binding inside the property definition, if there is
+ // one
+ m_skipBindingIdentifiers = el->binding;
}
- *newC.mutableAs<QmlComponent>() = comp;
- removeCurrentNode(DomType::QmlComponent);
- Q_ASSERT_X(nodeStack.isEmpty(), className, "ui program did not finish node stack");
- }
-
- bool visit(UiPragma *el) override
- {
- createMap(DomType::Pragma, qmlFilePtr->addPragma(Pragma(el->name.toString())), el);
- return true;
- }
-
- bool visit(UiImport *el) override
- {
- Version v(Version::Latest, Version::Latest);
- if (el->version && el->version->version.hasMajorVersion())
- v.majorVersion = el->version->version.majorVersion();
- if (el->version && el->version->version.hasMinorVersion())
- v.minorVersion = el->version->version.minorVersion();
- if (el->importUri != nullptr)
- createMap(DomType::Import,
- qmlFilePtr->addImport(Import::fromUriString(toString(el->importUri), v,
- el->importId.toString())),
- el);
- else
- createMap(DomType::Import,
- qmlFilePtr->addImport(Import::fromFileString(
- el->fileName.toString(),
- el->importId.toString())),
- el);
- return true;
- }
-
- bool visit(AST::UiPublicMember *el) override
- {
- switch (el->type) {
- case AST::UiPublicMember::Signal: {
- MethodInfo m;
- m.name = el->name.toString();
- m.typeName = toString(el->memberType);
- m.isReadonly = el->isReadonly();
- m.access = MethodInfo::Public;
- m.methodType = MethodInfo::Signal;
- m.isList = el->typeModifier == QLatin1String("list");
- MethodInfo *mPtr;
- Path p = current<QmlObject>().addMethod(m, AddOption::KeepExisting, &mPtr);
- pushEl(p, *mPtr, el);
- FileLocations::addRegion(nodeStack.last().fileLocations, u"signal", el->propertyToken());
- MethodInfo &mInfo = std::get<MethodInfo>(currentNode().value);
- AST::UiParameterList *args = el->parameters;
- while (args) {
- MethodParameter param;
- param.name = args->name.toString();
- param.typeName = args->type ? args->type->toString() : QString();
- index_type idx = index_type(mInfo.parameters.size());
- mInfo.parameters.append(param);
- auto argLocs = FileLocations::ensure(nodeStack.last().fileLocations,
- Path::Field(Fields::parameters).index(idx),
- AttachedInfo::PathType::Relative);
- FileLocations::addRegion(argLocs, QString(), combineLocations(args));
- args = args->next;
- }
- break;
+ pushEl(pPathFromOwner, *pPtr, el);
+ FileLocations::addRegion(nodeStack.last().fileLocations, PropertyKeywordRegion,
+ el->propertyToken());
+ FileLocations::addRegion(nodeStack.last().fileLocations, IdentifierRegion,
+ el->identifierToken);
+ FileLocations::addRegion(nodeStack.last().fileLocations, TypeIdentifierRegion,
+ el->typeToken);
+ FileLocations::addRegion(nodeStack.last().fileLocations, ColonTokenRegion, el->colonToken);
+ if (p.name == u"id")
+ qmlFile.addError(std::move(astParseErrors()
+ .warning(tr("id is a special attribute, that should not be "
+ "used as property name"))
+ .withPath(currentNodeEl().path)));
+ if (p.isDefaultMember) {
+ FileLocations::addRegion(nodeStack.last().fileLocations, DefaultKeywordRegion,
+ el->defaultToken());
}
- case AST::UiPublicMember::Property: {
- PropertyDefinition p;
- p.name = el->name.toString();
- p.typeName = toString(el->memberType);
- p.isReadonly = el->isReadonly();
- p.isDefaultMember = el->isDefaultMember();
- p.isRequired = el->isRequired();
- p.isList = el->typeModifier == QLatin1String("list");
- if (!el->typeModifier.isEmpty())
- p.typeName = el->typeModifier.toString() + QChar(u'<') + p.typeName + QChar(u'>');
- PropertyDefinition *pPtr;
- Path pPathFromOwner =
- current<QmlObject>().addPropertyDef(p, AddOption::KeepExisting, &pPtr);
- pushEl(pPathFromOwner, *pPtr, el);
- FileLocations::addRegion(nodeStack.last().fileLocations, u"property",
- el->propertyToken());
- if (p.name == u"id")
- qmlFile.addError(
- myParseErrors()
- .warning(tr("id is a special attribute, that should not be "
- "used as property name"))
- .withPath(currentNodeEl().path));
- if (p.isDefaultMember)
- FileLocations::addRegion(nodeStack.last().fileLocations, u"default",
- el->defaultToken());
- if (p.isRequired)
- FileLocations::addRegion(nodeStack.last().fileLocations, u"required",
- el->requiredToken());
- if (el->statement) {
- BindingType bType = BindingType::Normal;
- SourceLocation loc = combineLocations(el->statement);
- QStringView code = qmlFilePtr->code();
-
- auto script = std::make_shared<ScriptExpression>(
- code.mid(loc.offset, loc.length), qmlFilePtr->engine(), el->statement,
- qmlFilePtr->astComments(),
- ScriptExpression::ExpressionType::BindingExpression, loc);
- Binding *bPtr;
- Path bPathFromOwner = current<QmlObject>().addBinding(
- Binding(p.name, script, bType), AddOption::KeepExisting, &bPtr);
- FileLocations::Tree bLoc = createMap(DomType::Binding, bPathFromOwner, el);
- FileLocations::addRegion(bLoc, u"colon", el->colonToken);
- FileLocations::Tree valueLoc = FileLocations::ensure(
- bLoc, Path::Field(Fields::value), AttachedInfo::PathType::Relative);
- FileLocations::addRegion(valueLoc, QString(), combineLocations(el->statement));
- }
- break;
+ if (p.isRequired) {
+ FileLocations::addRegion(nodeStack.last().fileLocations, RequiredKeywordRegion,
+ el->requiredToken());
}
+ if (p.isReadonly) {
+ FileLocations::addRegion(nodeStack.last().fileLocations, ReadonlyKeywordRegion,
+ el->readonlyToken());
}
- return true;
- }
-
- void endVisit(AST::UiPublicMember *el) override
- {
- Node::accept(el->parameters, this);
- loadAnnotations(el);
- if ((el->binding || el->statement)
- && nodeStack.last().item.kind == DomType::PropertyDefinition) {
- PropertyDefinition &pDef = std::get<PropertyDefinition>(nodeStack.last().item.value);
- if (!pDef.annotations.isEmpty()) {
- QmlObject duplicate;
- duplicate.setName(QLatin1String("duplicate"));
- QmlObject &obj = current<QmlObject>();
- auto it = obj.m_bindings.find(pDef.name);
- if (it != obj.m_bindings.end()) {
- for (QmlObject ann : pDef.annotations) {
- ann.addAnnotation(duplicate);
- it->addAnnotation(
- currentEl<QmlObject>()
- .path.field(Fields::bindings)
- .key(pDef.name)
- .index(obj.m_bindings.values(pDef.name).size() - 1),
- ann);
- }
- }
- }
+ if (el->statement) {
+ BindingType bType = BindingType::Normal;
+ SourceLocation loc = combineLocations(el->statement);
+ QStringView code = qmlFilePtr->code();
+
+ auto script = std::make_shared<ScriptExpression>(
+ code.mid(loc.offset, loc.length), qmlFilePtr->engine(), el->statement,
+ qmlFilePtr->astComments(), ScriptExpression::ExpressionType::BindingExpression,
+ loc);
+ Binding *bPtr;
+ Path bPathFromOwner = current<QmlObject>().addBinding(Binding(p.name, script, bType),
+ AddOption::KeepExisting, &bPtr);
+ FileLocations::Tree bLoc = createMap(DomType::Binding, bPathFromOwner, el);
+ FileLocations::addRegion(bLoc, ColonTokenRegion, el->colonToken);
+ FileLocations::Tree valueLoc = FileLocations::ensure(bLoc, Path::Field(Fields::value),
+ AttachedInfo::PathType::Relative);
+ FileLocations::addRegion(valueLoc, MainRegion, combineLocations(el->statement));
+ // push it also: its needed in endVisit to add the scriptNode to it
+ // do not use pushEl to avoid recreating the already created "bLoc" Map
+ nodeStack.append({ bPathFromOwner, *bPtr, bLoc });
}
- QmlObject &obj = current<QmlObject>();
- StackEl &sEl = nodeStack.last();
- switch (sEl.item.kind) {
- case DomType::PropertyDefinition: {
- PropertyDefinition pDef = std::get<PropertyDefinition>(sEl.item.value);
- PropertyDefinition *pDefPtr =
- valueFromMultimap(obj.m_propertyDefs, pDef.name, sEl.path.last().headIndex());
- Q_ASSERT(pDefPtr);
- *pDefPtr = pDef;
- } break;
- case DomType::MethodInfo: {
- MethodInfo m = std::get<MethodInfo>(sEl.item.value);
- MethodInfo *mPtr =
- valueFromMultimap(obj.m_methods, m.name, sEl.path.last().headIndex());
- Q_ASSERT(mPtr);
- *mPtr = m;
- } break;
- default:
- Q_UNREACHABLE();
+ break;
+ }
+ }
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::UiPublicMember *el)
+{
+ if (auto &lastEl = currentNode(); lastEl.kind == DomType::Binding) {
+ Binding &b = std::get<Binding>(lastEl.value);
+ if (m_enableScriptExpressions
+ && (scriptNodeStack.size() != 1 || scriptNodeStack.last().isList())) {
+ Q_SCRIPTELEMENT_DISABLE();
}
+ if (m_enableScriptExpressions) {
+ b.scriptExpressionValue()->setScriptElement(finalizeScriptExpression(
+ currentScriptNodeEl().takeVariant(), Path().field(Fields::scriptElement),
+ FileLocations::ensure(currentNodeEl().fileLocations,
+ Path().field(Fields::value))));
+ removeCurrentScriptNode({});
+ }
+
+ QmlObject &containingObject = current<QmlObject>();
+ Binding *bPtr =
+ valueFromMultimap(containingObject.m_bindings, b.name(), currentIndex());
+ Q_ASSERT(bPtr);
removeCurrentNode({});
}
-
- bool visit(AST::UiSourceElement *el) override
- {
- QStringView code(qmlFilePtr->code());
- if (FunctionDeclaration *fDef = cast<FunctionDeclaration *>(el->sourceElement)) {
- MethodInfo m;
- m.name = fDef->name.toString();
- if (AST::TypeAnnotation *tAnn = fDef->typeAnnotation) {
- if (AST::Type *t = tAnn->type)
- m.typeName = typeToString(t);
- }
- m.access = MethodInfo::Public;
- m.methodType = MethodInfo::Method;
- if (fDef->body) {
- SourceLocation bodyLoc = combineLocations(fDef->body);
- SourceLocation methodLoc = combineLocations(el);
- QStringView preCode =
- code.mid(methodLoc.begin(), bodyLoc.begin() - methodLoc.begin());
- QStringView postCode = code.mid(bodyLoc.end(), methodLoc.end() - bodyLoc.end());
- m.body = std::make_shared<ScriptExpression>(
- code.mid(bodyLoc.offset, bodyLoc.length), qmlFilePtr->engine(), fDef->body,
- qmlFilePtr->astComments(), ScriptExpression::ExpressionType::FunctionBody,
- bodyLoc, 0, preCode, postCode);
- }
- MethodInfo *mPtr;
- Path mPathFromOwner = current<QmlObject>().addMethod(m, AddOption::KeepExisting, &mPtr);
- pushEl(mPathFromOwner, *mPtr,
- fDef); // add at the start and use the normal recursive visit?
- FileLocations::Tree &fLoc = nodeStack.last().fileLocations;
- if (fDef->lparenToken.length != 0)
- FileLocations::addRegion(fLoc, u"leftParen", fDef->lparenToken);
- if (fDef->rparenToken.length != 0)
- FileLocations::addRegion(fLoc, u"rightParen", fDef->rparenToken);
- if (fDef->lbraceToken.length != 0)
- FileLocations::addRegion(fLoc, u"leftBrace", fDef->lbraceToken);
- if (fDef->rbraceToken.length != 0)
- FileLocations::addRegion(fLoc, u"rightBrace", fDef->rbraceToken);
- loadAnnotations(el);
- MethodInfo &mInfo = std::get<MethodInfo>(currentNode().value);
- AST::FormalParameterList *args = fDef->formals;
- while (args) {
- MethodParameter param;
- param.name = args->element->bindingIdentifier.toString();
- if (AST::TypeAnnotation *tAnn = args->element->typeAnnotation) {
- if (AST::Type *t = tAnn->type)
- param.typeName = typeToString(t);
+ Node::accept(el->parameters, this);
+ loadAnnotations(el);
+ if ((el->binding || el->statement)
+ && nodeStack.last().item.kind == DomType::PropertyDefinition) {
+ PropertyDefinition &pDef = std::get<PropertyDefinition>(nodeStack.last().item.value);
+ if (!pDef.annotations.isEmpty()) {
+ QmlObject duplicate;
+ duplicate.setName(QLatin1String("duplicate"));
+ QmlObject &obj = current<QmlObject>();
+ auto it = obj.m_bindings.find(pDef.name);
+ if (it != obj.m_bindings.end()) {
+ for (QmlObject ann : pDef.annotations) {
+ ann.addAnnotation(duplicate);
+ it->addAnnotation(currentEl<QmlObject>()
+ .path.field(Fields::bindings)
+ .key(pDef.name)
+ .index(obj.m_bindings.values(pDef.name).size() - 1),
+ ann);
}
- if (args->element->initializer) {
- SourceLocation loc = combineLocations(args->element->initializer);
- auto script = std::make_shared<ScriptExpression>(
- code.mid(loc.offset, loc.length), qmlFilePtr->engine(),
- args->element->initializer, qmlFilePtr->astComments(),
- ScriptExpression::ExpressionType::ArgInitializer, loc);
- param.defaultValue = script;
- }
- index_type idx = index_type(mInfo.parameters.size());
- mInfo.parameters.append(param);
- auto argLocs = FileLocations::ensure(nodeStack.last().fileLocations,
- Path::Field(Fields::parameters).index(idx),
- AttachedInfo::PathType::Relative);
- FileLocations::addRegion(argLocs, QString(), combineLocations(args));
- args = args->next;
}
- return false;
- } else {
- qCWarning(creatorLog) << "unhandled source el:" << static_cast<AST::Node *>(el);
- Q_UNREACHABLE();
}
- return true;
}
-
- void endVisit(AST::UiSourceElement *) override
- {
- MethodInfo &m = std::get<MethodInfo>(currentNode().value);
- QmlObject &obj = current<QmlObject>();
- MethodInfo *mPtr =
- valueFromMultimap(obj.m_methods, m.name, nodeStack.last().path.last().headIndex());
+ QmlObject &obj = current<QmlObject>();
+ QmlStackElement &sEl = nodeStack.last();
+ switch (sEl.item.kind) {
+ case DomType::PropertyDefinition: {
+ PropertyDefinition pDef = std::get<PropertyDefinition>(sEl.item.value);
+ PropertyDefinition *pDefPtr =
+ valueFromMultimap(obj.m_propertyDefs, pDef.name, sEl.path.last().headIndex());
+ Q_ASSERT(pDefPtr);
+ *pDefPtr = pDef;
+ } break;
+ case DomType::MethodInfo: {
+ MethodInfo m = std::get<MethodInfo>(sEl.item.value);
+ MethodInfo *mPtr = valueFromMultimap(obj.m_methods, m.name, sEl.path.last().headIndex());
Q_ASSERT(mPtr);
*mPtr = m;
- removeCurrentNode(DomType::MethodInfo);
- }
-
- void loadAnnotations(UiObjectMember *el) { Node::accept(el->annotations, this); }
-
- bool visit(AST::UiObjectDefinition *el) override
- {
- QmlObject scope;
- scope.setName(toString(el->qualifiedTypeNameId));
- scope.addPrototypePath(Paths::lookupTypePath(scope.name()));
- QmlObject *sPtr = nullptr;
- Path sPathFromOwner;
- if (!arrayBindingLevels.isEmpty() && nodeStack.size() == arrayBindingLevels.last()) {
- if (currentNode().kind == DomType::Binding) {
- QList<QmlObject> *vals = std::get<Binding>(currentNode().value).arrayValue();
- if (vals) {
- int idx = vals->size();
- vals->append(scope);
- sPathFromOwner = currentNodeEl().path.field(Fields::value).index(idx);
- sPtr = &((*vals)[idx]);
- sPtr->updatePathFromOwner(sPathFromOwner);
- } else {
- Q_ASSERT_X(false, className,
- "expected an array binding with a valid QList<QmlScope> as value");
- }
- } else {
- Q_ASSERT_X(false, className, "expected an array binding as last node on the stack");
- }
+ } break;
+ default:
+ Q_UNREACHABLE();
+ }
+ removeCurrentNode({});
+}
+
+void QQmlDomAstCreator::endVisit(AST::FormalParameterList *list)
+{
+ endVisitForLists(list);
+}
+
+bool QQmlDomAstCreator::visit(AST::FunctionExpression *)
+{
+ ++m_nestedFunctionDepth;
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
+
+ScriptElementVariant QQmlDomAstCreator::prepareBodyForFunction(AST::FunctionExpression *fExpression)
+{
+ Q_ASSERT(!scriptNodeStack.isEmpty() || !fExpression->body);
+
+ if (fExpression->body) {
+ if (currentScriptNodeEl().isList()) {
+ // It is more intuitive to have functions with a block as a body instead of a
+ // list.
+ auto body = std::make_shared<ScriptElements::BlockStatement>(
+ combineLocations(fExpression->lbraceToken, fExpression->rbraceToken));
+ body->setStatements(currentScriptNodeEl().takeList());
+ if (auto semanticScope = body->statements().semanticScope())
+ body->setSemanticScope(semanticScope);
+ auto result = ScriptElementVariant::fromElement(body);
+ removeCurrentScriptNode({});
+ return result;
} else {
- DomValue &containingObject = currentQmlObjectOrComponentEl().item;
- switch (containingObject.kind) {
- case DomType::QmlComponent:
- sPathFromOwner =
- std::get<QmlComponent>(containingObject.value).addObject(scope, &sPtr);
- break;
- case DomType::QmlObject:
- sPathFromOwner = std::get<QmlObject>(containingObject.value).addChild(scope, &sPtr);
- break;
- default:
- Q_UNREACHABLE();
- }
+ auto result = currentScriptNodeEl().takeVariant();
+ removeCurrentScriptNode({});
+ return result;
}
- Q_ASSERT_X(sPtr, className, "could not recover new scope");
- pushEl(sPathFromOwner, *sPtr, el);
- loadAnnotations(el);
- return true;
- }
-
- void endVisit(AST::UiObjectDefinition *) override
- {
- QmlObject &obj = current<QmlObject>();
- int idx = currentIndex();
- if (!arrayBindingLevels.isEmpty() && nodeStack.size() == arrayBindingLevels.last() + 1) {
- if (currentNode(1).kind == DomType::Binding) {
- Binding &b = std::get<Binding>(currentNode(1).value);
- QList<QmlObject> *vals = b.arrayValue();
- Q_ASSERT_X(vals, className,
- "expected an array binding with a valid QList<QmlScope> as value");
- (*vals)[idx] = obj;
+ Q_UNREACHABLE_RETURN({});
+ }
+
+ // for convenience purposes: insert an empty BlockStatement
+ auto body = std::make_shared<ScriptElements::BlockStatement>(
+ combineLocations(fExpression->lbraceToken, fExpression->rbraceToken));
+ return ScriptElementVariant::fromElement(body);
+}
+
+void QQmlDomAstCreator::endVisit(AST::FunctionExpression *fExpression)
+{
+ --m_nestedFunctionDepth;
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeGenericScriptElement(fExpression, DomType::ScriptFunctionExpression);
+ if (fExpression->identifierToken.isValid())
+ current->addLocation(IdentifierRegion, fExpression->identifierToken);
+ if (fExpression->functionToken.isValid())
+ current->addLocation(FunctionKeywordRegion, fExpression->functionToken);
+ if (fExpression->lparenToken.isValid())
+ current->addLocation(LeftParenthesisRegion, fExpression->lparenToken);
+ if (fExpression->rparenToken.isValid())
+ current->addLocation(RightParenthesisRegion, fExpression->rparenToken);
+ if (fExpression->lbraceToken.isValid())
+ current->addLocation(LeftBraceRegion, fExpression->lbraceToken);
+ if (fExpression->rbraceToken.isValid())
+ current->addLocation(RightBraceRegion, fExpression->rbraceToken);
+ if (fExpression->typeAnnotation) {
+ current->addLocation(TypeIdentifierRegion,
+ combineLocations(fExpression->typeAnnotation->type));
+ }
+
+ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() && fExpression->body);
+ current->insertChild(Fields::body, prepareBodyForFunction(fExpression));
+
+ if (fExpression->typeAnnotation) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::returnType, currentScriptNodeEl().takeVariant());
+ scriptNodeStack.removeLast();
+ }
+ if (fExpression->formals) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
+ current->insertChild(Fields::parameters, currentScriptNodeEl().takeList());
+ scriptNodeStack.removeLast();
+ }
+
+ if (!fExpression->name.isEmpty())
+ current->insertValue(Fields::name, fExpression->name);
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::FunctionDeclaration *fDef)
+{
+ // Treat nested functions as (named) lambdas instead of Qml Object methods.
+ if (m_nestedFunctionDepth > 0) {
+ return visit(static_cast<FunctionExpression *>(fDef));
+ }
+ ++m_nestedFunctionDepth;
+ const QStringView code(qmlFilePtr->code());
+ MethodInfo m;
+ m.name = fDef->name.toString();
+ if (AST::TypeAnnotation *tAnn = fDef->typeAnnotation) {
+ if (AST::Type *t = tAnn->type)
+ m.typeName = typeToString(t);
+ }
+ m.access = MethodInfo::Public;
+ m.methodType = MethodInfo::Method;
+
+ SourceLocation bodyLoc = fDef->body ? combineLocations(fDef->body)
+ : combineLocations(fDef->lbraceToken, fDef->rbraceToken);
+ SourceLocation methodLoc = combineLocations(fDef);
+ QStringView preCode = code.mid(methodLoc.begin(), bodyLoc.begin() - methodLoc.begin());
+ QStringView postCode = code.mid(bodyLoc.end(), methodLoc.end() - bodyLoc.end());
+ m.body = std::make_shared<ScriptExpression>(
+ code.mid(bodyLoc.offset, bodyLoc.length), qmlFilePtr->engine(), fDef->body,
+ qmlFilePtr->astComments(), ScriptExpression::ExpressionType::FunctionBody, bodyLoc, 0,
+ preCode, postCode);
+
+ if (fDef->typeAnnotation) {
+ SourceLocation typeLoc = combineLocations(fDef->typeAnnotation);
+ m.returnType = std::make_shared<ScriptExpression>(
+ code.mid(typeLoc.offset, typeLoc.length), qmlFilePtr->engine(),
+ fDef->typeAnnotation, qmlFilePtr->astComments(),
+ ScriptExpression::ExpressionType::ReturnType, typeLoc, 0, u"", u"");
+ }
+
+ MethodInfo *mPtr;
+ Path mPathFromOwner = current<QmlObject>().addMethod(m, AddOption::KeepExisting, &mPtr);
+ pushEl(mPathFromOwner, *mPtr,
+ fDef); // add at the start and use the normal recursive visit?
+ FileLocations::Tree &fLoc = nodeStack.last().fileLocations;
+ if (fDef->identifierToken.isValid())
+ FileLocations::addRegion(fLoc, IdentifierRegion, fDef->identifierToken);
+ auto bodyTree = FileLocations::ensure(fLoc, Path::Field(Fields::body),
+ AttachedInfo::PathType::Relative);
+ FileLocations::addRegion(bodyTree, MainRegion, bodyLoc);
+ if (fDef->functionToken.isValid())
+ FileLocations::addRegion(fLoc, FunctionKeywordRegion, fDef->functionToken);
+ if (fDef->lparenToken.length != 0)
+ FileLocations::addRegion(fLoc, LeftParenthesisRegion, fDef->lparenToken);
+ if (fDef->rparenToken.length != 0)
+ FileLocations::addRegion(fLoc, RightParenthesisRegion, fDef->rparenToken);
+ if (fDef->lbraceToken.length != 0)
+ FileLocations::addRegion(fLoc, LeftBraceRegion, fDef->lbraceToken);
+ if (fDef->rbraceToken.length != 0)
+ FileLocations::addRegion(fLoc, RightBraceRegion, fDef->rbraceToken);
+ if (fDef->typeAnnotation)
+ FileLocations::addRegion(fLoc, TypeIdentifierRegion, combineLocations(fDef->typeAnnotation->type));
+ MethodInfo &mInfo = std::get<MethodInfo>(currentNode().value);
+ AST::FormalParameterList *args = fDef->formals;
+ while (args) {
+ MethodParameter param;
+ param.name = args->element->bindingIdentifier.toString();
+ if (AST::TypeAnnotation *tAnn = args->element->typeAnnotation) {
+ if (AST::Type *t = tAnn->type)
+ param.typeName = typeToString(t);
+ }
+ if (args->element->initializer) {
+ SourceLocation loc = combineLocations(args->element->initializer);
+ auto script = std::make_shared<ScriptExpression>(
+ code.mid(loc.offset, loc.length), qmlFilePtr->engine(),
+ args->element->initializer, qmlFilePtr->astComments(),
+ ScriptExpression::ExpressionType::ArgInitializer, loc);
+ param.defaultValue = script;
+ }
+ if (args->element->type == AST::PatternElement::SpreadElement)
+ param.isRestElement = true;
+ SourceLocation parameterLoc = combineLocations(args->element);
+ param.value = std::make_shared<ScriptExpression>(
+ code.mid(parameterLoc.offset, parameterLoc.length), qmlFilePtr->engine(),
+ args->element, qmlFilePtr->astComments(),
+ ScriptExpression::ExpressionType::ArgumentStructure, parameterLoc);
+
+ index_type idx = index_type(mInfo.parameters.size());
+ mInfo.parameters.append(param);
+ auto argLocs = FileLocations::ensure(nodeStack.last().fileLocations,
+ Path::Field(Fields::parameters).index(idx),
+ AttachedInfo::PathType::Relative);
+ FileLocations::addRegion(argLocs, MainRegion, combineLocations(args));
+ if (args->element->identifierToken.isValid())
+ FileLocations::addRegion(argLocs, IdentifierRegion, args->element->identifierToken);
+ if (args->element->typeAnnotation)
+ FileLocations::addRegion(argLocs, TypeIdentifierRegion, combineLocations(args->element->typeAnnotation->type));
+ args = args->next;
+ }
+ return true;
+}
+
+bool QQmlDomAstCreator::visit(AST::UiSourceElement *el)
+{
+ if (!cast<FunctionDeclaration *>(el->sourceElement)) {
+ qCWarning(creatorLog) << "unhandled source el:" << static_cast<AST::Node *>(el);
+ Q_UNREACHABLE();
+ }
+ return true;
+}
+
+static void setFormalParameterKind(ScriptElementVariant &variant)
+{
+ if (auto data = variant.data()) {
+ if (auto genericElement =
+ std::get_if<std::shared_ptr<ScriptElements::GenericScriptElement>>(&*data)) {
+ (*genericElement)->setKind(DomType::ScriptFormalParameter);
+ }
+ }
+}
+
+void QQmlDomAstCreator::endVisit(AST::FunctionDeclaration *fDef)
+{
+ // Treat nested functions as (named) lambdas instead of Qml Object methods.
+ if (m_nestedFunctionDepth > 1) {
+ endVisit(static_cast<FunctionExpression *>(fDef));
+ return;
+ }
+ --m_nestedFunctionDepth;
+ MethodInfo &m = std::get<MethodInfo>(currentNode().value);
+ const FileLocations::Tree bodyTree =
+ FileLocations::ensure(currentNodeEl().fileLocations, Path().field(Fields::body));
+ const Path bodyPath = Path().field(Fields::scriptElement);
+
+ if (!m_enableScriptExpressions)
+ return;
+
+ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() && fDef->body);
+ m.body->setScriptElement(
+ finalizeScriptExpression(prepareBodyForFunction(fDef), bodyPath, bodyTree));
+
+ if (fDef->typeAnnotation) {
+ auto argLoc = FileLocations::ensure(nodeStack.last().fileLocations,
+ Path().field(Fields::returnType),
+ AttachedInfo::PathType::Relative);
+ const Path pathToReturnType = Path().field(Fields::scriptElement);
+
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ ScriptElementVariant variant = currentScriptNodeEl().takeVariant();
+ finalizeScriptExpression(variant, pathToReturnType, argLoc);
+ m.returnType->setScriptElement(variant);
+ removeCurrentScriptNode({});
+ }
+ if (fDef->formals) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
+ auto parameterList = scriptNodeStack.takeLast().takeList();
+ const auto parameterQList = parameterList.qList();
+ size_t size = (size_t)parameterQList.size();
+ for (size_t idx = size - 1; idx < size; --idx) {
+ auto argLoc = FileLocations::ensure(
+ nodeStack.last().fileLocations,
+ Path().field(Fields::parameters).index(idx).field(Fields::value),
+ AttachedInfo::PathType::Relative);
+ const Path pathToArgument = Path().field(Fields::scriptElement);
+
+ ScriptElementVariant variant = parameterQList[idx];
+ setFormalParameterKind(variant);
+ finalizeScriptExpression(variant, pathToArgument, argLoc);
+ m.parameters[idx].value->setScriptElement(variant);
+ }
+ }
+
+ // there should be no more uncollected script elements
+ if (m_enableScriptExpressions && !scriptNodeStack.empty()) {
+ Q_SCRIPTELEMENT_DISABLE();
+ }
+}
+
+void QQmlDomAstCreator::endVisit(AST::UiSourceElement *el)
+{
+ MethodInfo &m = std::get<MethodInfo>(currentNode().value);
+ loadAnnotations(el);
+ QmlObject &obj = current<QmlObject>();
+ MethodInfo *mPtr =
+ valueFromMultimap(obj.m_methods, m.name, nodeStack.last().path.last().headIndex());
+ Q_ASSERT(mPtr);
+ *mPtr = m;
+ removeCurrentNode(DomType::MethodInfo);
+}
+
+bool QQmlDomAstCreator::visit(AST::UiObjectDefinition *el)
+{
+ QmlObject scope;
+ scope.setName(toString(el->qualifiedTypeNameId));
+ scope.addPrototypePath(Paths::lookupTypePath(scope.name()));
+ QmlObject *sPtr = nullptr;
+ Path sPathFromOwner;
+ if (!arrayBindingLevels.isEmpty() && nodeStack.size() == arrayBindingLevels.last()) {
+ if (currentNode().kind == DomType::Binding) {
+ QList<QmlObject> *vals = std::get<Binding>(currentNode().value).arrayValue();
+ if (vals) {
+ int idx = vals->size();
+ vals->append(scope);
+ sPathFromOwner = currentNodeEl().path.field(Fields::value).index(idx);
+ sPtr = &((*vals)[idx]);
+ sPtr->updatePathFromOwner(sPathFromOwner);
} else {
- Q_ASSERT_X(false, className, "expected an array binding as last node on the stack");
+ Q_ASSERT_X(false, className,
+ "expected an array binding with a valid QList<QmlScope> as value");
}
} else {
- DomValue &containingObject = currentNodeEl(1).item;
- Path p = currentNodeEl().path;
- switch (containingObject.kind) {
- case DomType::QmlComponent:
- if (p[p.length() - 2] == Path::Field(Fields::objects))
- std::get<QmlComponent>(containingObject.value).m_objects[idx] = obj;
- else
- Q_UNREACHABLE();
- break;
- case DomType::QmlObject:
- if (p[p.length() - 2] == Path::Field(Fields::children))
- std::get<QmlObject>(containingObject.value).m_children[idx] = obj;
- else
- Q_UNREACHABLE();
- break;
- default:
+ Q_ASSERT_X(false, className, "expected an array binding as last node on the stack");
+ }
+ } else {
+ DomValue &containingObject = currentQmlObjectOrComponentEl().item;
+ switch (containingObject.kind) {
+ case DomType::QmlComponent:
+ sPathFromOwner = std::get<QmlComponent>(containingObject.value).addObject(scope, &sPtr);
+ break;
+ case DomType::QmlObject:
+ sPathFromOwner = std::get<QmlObject>(containingObject.value).addChild(scope, &sPtr);
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+ Path pathFromContainingObject = sPathFromOwner.mid(currentNodeEl().path.length());
+ FileLocations::Tree fLoc =
+ FileLocations::ensure(currentNodeEl().fileLocations, pathFromContainingObject,
+ AttachedInfo::PathType::Relative);
+ FileLocations::addRegion(fLoc, IdentifierRegion,
+ el->qualifiedTypeNameId->identifierToken);
+ }
+ Q_ASSERT_X(sPtr, className, "could not recover new scope");
+
+ if (m_enableScriptExpressions) {
+ auto qmlObjectType = makeGenericScriptElement(el->qualifiedTypeNameId, DomType::ScriptType);
+ qmlObjectType->insertChild(Fields::typeName,
+ fieldMemberExpressionForQualifiedId(el->qualifiedTypeNameId));
+ sPtr->setNameIdentifiers(
+ finalizeScriptExpression(ScriptElementVariant::fromElement(qmlObjectType),
+ sPathFromOwner.field(Fields::nameIdentifiers), rootMap));
+ }
+ pushEl(sPathFromOwner, *sPtr, el);
+
+ if (m_enableScriptExpressions && el->initializer) {
+ FileLocations::addRegion(nodeStack.last().fileLocations, LeftBraceRegion,
+ el->initializer->lbraceToken);
+ FileLocations::addRegion(nodeStack.last().fileLocations, RightBraceRegion,
+ el->initializer->rbraceToken);
+ }
+ loadAnnotations(el);
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::UiObjectDefinition *)
+{
+ QmlObject &obj = current<QmlObject>();
+ int idx = currentIndex();
+ if (!arrayBindingLevels.isEmpty() && nodeStack.size() == arrayBindingLevels.last() + 1) {
+ if (currentNode(1).kind == DomType::Binding) {
+ Binding &b = std::get<Binding>(currentNode(1).value);
+ QList<QmlObject> *vals = b.arrayValue();
+ Q_ASSERT_X(vals, className,
+ "expected an array binding with a valid QList<QmlScope> as value");
+ (*vals)[idx] = obj;
+ } else {
+ Q_ASSERT_X(false, className, "expected an array binding as last node on the stack");
+ }
+ } else {
+ DomValue &containingObject = currentNodeEl(1).item;
+ Path p = currentNodeEl().path;
+ switch (containingObject.kind) {
+ case DomType::QmlComponent:
+ if (p[p.length() - 2] == Path::Field(Fields::objects))
+ std::get<QmlComponent>(containingObject.value).m_objects[idx] = obj;
+ else
Q_UNREACHABLE();
- }
+ break;
+ case DomType::QmlObject:
+ if (p[p.length() - 2] == Path::Field(Fields::children))
+ std::get<QmlObject>(containingObject.value).m_children[idx] = obj;
+ else
+ Q_UNREACHABLE();
+ break;
+ default:
+ Q_UNREACHABLE();
}
- removeCurrentNode(DomType::QmlObject);
- }
-
- bool visit(AST::UiObjectBinding *el) override
- {
- BindingType bType = (el->hasOnToken ? BindingType::OnBinding : BindingType::Normal);
- QmlObject value;
- value.setName(toString(el->qualifiedTypeNameId));
- Binding *bPtr;
- Path bPathFromOwner = current<QmlObject>().addBinding(
- Binding(toString(el->qualifiedId), value, bType), AddOption::KeepExisting, &bPtr);
- if (bPtr->name() == u"id")
- qmlFile.addError(myParseErrors()
- .warning(tr("id attributes should only be a lower case letter "
- "followed by letters, numbers or underscore, "
- "assuming they refer to an id property"))
- .withPath(bPathFromOwner));
- pushEl(bPathFromOwner, *bPtr, el);
- FileLocations::addRegion(nodeStack.last().fileLocations, u"colon", el->colonToken);
- loadAnnotations(el);
- QmlObject *objValue = bPtr->objectValue();
- Q_ASSERT_X(objValue, className, "could not recover objectValue");
- pushEl(bPathFromOwner.field(Fields::value), *objValue, el->initializer);
- return true;
- }
-
- void endVisit(AST::UiObjectBinding *) override
- {
- QmlObject &objValue = current<QmlObject>();
- QmlObject &containingObj = current<QmlObject>(1);
- Binding &b = std::get<Binding>(currentNode(1).value);
- QmlObject *objPtr = b.objectValue();
- Q_ASSERT(objPtr);
- *objPtr = objValue;
- index_type idx = currentNodeEl(1).path.last().headIndex();
- Binding *bPtr = valueFromMultimap(containingObj.m_bindings, b.name(), idx);
- Q_ASSERT(bPtr);
- *bPtr = b;
- removeCurrentNode(DomType::QmlObject);
- removeCurrentNode(DomType::Binding);
- }
-
- bool visit(AST::UiScriptBinding *el) override
- {
- QStringView code = qmlFilePtr->code();
- SourceLocation loc = combineLocations(el->statement);
- auto script = std::make_shared<ScriptExpression>(
- code.mid(loc.offset, loc.length), qmlFilePtr->engine(),
- el->statement, qmlFilePtr->astComments(),
- ScriptExpression::ExpressionType::BindingExpression, loc);
- Binding bindingV(toString(el->qualifiedId), script, BindingType::Normal);
- Binding *bindingPtr = nullptr;
- Id *idPtr = nullptr;
- Path pathFromOwner;
- if (bindingV.name() == u"id") {
- Node *exp = script->ast();
- if (ExpressionStatement *eStat = cast<ExpressionStatement *>(script->ast()))
- exp = eStat->expression;
- if (IdentifierExpression *iExp = cast<IdentifierExpression *>(exp)) {
- StackEl &containingObjectEl = currentEl<QmlObject>();
- QmlObject &containingObject = std::get<QmlObject>(containingObjectEl.item.value);
- QString idName = iExp->name.toString();
- Id idVal(idName, qmlFile.canonicalPath().path(containingObject.pathFromOwner()));
- containingObject.setIdStr(idName);
- FileLocations::addRegion(containingObjectEl.fileLocations, u"idToken",
- combineLocations(el->qualifiedId));
- FileLocations::addRegion(containingObjectEl.fileLocations, u"idColon",
- el->colonToken);
- FileLocations::addRegion(containingObjectEl.fileLocations, u"id",
- combineLocations(el->statement));
- QmlComponent &comp = current<QmlComponent>();
- pathFromOwner = comp.addId(idVal, AddOption::KeepExisting, &idPtr);
- QRegularExpression idRe(QRegularExpression::anchoredPattern(
- QStringLiteral(uR"([[:lower:]][[:lower:][:upper:]0-9_]*)")));
- auto m = idRe.matchView(iExp->name);
- if (!m.hasMatch()) {
- qmlFile.addError(
- myParseErrors()
- .warning(
- tr("id attributes should only be a lower case letter "
- "followed by letters, numbers or underscore, not %1")
- .arg(iExp->name))
- .withPath(pathFromOwner));
- }
- } else {
- pathFromOwner = current<QmlObject>().addBinding(bindingV, AddOption::KeepExisting,
- &bindingPtr);
- Q_ASSERT_X(bindingPtr, className, "binding could not be retrieved");
- qmlFile.addError(
- myParseErrors()
+ }
+ removeCurrentNode(DomType::QmlObject);
+}
+
+void QQmlDomAstCreator::setBindingIdentifiers(const Path &pathFromOwner,
+ const UiQualifiedId *identifiers, Binding *bindingPtr)
+{
+ const bool skipBindingIdentifiers = std::exchange(m_skipBindingIdentifiers, false);
+ if (!m_enableScriptExpressions || skipBindingIdentifiers)
+ return;
+
+ ScriptElementVariant bindable = fieldMemberExpressionForQualifiedId(identifiers);
+ bindingPtr->setBindingIdentifiers(finalizeScriptExpression(
+ bindable, pathFromOwner.field(Fields::bindingIdentifiers), rootMap));
+}
+
+bool QQmlDomAstCreator::visit(AST::UiObjectBinding *el)
+{
+ BindingType bType = (el->hasOnToken ? BindingType::OnBinding : BindingType::Normal);
+ QmlObject value;
+ value.setName(toString(el->qualifiedTypeNameId));
+ Binding *bPtr;
+ Path bPathFromOwner = current<QmlObject>().addBinding(
+ Binding(toString(el->qualifiedId), value, bType), AddOption::KeepExisting, &bPtr);
+ if (bPtr->name() == u"id")
+ qmlFile.addError(std::move(astParseErrors()
+ .warning(tr("id attributes should only be a lower case letter "
+ "followed by letters, numbers or underscore, "
+ "assuming they refer to an id property"))
+ .withPath(bPathFromOwner)));
+ setBindingIdentifiers(bPathFromOwner, el->qualifiedId, bPtr);
+
+ pushEl(bPathFromOwner, *bPtr, el);
+ if (el->hasOnToken)
+ FileLocations::addRegion(nodeStack.last().fileLocations, OnTokenRegion, el->colonToken);
+ else
+ FileLocations::addRegion(nodeStack.last().fileLocations, ColonTokenRegion, el->colonToken);
+ FileLocations::addRegion(nodeStack.last().fileLocations, IdentifierRegion, combineLocations(el->qualifiedId));
+ loadAnnotations(el);
+ QmlObject *objValue = bPtr->objectValue();
+ Q_ASSERT_X(objValue, className, "could not recover objectValue");
+ objValue->setName(toString(el->qualifiedTypeNameId));
+
+ if (m_enableScriptExpressions) {
+ auto qmlObjectType = makeGenericScriptElement(el->qualifiedTypeNameId, DomType::ScriptType);
+ qmlObjectType->insertChild(Fields::typeName,
+ fieldMemberExpressionForQualifiedId(el->qualifiedTypeNameId));
+ objValue->setNameIdentifiers(finalizeScriptExpression(
+ ScriptElementVariant::fromElement(qmlObjectType),
+ bPathFromOwner.field(Fields::value).field(Fields::nameIdentifiers), rootMap));
+ }
+
+ objValue->addPrototypePath(Paths::lookupTypePath(objValue->name()));
+ pushEl(bPathFromOwner.field(Fields::value), *objValue, el->initializer);
+ if (m_enableScriptExpressions && el->initializer) {
+ FileLocations::addRegion(nodeStack.last().fileLocations, LeftBraceRegion,
+ el->initializer->lbraceToken);
+ FileLocations::addRegion(nodeStack.last().fileLocations, RightBraceRegion,
+ el->initializer->rbraceToken);
+ }
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::UiObjectBinding *)
+{
+ QmlObject &objValue = current<QmlObject>();
+ QmlObject &containingObj = current<QmlObject>(1);
+ Binding &b = std::get<Binding>(currentNode(1).value);
+ QmlObject *objPtr = b.objectValue();
+ Q_ASSERT(objPtr);
+ *objPtr = objValue;
+ index_type idx = currentNodeEl(1).path.last().headIndex();
+ Binding *bPtr = valueFromMultimap(containingObj.m_bindings, b.name(), idx);
+ Q_ASSERT(bPtr);
+ *bPtr = b;
+ removeCurrentNode(DomType::QmlObject);
+ removeCurrentNode(DomType::Binding);
+}
+
+bool QQmlDomAstCreator::visit(AST::UiScriptBinding *el)
+{
+ QStringView code = qmlFilePtr->code();
+ SourceLocation loc = combineLocations(el->statement);
+ auto script = std::make_shared<ScriptExpression>(
+ code.mid(loc.offset, loc.length), qmlFilePtr->engine(), el->statement,
+ qmlFilePtr->astComments(), ScriptExpression::ExpressionType::BindingExpression, loc);
+ Binding bindingV(toString(el->qualifiedId), script, BindingType::Normal);
+ Binding *bindingPtr = nullptr;
+ Id *idPtr = nullptr;
+ Path pathFromOwner;
+ if (bindingV.name() == u"id") {
+ Node *exp = script->ast();
+ if (ExpressionStatement *eStat = cast<ExpressionStatement *>(script->ast()))
+ exp = eStat->expression;
+ if (IdentifierExpression *iExp = cast<IdentifierExpression *>(exp)) {
+ QmlStackElement &containingObjectEl = currentEl<QmlObject>();
+ QmlObject &containingObject = std::get<QmlObject>(containingObjectEl.item.value);
+ QString idName = iExp->name.toString();
+ Id idVal(idName, qmlFile.canonicalPath().path(containingObject.pathFromOwner()));
+ idVal.value = script;
+ containingObject.setIdStr(idName);
+ FileLocations::addRegion(containingObjectEl.fileLocations, IdTokenRegion,
+ combineLocations(el->qualifiedId));
+ FileLocations::addRegion(containingObjectEl.fileLocations, IdColonTokenRegion,
+ el->colonToken);
+ FileLocations::addRegion(containingObjectEl.fileLocations, IdNameRegion,
+ combineLocations(el->statement));
+ QmlComponent &comp = current<QmlComponent>();
+ pathFromOwner = comp.addId(idVal, AddOption::KeepExisting, &idPtr);
+ QRegularExpression idRe(QRegularExpression::anchoredPattern(
+ QStringLiteral(uR"([[:lower:]][[:lower:][:upper:]0-9_]*)")));
+ auto m = idRe.matchView(iExp->name);
+ if (!m.hasMatch()) {
+ qmlFile.addError(std::move(
+ astParseErrors()
.warning(tr("id attributes should only be a lower case letter "
- "followed by letters, numbers or underscore, not %1 "
- "%2, assuming they refer to a property")
- .arg(script->code(), script->astRelocatableDump()))
- .withPath(pathFromOwner));
+ "followed by letters, numbers or underscore, not %1")
+ .arg(iExp->name))
+ .withPath(pathFromOwner)));
}
} else {
pathFromOwner =
current<QmlObject>().addBinding(bindingV, AddOption::KeepExisting, &bindingPtr);
Q_ASSERT_X(bindingPtr, className, "binding could not be retrieved");
+ qmlFile.addError(std::move(
+ astParseErrors()
+ .warning(tr("id attributes should only be a lower case letter "
+ "followed by letters, numbers or underscore, not %1 "
+ "%2, assuming they refer to a property")
+ .arg(script->code(), script->astRelocatableDump()))
+ .withPath(pathFromOwner)));
}
- if (bindingPtr)
- pushEl(pathFromOwner, *bindingPtr, el);
- else if (idPtr)
- pushEl(pathFromOwner, *idPtr, el);
- else
- Q_UNREACHABLE();
- loadAnnotations(el);
- // avoid duplicate colon location for id?
- FileLocations::addRegion(nodeStack.last().fileLocations, u"colon", el->colonToken);
- return false;
- }
-
- void endVisit(AST::UiScriptBinding *) override
- {
- DomValue &lastEl = currentNode();
- index_type idx = currentIndex();
- if (lastEl.kind == DomType::Binding) {
- Binding &b = std::get<Binding>(lastEl.value);
- QmlObject &containingObject = current<QmlObject>();
- Binding *bPtr = valueFromMultimap(containingObject.m_bindings, b.name(), idx);
- Q_ASSERT(bPtr);
- *bPtr = b;
- } else if (lastEl.kind == DomType::Id) {
- Id &id = std::get<Id>(lastEl.value);
- QmlComponent &comp = current<QmlComponent>();
- Id *idPtr = valueFromMultimap(comp.m_ids, id.name, idx);
- *idPtr = id;
- } else {
- Q_UNREACHABLE();
- }
- removeCurrentNode({});
+ } else {
+ pathFromOwner =
+ current<QmlObject>().addBinding(bindingV, AddOption::KeepExisting, &bindingPtr);
+ QmlStackElement &containingObjectEl = currentEl<QmlObject>();
+ // remove the containingObjectEl.path prefix from pathFromOwner
+ Path pathFromContainingObject = pathFromOwner.mid(containingObjectEl.path.length());
+ auto bindingFileLocation =
+ FileLocations::ensure(containingObjectEl.fileLocations, pathFromContainingObject);
+ FileLocations::addRegion(bindingFileLocation, IdentifierRegion,
+ el->qualifiedId->identifierToken);
+ FileLocations::addRegion(bindingFileLocation, ColonTokenRegion, el->colonToken);
+
+ setBindingIdentifiers(pathFromOwner, el->qualifiedId, bindingPtr);
+
+ Q_ASSERT_X(bindingPtr, className, "binding could not be retrieved");
}
+ if (bindingPtr)
+ pushEl(pathFromOwner, *bindingPtr, el);
+ else if (idPtr)
+ pushEl(pathFromOwner, *idPtr, el);
+ else
+ Q_UNREACHABLE();
+ loadAnnotations(el);
+ // avoid duplicate colon location for id?
+ FileLocations::addRegion(nodeStack.last().fileLocations, ColonTokenRegion, el->colonToken);
+ return true;
+}
- bool visit(AST::UiArrayBinding *el) override
- {
- QList<QmlObject> value;
- Binding bindingV(toString(el->qualifiedId), value, BindingType::Normal);
- Binding *bindingPtr;
- Path bindingPathFromOwner =
- current<QmlObject>().addBinding(bindingV, AddOption::KeepExisting, &bindingPtr);
- if (bindingV.name() == u"id")
- qmlFile.addError(
- myParseErrors()
- .error(tr("id attributes should have only simple strings as values"))
- .withPath(bindingPathFromOwner));
- pushEl(bindingPathFromOwner, *bindingPtr, el);
- FileLocations::addRegion(currentNodeEl().fileLocations, u"colon", el->colonToken);
- loadAnnotations(el);
- FileLocations::Tree arrayList =
- createMap(currentNodeEl().fileLocations, Path::Field(Fields::value), nullptr);
- FileLocations::addRegion(arrayList, u"leftSquareBrace", el->lbracketToken);
- FileLocations::addRegion(arrayList, u"rightSquareBrace", el->lbracketToken);
- arrayBindingLevels.append(nodeStack.size());
- return true;
- }
-
- void endVisit(AST::UiArrayBinding *) override
- {
- index_type idx = currentIndex();
- Binding &b = std::get<Binding>(currentNode().value);
- Binding *bPtr = valueFromMultimap(current<QmlObject>().m_bindings, b.name(), idx);
+void QQmlDomAstCreator::setScriptExpression (const std::shared_ptr<ScriptExpression>& value)
+{
+ if (m_enableScriptExpressions
+ && (scriptNodeStack.size() != 1 || currentScriptNodeEl().isList()))
+ Q_SCRIPTELEMENT_DISABLE();
+ if (m_enableScriptExpressions) {
+ FileLocations::Tree valueLoc = FileLocations::ensure(currentNodeEl().fileLocations,
+ Path().field(Fields::value));
+ value->setScriptElement(finalizeScriptExpression(currentScriptNodeEl().takeVariant(),
+ Path().field(Fields::scriptElement),
+ valueLoc));
+ removeCurrentScriptNode({});
+ }
+};
+
+void QQmlDomAstCreator::endVisit(AST::UiScriptBinding *)
+{
+ DomValue &lastEl = currentNode();
+ index_type idx = currentIndex();
+ if (lastEl.kind == DomType::Binding) {
+ Binding &b = std::get<Binding>(lastEl.value);
+
+ setScriptExpression(b.scriptExpressionValue());
+
+ QmlObject &containingObject = current<QmlObject>();
+ Binding *bPtr = valueFromMultimap(containingObject.m_bindings, b.name(), idx);
+ Q_ASSERT(bPtr);
*bPtr = b;
- arrayBindingLevels.removeLast();
- removeCurrentNode(DomType::Binding);
+ } else if (lastEl.kind == DomType::Id) {
+ Id &id = std::get<Id>(lastEl.value);
+
+ setScriptExpression(id.value);
+
+ QmlComponent &comp = current<QmlComponent>();
+ Id *idPtr = valueFromMultimap(comp.m_ids, id.name, idx);
+ *idPtr = id;
+ } else {
+ Q_UNREACHABLE();
}
- bool visit(AST::UiParameterList *el) override
- { // currently not used...
- MethodParameter p {
- el->name.toString(),
- el->type ? el->type->toString() : QString(),
- false, false, false, {}, {}, {}
- };
- return true;
- }
- void endVisit(AST::UiParameterList *el) override
- {
- Node::accept(el->next, this); // put other args at the same level as this one...
- }
-
- bool visit(AST::UiQualifiedId *) override { return false; }
-
- bool visit(AST::UiEnumDeclaration *el) override
- {
- EnumDecl eDecl;
- eDecl.setName(el->name.toString());
- EnumDecl *ePtr;
- Path enumPathFromOwner =
- current<QmlComponent>().addEnumeration(eDecl, AddOption::KeepExisting, &ePtr);
- pushEl(enumPathFromOwner, *ePtr, el);
- loadAnnotations(el);
- return true;
- }
-
- void endVisit(AST::UiEnumDeclaration *) override
- {
- EnumDecl &e = std::get<EnumDecl>(currentNode().value);
- EnumDecl *ePtr =
- valueFromMultimap(current<QmlComponent>().m_enumerations, e.name(), currentIndex());
- Q_ASSERT(ePtr);
- *ePtr = e;
- removeCurrentNode(DomType::EnumDecl);
- }
-
- bool visit(AST::UiEnumMemberList *el) override
- {
- EnumItem it(el->member.toString(), el->value);
- EnumDecl &eDecl = std::get<EnumDecl>(currentNode().value);
- Path itPathFromDecl = eDecl.addValue(it);
- FileLocations::addRegion(createMap(DomType::EnumItem, itPathFromDecl, nullptr), QString(),
- combine(el->memberToken, el->valueToken));
- return true;
- }
-
- void endVisit(AST::UiEnumMemberList *el) override
- {
- Node::accept(el->next, this); // put other enum members at the same level as this one...
- }
-
- bool visit(AST::UiInlineComponent *el) override
- {
- QStringList els = current<QmlComponent>().name().split(QLatin1Char('.'));
- els.append(el->name.toString());
- QString cName = els.join(QLatin1Char('.'));
- QmlComponent *compPtr;
- Path p = qmlFilePtr->addComponent(QmlComponent(cName), AddOption::KeepExisting, &compPtr);
- pushEl(p, *compPtr, el);
- FileLocations::addRegion(nodeStack.last().fileLocations, u"component", el->componentToken);
- loadAnnotations(el);
- return true;
- }
-
- void endVisit(AST::UiInlineComponent *) override
- {
- QmlComponent &component = std::get<QmlComponent>(currentNode().value);
- QStringList nameEls = component.name().split(QChar::fromLatin1('.'));
- QString key = nameEls.mid(1).join(QChar::fromLatin1('.'));
- QmlComponent *cPtr = valueFromMultimap(qmlFilePtr->m_components, key, currentIndex());
- Q_ASSERT(cPtr);
- *cPtr = component;
- removeCurrentNode(DomType::QmlComponent);
- }
-
- bool visit(UiRequired *el) override
- {
- PropertyDefinition pDef;
- pDef.name = el->name.toString();
- pDef.isRequired = true;
- PropertyDefinition *pDefPtr;
- Path pathFromOwner =
- current<QmlObject>().addPropertyDef(pDef, AddOption::KeepExisting, &pDefPtr);
- createMap(DomType::PropertyDefinition, pathFromOwner, el);
- return false;
- }
-
- bool visit(AST::UiAnnotation *el) override
- {
- QmlObject a;
- a.setName(QStringLiteral(u"@") + toString(el->qualifiedTypeNameId));
- // add annotation prototype?
- DomValue &containingElement = currentNode();
- Path pathFromOwner;
- QmlObject *aPtr = nullptr;
- switch (containingElement.kind) {
- case DomType::QmlObject:
- pathFromOwner = std::get<QmlObject>(containingElement.value).addAnnotation(a, &aPtr);
- break;
- case DomType::Binding:
- pathFromOwner = std::get<Binding>(containingElement.value)
- .addAnnotation(currentNodeEl().path, a, &aPtr);
- break;
- case DomType::Id:
- pathFromOwner = std::get<Id>(containingElement.value)
- .addAnnotation(currentNodeEl().path, a, &aPtr);
- break;
- case DomType::PropertyDefinition:
- pathFromOwner = std::get<PropertyDefinition>(containingElement.value)
- .addAnnotation(currentNodeEl().path, a, &aPtr);
- break;
- case DomType::MethodInfo:
- pathFromOwner = std::get<MethodInfo>(containingElement.value)
- .addAnnotation(currentNodeEl().path, a, &aPtr);
- break;
- default:
- qCWarning(domLog) << "Unexpected container object for annotation:"
- << domTypeToString(containingElement.kind);
- Q_UNREACHABLE();
+ // there should be no more uncollected script elements
+ if (m_enableScriptExpressions && !scriptNodeStack.empty()) {
+ Q_SCRIPTELEMENT_DISABLE();
+ }
+ removeCurrentNode({});
+}
+
+bool QQmlDomAstCreator::visit(AST::UiArrayBinding *el)
+{
+ QList<QmlObject> value;
+ Binding bindingV(toString(el->qualifiedId), value, BindingType::Normal);
+ Binding *bindingPtr;
+ Path bindingPathFromOwner =
+ current<QmlObject>().addBinding(bindingV, AddOption::KeepExisting, &bindingPtr);
+ if (bindingV.name() == u"id")
+ qmlFile.addError(std::move(
+ astParseErrors()
+ .error(tr("id attributes should have only simple strings as values"))
+ .withPath(bindingPathFromOwner)));
+
+ setBindingIdentifiers(bindingPathFromOwner, el->qualifiedId, bindingPtr);
+
+ pushEl(bindingPathFromOwner, *bindingPtr, el);
+ FileLocations::addRegion(currentNodeEl().fileLocations, ColonTokenRegion, el->colonToken);
+ loadAnnotations(el);
+ FileLocations::Tree arrayList =
+ createMap(currentNodeEl().fileLocations, Path::Field(Fields::value), nullptr);
+ FileLocations::addRegion(arrayList, LeftBracketRegion, el->lbracketToken);
+ FileLocations::addRegion(arrayList, RightBracketRegion, el->rbracketToken);
+ arrayBindingLevels.append(nodeStack.size());
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::UiArrayBinding *)
+{
+ index_type idx = currentIndex();
+ Binding &b = std::get<Binding>(currentNode().value);
+ Binding *bPtr = valueFromMultimap(current<QmlObject>().m_bindings, b.name(), idx);
+ *bPtr = b;
+ arrayBindingLevels.removeLast();
+ removeCurrentNode(DomType::Binding);
+}
+
+void QQmlDomAstCreator::endVisit(AST::ArgumentList *list)
+{
+ endVisitForLists(list);
+}
+
+bool QQmlDomAstCreator::visit(AST::UiParameterList *)
+{
+ return false; // do not create script node for Ui stuff
+}
+
+void QQmlDomAstCreator::endVisit(AST::PatternElementList *list)
+{
+ endVisitForLists<AST::PatternElementList>(list, [](AST::PatternElementList *current) {
+ int toCollect = 0;
+ toCollect += bool(current->elision);
+ toCollect += bool(current->element);
+ return toCollect;
+ });
+}
+
+void QQmlDomAstCreator::endVisit(AST::PatternPropertyList *list)
+{
+ endVisitForLists(list);
+}
+
+/*!
+ \internal
+ Implementing the logic of this method in \c QQmlDomAstCreator::visit(AST::UiQualifiedId *)
+ would create scriptelements at places where there are not needed. This is mainly because
+ UiQualifiedId's appears inside and outside of script parts.
+*/
+ScriptElementVariant QQmlDomAstCreator::scriptElementForQualifiedId(AST::UiQualifiedId *expression)
+{
+ auto id = std::make_shared<ScriptElements::IdentifierExpression>(
+ expression->firstSourceLocation(), expression->lastSourceLocation());
+ id->setName(expression->toString());
+
+ return ScriptElementVariant::fromElement(id);
+}
+
+bool QQmlDomAstCreator::visit(AST::UiQualifiedId *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return false;
+}
+
+bool QQmlDomAstCreator::visit(AST::UiEnumDeclaration *el)
+{
+ EnumDecl eDecl;
+ eDecl.setName(el->name.toString());
+ EnumDecl *ePtr;
+ Path enumPathFromOwner =
+ current<QmlComponent>().addEnumeration(eDecl, AddOption::KeepExisting, &ePtr);
+ pushEl(enumPathFromOwner, *ePtr, el);
+ FileLocations::addRegion(nodeStack.last().fileLocations, EnumKeywordRegion, el->enumToken);
+ FileLocations::addRegion(nodeStack.last().fileLocations, IdentifierRegion, el->identifierToken);
+ loadAnnotations(el);
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::UiEnumDeclaration *)
+{
+ EnumDecl &e = std::get<EnumDecl>(currentNode().value);
+ EnumDecl *ePtr =
+ valueFromMultimap(current<QmlComponent>().m_enumerations, e.name(), currentIndex());
+ Q_ASSERT(ePtr);
+ *ePtr = e;
+ removeCurrentNode(DomType::EnumDecl);
+}
+
+bool QQmlDomAstCreator::visit(AST::UiEnumMemberList *el)
+{
+ EnumItem it(el->member.toString(), el->value,
+ el->valueToken.isValid() ? EnumItem::ValueKind::ExplicitValue
+ : EnumItem::ValueKind::ImplicitValue);
+ EnumDecl &eDecl = std::get<EnumDecl>(currentNode().value);
+ Path itPathFromDecl = eDecl.addValue(it);
+ const auto map = createMap(DomType::EnumItem, itPathFromDecl, nullptr);
+ FileLocations::addRegion(map, MainRegion, combine(el->memberToken, el->valueToken));
+ if (el->memberToken.isValid())
+ FileLocations::addRegion(map, IdentifierRegion, el->memberToken);
+ if (el->valueToken.isValid())
+ FileLocations::addRegion(map, EnumValueRegion, el->valueToken);
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::UiEnumMemberList *el)
+{
+ Node::accept(el->next, this); // put other enum members at the same level as this one...
+}
+
+bool QQmlDomAstCreator::visit(AST::UiInlineComponent *el)
+{
+ QStringList els = current<QmlComponent>().name().split(QLatin1Char('.'));
+ els.append(el->name.toString());
+ QString cName = els.join(QLatin1Char('.'));
+ QmlComponent *compPtr;
+ Path p = qmlFilePtr->addComponent(QmlComponent(cName), AddOption::KeepExisting, &compPtr);
+
+ if (m_enableScriptExpressions) {
+ auto inlineComponentType =
+ makeGenericScriptElement(el->identifierToken, DomType::ScriptType);
+
+ auto typeName = std::make_shared<ScriptElements::IdentifierExpression>(el->identifierToken);
+ typeName->setName(el->name);
+ inlineComponentType->insertChild(Fields::typeName,
+ ScriptElementVariant::fromElement(typeName));
+ compPtr->setNameIdentifiers(
+ finalizeScriptExpression(ScriptElementVariant::fromElement(inlineComponentType),
+ p.field(Fields::nameIdentifiers), rootMap));
+ }
+
+ pushEl(p, *compPtr, el);
+ FileLocations::addRegion(nodeStack.last().fileLocations, ComponentKeywordRegion,
+ el->componentToken);
+ FileLocations::addRegion(nodeStack.last().fileLocations, IdentifierRegion, el->identifierToken);
+ loadAnnotations(el);
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::UiInlineComponent *)
+{
+ QmlComponent &component = std::get<QmlComponent>(currentNode().value);
+ QStringList nameEls = component.name().split(QChar::fromLatin1('.'));
+ QString key = nameEls.mid(1).join(QChar::fromLatin1('.'));
+ QmlComponent *cPtr = valueFromMultimap(qmlFilePtr->lazyMembers().m_components, key, currentIndex());
+ Q_ASSERT(cPtr);
+ *cPtr = component;
+ removeCurrentNode(DomType::QmlComponent);
+}
+
+bool QQmlDomAstCreator::visit(UiRequired *el)
+{
+ PropertyDefinition pDef;
+ pDef.name = el->name.toString();
+ pDef.isRequired = true;
+ PropertyDefinition *pDefPtr;
+ Path pathFromOwner =
+ current<QmlObject>().addPropertyDef(pDef, AddOption::KeepExisting, &pDefPtr);
+ createMap(DomType::PropertyDefinition, pathFromOwner, el);
+ return false;
+}
+
+bool QQmlDomAstCreator::visit(AST::UiAnnotation *el)
+{
+ QmlObject a;
+ a.setName(QStringLiteral(u"@") + toString(el->qualifiedTypeNameId));
+ // add annotation prototype?
+ DomValue &containingElement = currentNode();
+ Path pathFromOwner;
+ QmlObject *aPtr = nullptr;
+ switch (containingElement.kind) {
+ case DomType::QmlObject:
+ pathFromOwner = std::get<QmlObject>(containingElement.value).addAnnotation(a, &aPtr);
+ break;
+ case DomType::Binding:
+ pathFromOwner = std::get<Binding>(containingElement.value)
+ .addAnnotation(currentNodeEl().path, a, &aPtr);
+ break;
+ case DomType::Id:
+ pathFromOwner =
+ std::get<Id>(containingElement.value).addAnnotation(currentNodeEl().path, a, &aPtr);
+ break;
+ case DomType::PropertyDefinition:
+ pathFromOwner = std::get<PropertyDefinition>(containingElement.value)
+ .addAnnotation(currentNodeEl().path, a, &aPtr);
+ break;
+ case DomType::MethodInfo:
+ pathFromOwner = std::get<MethodInfo>(containingElement.value)
+ .addAnnotation(currentNodeEl().path, a, &aPtr);
+ break;
+ default:
+ qCWarning(domLog) << "Unexpected container object for annotation:"
+ << domTypeToString(containingElement.kind);
+ Q_UNREACHABLE();
+ }
+ pushEl(pathFromOwner, *aPtr, el);
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::UiAnnotation *)
+{
+ DomValue &containingElement = currentNode(1);
+ Path pathFromOwner;
+ QmlObject &a = std::get<QmlObject>(currentNode().value);
+ switch (containingElement.kind) {
+ case DomType::QmlObject:
+ std::get<QmlObject>(containingElement.value).m_annotations[currentIndex()] = a;
+ break;
+ case DomType::Binding:
+ std::get<Binding>(containingElement.value).m_annotations[currentIndex()] = a;
+ break;
+ case DomType::Id:
+ std::get<Id>(containingElement.value).annotations[currentIndex()] = a;
+ break;
+ case DomType::PropertyDefinition:
+ std::get<PropertyDefinition>(containingElement.value).annotations[currentIndex()] = a;
+ break;
+ case DomType::MethodInfo:
+ std::get<MethodInfo>(containingElement.value).annotations[currentIndex()] = a;
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+ removeCurrentNode(DomType::QmlObject);
+}
+
+void QQmlDomAstCreator::throwRecursionDepthError()
+{
+ qmlFile.addError(astParseErrors().error(
+ tr("Maximum statement or expression depth exceeded in QmlDomAstCreator")));
+}
+
+void QQmlDomAstCreator::endVisit(AST::StatementList *list)
+{
+ endVisitForLists(list);
+}
+
+bool QQmlDomAstCreator::visit(AST::BinaryExpression *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::BinaryExpression *exp)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeScriptElement<ScriptElements::BinaryExpression>(exp);
+ current->addLocation(OperatorTokenRegion, exp->operatorToken);
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->setRight(currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->setLeft(currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::Block *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::Block *block)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeScriptElement<ScriptElements::BlockStatement>(block);
+
+ if (block->statements) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
+ current->setStatements(currentScriptNodeEl().takeList());
+ removeCurrentScriptNode(DomType::List);
+ }
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::ForStatement *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::ForStatement *forStatement)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeScriptElement<ScriptElements::ForStatement>(forStatement);
+ current->addLocation(FileLocationRegion::ForKeywordRegion, forStatement->forToken);
+ current->addLocation(FileLocationRegion::LeftParenthesisRegion, forStatement->lparenToken);
+ current->addLocation(FileLocationRegion::FirstSemicolonTokenRegion,
+ forStatement->firstSemicolonToken);
+ current->addLocation(FileLocationRegion::SecondSemicolonRegion,
+ forStatement->secondSemicolonToken);
+ current->addLocation(FileLocationRegion::RightParenthesisRegion, forStatement->rparenToken);
+
+ if (forStatement->statement) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->setBody(currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode(std::nullopt);
+ }
+
+ if (forStatement->expression) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->setExpression(currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode(std::nullopt);
+ }
+
+ if (forStatement->condition) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->setCondition(currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode(std::nullopt);
+ }
+
+ if (forStatement->declarations) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
+ auto variableDeclaration = makeGenericScriptElement(forStatement->declarations,
+ DomType::ScriptVariableDeclaration);
+
+ ScriptElements::ScriptList list = currentScriptNodeEl().takeList();
+ list.replaceKindForGenericChildren(DomType::ScriptPattern,
+ DomType::ScriptVariableDeclarationEntry);
+ variableDeclaration->insertChild(Fields::declarations, std::move(list));
+ removeCurrentScriptNode({});
+
+ current->setDeclarations(ScriptElementVariant::fromElement(variableDeclaration));
+
+ if (auto pe = forStatement->declarations->declaration;
+ pe && pe->declarationKindToken.isValid()) {
+ current->addLocation(FileLocationRegion::TypeIdentifierRegion,
+ pe->declarationKindToken);
}
- pushEl(pathFromOwner, *aPtr, el);
- return true;
}
- void endVisit(AST::UiAnnotation *) override
- {
- DomValue &containingElement = currentNode(1);
- Path pathFromOwner;
- QmlObject &a = std::get<QmlObject>(currentNode().value);
- switch (containingElement.kind) {
- case DomType::QmlObject:
- std::get<QmlObject>(containingElement.value).m_annotations[currentIndex()] = a;
- break;
- case DomType::Binding:
- std::get<Binding>(containingElement.value).m_annotations[currentIndex()] = a;
- break;
- case DomType::Id:
- std::get<Id>(containingElement.value).annotations[currentIndex()] = a;
- break;
- case DomType::PropertyDefinition:
- std::get<PropertyDefinition>(containingElement.value).annotations[currentIndex()] = a;
- break;
- case DomType::MethodInfo:
- std::get<MethodInfo>(containingElement.value).annotations[currentIndex()] = a;
- break;
- default:
- Q_UNREACHABLE();
+ if (forStatement->initialiser) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->setInitializer(currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode(std::nullopt);
+ }
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::IdentifierExpression *expression)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ auto current = makeScriptElement<ScriptElements::IdentifierExpression>(expression);
+ current->setName(expression->name);
+ pushScriptElement(current);
+ return true;
+}
+
+bool QQmlDomAstCreator::visit(AST::NumericLiteral *expression)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ auto current = makeScriptElement<ScriptElements::Literal>(expression);
+ current->setLiteralValue(expression->value);
+ pushScriptElement(current);
+ return true;
+}
+
+bool QQmlDomAstCreator::visit(AST::StringLiteral *expression)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ pushScriptElement(makeStringLiteral(expression->value, expression));
+ return true;
+}
+
+bool QQmlDomAstCreator::visit(AST::NullExpression *expression)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ auto current = makeScriptElement<ScriptElements::Literal>(expression);
+ current->setLiteralValue(nullptr);
+ pushScriptElement(current);
+ return true;
+}
+
+bool QQmlDomAstCreator::visit(AST::TrueLiteral *expression)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ auto current = makeScriptElement<ScriptElements::Literal>(expression);
+ current->setLiteralValue(true);
+ pushScriptElement(current);
+ return true;
+}
+
+bool QQmlDomAstCreator::visit(AST::FalseLiteral *expression)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ auto current = makeScriptElement<ScriptElements::Literal>(expression);
+ current->setLiteralValue(false);
+ pushScriptElement(current);
+ return true;
+}
+
+bool QQmlDomAstCreator::visit(AST::IdentifierPropertyName *expression)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ auto current = makeScriptElement<ScriptElements::IdentifierExpression>(expression);
+ current->setName(expression->id);
+ pushScriptElement(current);
+ return true;
+}
+
+bool QQmlDomAstCreator::visit(AST::StringLiteralPropertyName *expression)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ pushScriptElement(makeStringLiteral(expression->id, expression));
+ return true;
+}
+
+bool QQmlDomAstCreator::visit(AST::TypeAnnotation *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ // do nothing: the work is done in (end)visit(AST::Type*).
+ return true;
+}
+
+bool QQmlDomAstCreator::visit(AST::NumericLiteralPropertyName *expression)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ auto current = makeScriptElement<ScriptElements::Literal>(expression);
+ current->setLiteralValue(expression->id);
+ pushScriptElement(current);
+ return true;
+}
+
+bool QQmlDomAstCreator::visit(AST::ComputedPropertyName *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ // nothing to do, just forward the underlying expression without changing/wrapping it
+ return true;
+}
+
+template<typename T>
+void QQmlDomAstCreator::endVisitForLists(T *list,
+ const std::function<int(T *)> &scriptElementsPerEntry)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeScriptList(list);
+ for (auto it = list; it; it = it->next) {
+ const int entriesToCollect = scriptElementsPerEntry ? scriptElementsPerEntry(it) : 1;
+ for (int i = 0; i < entriesToCollect; ++i) {
+ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
+ auto last = scriptNodeStack.takeLast();
+ if (last.isList())
+ current.append(last.takeList());
+ else
+ current.append(last.takeVariant());
}
- removeCurrentNode(DomType::QmlObject);
}
- void throwRecursionDepthError() override
- {
- qmlFile.addError(myParseErrors().error(
- tr("Maximum statement or expression depth exceeded in QmlDomAstCreator")));
+ current.reverse();
+ pushScriptElement(current);
+}
+
+void QQmlDomAstCreator::endVisit(AST::VariableDeclarationList *list)
+{
+ endVisitForLists(list);
+}
+
+bool QQmlDomAstCreator::visit(AST::Elision *list)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ auto currentList = makeScriptList(list);
+
+ for (auto it = list; it; it = it->next) {
+ auto current = makeGenericScriptElement(it->commaToken, DomType::ScriptElision);
+ currentList.append(ScriptElementVariant::fromElement(current));
}
-};
+ pushScriptElement(currentList);
+
+ return false; // return false because we already iterated over the children using the custom
+ // iteration above
+}
+
+bool QQmlDomAstCreator::visit(AST::PatternElement *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
+
+/*!
+ \internal
+ Avoid code-duplication, reuse this code when doing endVisit on types inheriting from
+ AST::PatternElement.
+*/
+void QQmlDomAstCreator::endVisitHelper(
+ AST::PatternElement *pe,
+ const std::shared_ptr<ScriptElements::GenericScriptElement> &current)
+{
+ if (pe->equalToken.isValid())
+ current->addLocation(FileLocationRegion::EqualTokenRegion, pe->equalToken);
+
+ if (pe->identifierToken.isValid() && !pe->bindingIdentifier.isEmpty()) {
+ auto identifier =
+ std::make_shared<ScriptElements::IdentifierExpression>(pe->identifierToken);
+ identifier->setName(pe->bindingIdentifier);
+ current->insertChild(Fields::identifier, ScriptElementVariant::fromElement(identifier));
+ }
+ if (pe->initializer) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::initializer, scriptNodeStack.last().takeVariant());
+ scriptNodeStack.removeLast();
+ }
+ if (pe->typeAnnotation) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::type, scriptNodeStack.last().takeVariant());
+ scriptNodeStack.removeLast();
+ }
+ if (pe->bindingTarget) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::bindingElement, scriptNodeStack.last().takeVariant());
+ scriptNodeStack.removeLast();
+ }
+}
+
+void QQmlDomAstCreator::endVisit(AST::PatternElement *pe)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto element = makeGenericScriptElement(pe, DomType::ScriptPattern);
+ endVisitHelper(pe, element);
+ // check if helper disabled scriptexpressions
+ if (!m_enableScriptExpressions)
+ return;
+
+ pushScriptElement(element);
+}
+
+bool QQmlDomAstCreator::visit(AST::IfStatement *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::IfStatement *ifStatement)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeScriptElement<ScriptElements::IfStatement>(ifStatement);
+ current->addLocation(LeftParenthesisRegion, ifStatement->lparenToken);
+ current->addLocation(RightParenthesisRegion, ifStatement->rparenToken);
+ current->addLocation(ElseKeywordRegion, ifStatement->elseToken);
+ current->addLocation(IfKeywordRegion, ifStatement->ifToken);
+
+ if (ifStatement->ko) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->setAlternative(scriptNodeStack.last().takeVariant());
+ scriptNodeStack.removeLast();
+ }
+
+ if (ifStatement->ok) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->setConsequence(scriptNodeStack.last().takeVariant());
+ scriptNodeStack.removeLast();
+ }
+ if (ifStatement->expression) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->setCondition(scriptNodeStack.last().takeVariant());
+ scriptNodeStack.removeLast();
+ }
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::ReturnStatement *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::ReturnStatement *returnStatement)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeScriptElement<ScriptElements::ReturnStatement>(returnStatement);
+ current->addLocation(ReturnKeywordRegion, returnStatement->returnToken);
+
+ if (returnStatement->expression) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->setExpression(currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::YieldExpression *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::YieldExpression *yExpression)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeGenericScriptElement(yExpression, DomType::ScriptYieldExpression);
+ current->addLocation(YieldKeywordRegion, yExpression->yieldToken);
+
+ if (yExpression->expression) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::FieldMemberExpression *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::FieldMemberExpression *expression)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeScriptElement<ScriptElements::BinaryExpression>(expression);
+ current->setOp(ScriptElements::BinaryExpression::FieldMemberAccess);
+ current->addLocation(FileLocationRegion::OperatorTokenRegion, expression->dotToken);
+
+ if (expression->base) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->setLeft(currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ auto scriptIdentifier =
+ std::make_shared<ScriptElements::IdentifierExpression>(expression->identifierToken);
+ scriptIdentifier->setName(expression->name);
+ current->setRight(ScriptElementVariant::fromElement(scriptIdentifier));
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::ArrayMemberExpression *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
-void createDom(MutableDomItem qmlFile)
+void QQmlDomAstCreator::endVisit(AST::ArrayMemberExpression *expression)
{
- if (std::shared_ptr<QmlFile> qmlFilePtr = qmlFile.ownerAs<QmlFile>()) {
- QmlDomAstCreator componentCreator(qmlFile);
- AST::Node::accept(qmlFilePtr->ast(), &componentCreator);
- AstComments::collectComments(qmlFile);
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeScriptElement<ScriptElements::BinaryExpression>(expression);
+ current->setOp(ScriptElements::BinaryExpression::ArrayMemberAccess);
+ current->addLocation(FileLocationRegion::OperatorTokenRegion, expression->lbracketToken);
+
+ if (expression->expression) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ // if scriptNodeStack.last() is fieldmember expression, add expression to it instead of
+ // creating new one
+ current->setRight(currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ if (expression->base) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->setLeft(currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::CallExpression *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::CallExpression *exp)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeGenericScriptElement(exp, DomType::ScriptCallExpression);
+ current->addLocation(LeftParenthesisRegion, exp->lparenToken);
+ current->addLocation(RightParenthesisRegion, exp->rparenToken);
+
+ if (exp->arguments) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
+ current->insertChild(Fields::arguments, currentScriptNodeEl().takeList());
+ removeCurrentScriptNode({});
} else {
- qCWarning(creatorLog) << "createDom called on non qmlFile";
+ // insert empty list
+ current->insertChild(Fields::arguments,
+ ScriptElements::ScriptList(exp->lparenToken, exp->rparenToken));
+ }
+
+ if (exp->base) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::callee, currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::ArrayPattern *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::ArrayPattern *exp)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeGenericScriptElement(exp, DomType::ScriptArray);
+
+ if (exp->elements) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
+ ScriptElements::ScriptList list = currentScriptNodeEl().takeList();
+ list.replaceKindForGenericChildren(DomType::ScriptPattern, DomType::ScriptArrayEntry);
+ current->insertChild(Fields::elements, std::move(list));
+
+ removeCurrentScriptNode({});
+ } else {
+ // insert empty list
+ current->insertChild(Fields::elements,
+ ScriptElements::ScriptList(exp->lbracketToken, exp->rbracketToken));
+ }
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::ObjectPattern *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::ObjectPattern *exp)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeGenericScriptElement(exp, DomType::ScriptObject);
+
+ if (exp->properties) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
+ current->insertChild(Fields::properties, currentScriptNodeEl().takeList());
+ removeCurrentScriptNode({});
+ } else {
+ // insert empty list
+ current->insertChild(Fields::properties,
+ ScriptElements::ScriptList(exp->lbraceToken, exp->rbraceToken));
+ }
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::PatternProperty *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::PatternProperty *exp)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeGenericScriptElement(exp, DomType::ScriptProperty);
+
+ // handle the stuff from PatternProperty's base class PatternElement
+ endVisitHelper(static_cast<PatternElement *>(exp), current);
+
+ // check if helper disabled scriptexpressions
+ if (!m_enableScriptExpressions)
+ return;
+
+ if (exp->name) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::name, currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::VariableStatement *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::VariableStatement *statement)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeGenericScriptElement(statement, DomType::ScriptVariableDeclaration);
+ current->addLocation(FileLocationRegion::TypeIdentifierRegion, statement->declarationKindToken);
+
+ if (statement->declarations) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
+
+ ScriptElements::ScriptList list = currentScriptNodeEl().takeList();
+ list.replaceKindForGenericChildren(DomType::ScriptPattern,
+ DomType::ScriptVariableDeclarationEntry);
+ current->insertChild(Fields::declarations, std::move(list));
+
+ removeCurrentScriptNode({});
+ }
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::Type *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::Type *exp)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeGenericScriptElement(exp, DomType::ScriptType);
+
+ if (exp->typeArgument) {
+ current->insertChild(Fields::typeArgumentName,
+ fieldMemberExpressionForQualifiedId(exp->typeArgument));
+ current->addLocation(FileLocationRegion::IdentifierRegion, combineLocations(exp->typeArgument));
+ }
+
+ if (exp->typeId) {
+ current->insertChild(Fields::typeName, fieldMemberExpressionForQualifiedId(exp->typeId));
+ current->addLocation(FileLocationRegion::TypeIdentifierRegion, combineLocations(exp->typeId));
+ }
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::DefaultClause *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::DefaultClause *exp)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeGenericScriptElement(exp, DomType::ScriptDefaultClause);
+ current->addLocation(DefaultKeywordRegion, exp->defaultToken);
+ current->addLocation(ColonTokenRegion, exp->colonToken);
+
+ if (exp->statements) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
+ current->insertChild(Fields::statements, currentScriptNodeEl().takeList());
+ removeCurrentScriptNode({});
+ }
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::CaseClause *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::CaseClause *exp)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeGenericScriptElement(exp, DomType::ScriptCaseClause);
+ current->addLocation(FileLocationRegion::CaseKeywordRegion, exp->caseToken);
+ current->addLocation(FileLocationRegion::ColonTokenRegion, exp->colonToken);
+
+ if (exp->statements) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
+ current->insertChild(Fields::statements, currentScriptNodeEl().takeList());
+ removeCurrentScriptNode({});
+ }
+
+ if (exp->expression) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::CaseClauses *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::CaseClauses *list)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeScriptList(list);
+
+ for (auto it = list; it; it = it->next) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current.append(scriptNodeStack.takeLast().takeVariant());
+ }
+
+ current.reverse();
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::CaseBlock *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::CaseBlock *exp)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeGenericScriptElement(exp, DomType::ScriptCaseBlock);
+ current->addLocation(FileLocationRegion::LeftBraceRegion, exp->lbraceToken);
+ current->addLocation(FileLocationRegion::RightBraceRegion, exp->rbraceToken);
+
+ if (exp->moreClauses) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
+ current->insertChild(Fields::moreCaseClauses, currentScriptNodeEl().takeList());
+ removeCurrentScriptNode({});
+ }
+
+ if (exp->defaultClause) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::defaultClause, currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ if (exp->clauses) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
+ current->insertChild(Fields::caseClauses, currentScriptNodeEl().takeList());
+ removeCurrentScriptNode({});
+ }
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::SwitchStatement *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::SwitchStatement *exp)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeGenericScriptElement(exp, DomType::ScriptSwitchStatement);
+ current->addLocation(FileLocationRegion::SwitchKeywordRegion, exp->switchToken);
+ current->addLocation(FileLocationRegion::LeftParenthesisRegion, exp->lparenToken);
+ current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
+
+ if (exp->block) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::caseBlock, currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+ if (exp->expression) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::WhileStatement *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::WhileStatement *exp)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeGenericScriptElement(exp, DomType::ScriptWhileStatement);
+ current->addLocation(FileLocationRegion::WhileKeywordRegion, exp->whileToken);
+ current->addLocation(FileLocationRegion::LeftParenthesisRegion, exp->lparenToken);
+ current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
+
+ if (exp->statement) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::body, currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ if (exp->expression) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::DoWhileStatement *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::DoWhileStatement *exp)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeGenericScriptElement(exp, DomType::ScriptDoWhileStatement);
+ current->addLocation(FileLocationRegion::DoKeywordRegion, exp->doToken);
+ current->addLocation(FileLocationRegion::WhileKeywordRegion, exp->whileToken);
+ current->addLocation(FileLocationRegion::LeftParenthesisRegion, exp->lparenToken);
+ current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
+
+ if (exp->expression) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ if (exp->statement) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::body, currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::ForEachStatement *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::ForEachStatement *exp)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeGenericScriptElement(exp, DomType::ScriptForEachStatement);
+ current->addLocation(FileLocationRegion::ForKeywordRegion, exp->forToken);
+ current->addLocation(FileLocationRegion::InOfTokenRegion, exp->inOfToken);
+ current->addLocation(FileLocationRegion::LeftParenthesisRegion, exp->lparenToken);
+ current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
+
+ if (exp->statement) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::body, currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+ if (exp->expression) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ if (exp->lhs) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::bindingElement, currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+
+ if (auto pe = AST::cast<PatternElement *>(exp->lhs);
+ pe && pe->declarationKindToken.isValid()) {
+ current->addLocation(FileLocationRegion::TypeIdentifierRegion,
+ pe->declarationKindToken);
+ }
+ }
+
+ pushScriptElement(current);
+}
+
+
+bool QQmlDomAstCreator::visit(AST::ClassExpression *)
+{
+ // TODO: Add support for js expressions in classes
+ // For now, turning off explicitly to avoid unwanted problems
+ if (m_enableScriptExpressions)
+ Q_SCRIPTELEMENT_DISABLE();
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::ClassExpression *)
+{
+}
+
+bool QQmlDomAstCreator::visit(AST::TemplateLiteral *)
+{
+ // TODO: Add support for template literals
+ // For now, turning off explicitly to avoid unwanted problems
+ if (m_enableScriptExpressions)
+ Q_SCRIPTELEMENT_DISABLE();
+ return true;
+}
+
+bool QQmlDomAstCreator::visit(AST::TryStatement *)
+{
+ return m_enableScriptExpressions;
+}
+
+void QQmlDomAstCreator::endVisit(AST::TryStatement *statement)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeGenericScriptElement(statement, DomType::ScriptTryCatchStatement);
+ current->addLocation(FileLocationRegion::TryKeywordRegion, statement->tryToken);
+
+ if (auto exp = statement->finallyExpression) {
+ current->addLocation(FileLocationRegion::FinallyKeywordRegion, exp->finallyToken);
+
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::finallyBlock, currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ if (auto exp = statement->catchExpression) {
+ current->addLocation(FileLocationRegion::CatchKeywordRegion, exp->catchToken);
+ current->addLocation(FileLocationRegion::LeftParenthesisRegion, exp->lparenToken);
+ current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
+
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::catchBlock, currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::catchParameter, currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ if (statement->statement) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::block, currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::Catch *)
+{
+ // handled in visit(AST::TryStatement* )
+ return m_enableScriptExpressions;
+}
+
+void QQmlDomAstCreator::endVisit(AST::Catch *)
+{
+ // handled in endVisit(AST::TryStatement* )
+}
+
+bool QQmlDomAstCreator::visit(AST::Finally *)
+{
+ // handled in visit(AST::TryStatement* )
+ return m_enableScriptExpressions;
+}
+
+void QQmlDomAstCreator::endVisit(AST::Finally *)
+{
+ // handled in endVisit(AST::TryStatement* )
+}
+
+bool QQmlDomAstCreator::visit(AST::ThrowStatement *)
+{
+ return m_enableScriptExpressions;
+}
+
+void QQmlDomAstCreator::endVisit(AST::ThrowStatement *statement)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeGenericScriptElement(statement, DomType::ScriptThrowStatement);
+ current->addLocation(FileLocationRegion::ThrowKeywordRegion, statement->throwToken);
+
+ if (statement->expression) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::LabelledStatement *)
+{
+ return m_enableScriptExpressions;
+}
+
+void QQmlDomAstCreator::endVisit(AST::LabelledStatement *statement)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeGenericScriptElement(statement, DomType::ScriptLabelledStatement);
+ current->addLocation(FileLocationRegion::ColonTokenRegion, statement->colonToken);
+
+ auto label = std::make_shared<ScriptElements::IdentifierExpression>(statement->identifierToken);
+ label->setName(statement->label);
+ current->insertChild(Fields::label, ScriptElementVariant::fromElement(label));
+
+
+ if (statement->statement) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::statement, currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::BreakStatement *)
+{
+ return m_enableScriptExpressions;
+}
+
+void QQmlDomAstCreator::endVisit(AST::BreakStatement *statement)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeGenericScriptElement(statement, DomType::ScriptBreakStatement);
+ current->addLocation(FileLocationRegion::BreakKeywordRegion, statement->breakToken);
+
+ if (!statement->label.isEmpty()) {
+ auto label =
+ std::make_shared<ScriptElements::IdentifierExpression>(statement->identifierToken);
+ label->setName(statement->label);
+ current->insertChild(Fields::label, ScriptElementVariant::fromElement(label));
+ }
+
+ pushScriptElement(current);
+}
+
+// note: thats for comma expressions
+bool QQmlDomAstCreator::visit(AST::Expression *)
+{
+ return m_enableScriptExpressions;
+}
+
+// note: thats for comma expressions
+void QQmlDomAstCreator::endVisit(AST::Expression *commaExpression)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeScriptElement<ScriptElements::BinaryExpression>(commaExpression);
+ current->addLocation(OperatorTokenRegion, commaExpression->commaToken);
+
+ if (commaExpression->right) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->setRight(currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ if (commaExpression->left) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->setLeft(currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::ConditionalExpression *)
+{
+ return m_enableScriptExpressions;
+}
+
+void QQmlDomAstCreator::endVisit(AST::ConditionalExpression *expression)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeGenericScriptElement(expression, DomType::ScriptConditionalExpression);
+ current->addLocation(FileLocationRegion::QuestionMarkTokenRegion, expression->questionToken);
+ current->addLocation(FileLocationRegion::ColonTokenRegion, expression->colonToken);
+
+ if (expression->ko) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::alternative, currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ if (expression->ok) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::consequence, currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ if (expression->expression) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::condition, currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::ContinueStatement *)
+{
+ return m_enableScriptExpressions;
+}
+
+void QQmlDomAstCreator::endVisit(AST::ContinueStatement *statement)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeGenericScriptElement(statement, DomType::ScriptContinueStatement);
+ current->addLocation(FileLocationRegion::ContinueKeywordRegion, statement->continueToken);
+
+ if (!statement->label.isEmpty()) {
+ auto label =
+ std::make_shared<ScriptElements::IdentifierExpression>(statement->identifierToken);
+ label->setName(statement->label);
+ current->insertChild(Fields::label, ScriptElementVariant::fromElement(label));
+ }
+
+ pushScriptElement(current);
+}
+
+/*!
+ \internal
+ Helper to create unary expressions from AST nodes.
+ \sa makeGenericScriptElement
+ */
+std::shared_ptr<ScriptElements::GenericScriptElement>
+QQmlDomAstCreator::makeUnaryExpression(AST::Node *expression, QQmlJS::SourceLocation operatorToken,
+ bool hasExpression, UnaryExpressionKind kind)
+{
+ const DomType type = [&kind]() {
+ switch (kind) {
+ case Prefix:
+ return DomType::ScriptUnaryExpression;
+ case Postfix:
+ return DomType::ScriptPostExpression;
+ }
+ Q_UNREACHABLE_RETURN(DomType::ScriptUnaryExpression);
+ }();
+
+ auto current = makeGenericScriptElement(expression, type);
+ current->addLocation(FileLocationRegion::OperatorTokenRegion, operatorToken);
+
+ if (hasExpression) {
+ if (!stackHasScriptVariant()) {
+ Q_SCRIPTELEMENT_DISABLE();
+ return {};
+ }
+ current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ return current;
+}
+
+bool QQmlDomAstCreator::visit(AST::UnaryMinusExpression *)
+{
+ return m_enableScriptExpressions;
+}
+
+void QQmlDomAstCreator::endVisit(AST::UnaryMinusExpression *statement)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current =
+ makeUnaryExpression(statement, statement->minusToken, statement->expression, Prefix);
+ if (!current)
+ return;
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::UnaryPlusExpression *)
+{
+ return m_enableScriptExpressions;
+}
+
+void QQmlDomAstCreator::endVisit(AST::UnaryPlusExpression *statement)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current =
+ makeUnaryExpression(statement, statement->plusToken, statement->expression, Prefix);
+ if (!current)
+ return;
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::TildeExpression *)
+{
+ return m_enableScriptExpressions;
+}
+
+void QQmlDomAstCreator::endVisit(AST::TildeExpression *statement)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current =
+ makeUnaryExpression(statement, statement->tildeToken, statement->expression, Prefix);
+ if (!current)
+ return;
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::NotExpression *)
+{
+ return m_enableScriptExpressions;
+}
+
+void QQmlDomAstCreator::endVisit(AST::NotExpression *statement)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current =
+ makeUnaryExpression(statement, statement->notToken, statement->expression, Prefix);
+ if (!current)
+ return;
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::TypeOfExpression *)
+{
+ return m_enableScriptExpressions;
+}
+
+void QQmlDomAstCreator::endVisit(AST::TypeOfExpression *statement)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current =
+ makeUnaryExpression(statement, statement->typeofToken, statement->expression, Prefix);
+ if (!current)
+ return;
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::DeleteExpression *)
+{
+ return m_enableScriptExpressions;
+}
+
+void QQmlDomAstCreator::endVisit(AST::DeleteExpression *statement)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current =
+ makeUnaryExpression(statement, statement->deleteToken, statement->expression, Prefix);
+ if (!current)
+ return;
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::VoidExpression *)
+{
+ return m_enableScriptExpressions;
+}
+
+void QQmlDomAstCreator::endVisit(AST::VoidExpression *statement)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current =
+ makeUnaryExpression(statement, statement->voidToken, statement->expression, Prefix);
+ if (!current)
+ return;
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::PostDecrementExpression *)
+{
+ return m_enableScriptExpressions;
+}
+
+void QQmlDomAstCreator::endVisit(AST::PostDecrementExpression *statement)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current =
+ makeUnaryExpression(statement, statement->decrementToken, statement->base, Postfix);
+ if (!current)
+ return;
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::PostIncrementExpression *)
+{
+ return m_enableScriptExpressions;
+}
+
+void QQmlDomAstCreator::endVisit(AST::PostIncrementExpression *statement)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current =
+ makeUnaryExpression(statement, statement->incrementToken, statement->base, Postfix);
+ if (!current)
+ return;
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::PreIncrementExpression *)
+{
+ return m_enableScriptExpressions;
+}
+
+void QQmlDomAstCreator::endVisit(AST::PreIncrementExpression *statement)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeUnaryExpression(statement, statement->incrementToken, statement->expression,
+ Prefix);
+ if (!current)
+ return;
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::EmptyStatement *)
+{
+ return m_enableScriptExpressions;
+}
+
+void QQmlDomAstCreator::endVisit(AST::EmptyStatement *statement)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeGenericScriptElement(statement, DomType::ScriptEmptyStatement);
+ current->addLocation(FileLocationRegion::SemicolonTokenRegion, statement->semicolonToken);
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::NestedExpression *)
+{
+ return m_enableScriptExpressions;
+}
+
+void QQmlDomAstCreator::endVisit(AST::NestedExpression *expression)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeGenericScriptElement(expression, DomType::ScriptParenthesizedExpression);
+ current->addLocation(FileLocationRegion::LeftParenthesisRegion, expression->lparenToken);
+ current->addLocation(FileLocationRegion::RightParenthesisRegion, expression->rparenToken);
+
+ if (expression->expression) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
}
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::PreDecrementExpression *)
+{
+ return m_enableScriptExpressions;
+}
+
+void QQmlDomAstCreator::endVisit(AST::PreDecrementExpression *statement)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeUnaryExpression(statement, statement->decrementToken, statement->expression,
+ Prefix);
+ if (!current)
+ return;
+
+ pushScriptElement(current);
+}
+
+static const DomEnvironment *environmentFrom(MutableDomItem &qmlFile)
+{
+ auto top = qmlFile.top();
+ if (!top) {
+ return {};
+ }
+ auto domEnvironment = top.as<DomEnvironment>();
+ if (!domEnvironment) {
+ return {};
+ }
+ return domEnvironment;
+}
+
+static QStringList qmldirFilesFrom(MutableDomItem &qmlFile)
+{
+ if (auto env = environmentFrom(qmlFile))
+ return env->qmldirFiles();
+
+ return {};
+}
+
+QQmlDomAstCreatorWithQQmlJSScope::QQmlDomAstCreatorWithQQmlJSScope(const QQmlJSScope::Ptr &current,
+ MutableDomItem &qmlFile,
+ QQmlJSLogger *logger,
+ QQmlJSImporter *importer)
+ : m_root(current),
+ m_logger(logger),
+ m_importer(importer),
+ m_implicitImportDirectory(QQmlJSImportVisitor::implicitImportDirectory(
+ m_logger->fileName(), m_importer->resourceFileMapper())),
+ m_scopeCreator(m_root, m_importer, m_logger, m_implicitImportDirectory,
+ qmldirFilesFrom(qmlFile)),
+ m_domCreator(qmlFile)
+{
+}
+
+#define X(name) \
+ bool QQmlDomAstCreatorWithQQmlJSScope::visit(name *node) \
+ { \
+ return visitT(node); \
+ } \
+ void QQmlDomAstCreatorWithQQmlJSScope::endVisit(name *node) \
+ { \
+ endVisitT(node); \
+ }
+QQmlJSASTClassListToVisit
+#undef X
+
+void QQmlDomAstCreatorWithQQmlJSScope::setScopeInDomAfterEndvisit()
+{
+ const QQmlJSScope::ConstPtr scope = m_scopeCreator.m_currentScope;
+ if (!m_domCreator.scriptNodeStack.isEmpty()) {
+ auto topOfStack = m_domCreator.currentScriptNodeEl();
+ switch (topOfStack.kind) {
+ case DomType::ScriptBlockStatement:
+ case DomType::ScriptForStatement:
+ case DomType::ScriptForEachStatement:
+ case DomType::ScriptDoWhileStatement:
+ case DomType::ScriptWhileStatement:
+ case DomType::List:
+ m_domCreator.currentScriptNodeEl().setSemanticScope(scope);
+ break;
+ case DomType::ScriptFunctionExpression: {
+ // Put the body's scope into the function expression: function expressions will contain
+ // their parents scope instead of their own without this
+ auto element = m_domCreator.currentScriptNodeEl().value;
+ auto scriptElementVariant = std::get_if<ScriptElementVariant>(&element);
+ if (!scriptElementVariant || !scriptElementVariant->data())
+ break;
+ scriptElementVariant->visit([](auto &&e) {
+ using U = std::remove_cv_t<std::remove_reference_t<decltype(e)>>;
+ if (e->kind() != DomType::ScriptFunctionExpression)
+ return;
+
+ if constexpr (std::is_same_v<U,
+ ScriptElement::PointerType<
+ ScriptElements::GenericScriptElement>>) {
+ if (auto bodyPtr = e->elementChild(Fields::body)) {
+ const auto bodyScope = bodyPtr.base()->semanticScope();
+ e->setSemanticScope(bodyScope);
+ }
+ }
+ });
+ break;
+ }
+
+ // TODO: find which script elements also have a scope and implement them here
+ default:
+ break;
+ };
+ } else if (!m_domCreator.nodeStack.isEmpty()) {
+ std::visit(
+ [&scope](auto &&e) {
+ using U = std::remove_cv_t<std::remove_reference_t<decltype(e)>>;
+ // TODO: find which dom elements also have a scope and implement them here
+ if constexpr (std::is_same_v<U, QmlObject>) {
+ e.setSemanticScope(scope);
+ } else if constexpr (std::is_same_v<U, QmlComponent>) {
+ e.setSemanticScope(scope);
+ } else if constexpr (std::is_same_v<U, MethodInfo>) {
+ if (e.body) {
+ if (auto scriptElement = e.body->scriptElement()) {
+ scriptElement.base()->setSemanticScope(scope);
+ }
+ }
+ e.setSemanticScope(scope);
+ }
+ },
+ m_domCreator.currentNodeEl().item.value);
+ }
+}
+
+void QQmlDomAstCreatorWithQQmlJSScope::setScopeInDomBeforeEndvisit()
+{
+ const QQmlJSScope::ConstPtr scope = m_scopeCreator.m_currentScope;
+
+ // depending whether the property definition has a binding, the property definition might be
+ // either at the last position in the stack or at the position before the last position.
+ if (m_domCreator.nodeStack.size() > 1
+ && m_domCreator.nodeStack.last().item.kind == DomType::Binding) {
+ std::visit(
+ [&scope](auto &&e) {
+ using U = std::remove_cv_t<std::remove_reference_t<decltype(e)>>;
+ if constexpr (std::is_same_v<U, PropertyDefinition>) {
+ // Make sure to use the property definition scope instead of the binding
+ // scope. If the current scope is a binding scope (this happens when the
+ // property definition has a binding, like `property int i: 45` for
+ // example), then the property definition scope is the parent of the current
+ // scope.
+ const bool usePropertyDefinitionScopeInsteadOfTheBindingScope =
+ scope->scopeType() == QQmlSA::ScopeType::JSFunctionScope
+ && scope->parentScope()
+ && scope->parentScope()->scopeType() == QQmlSA::ScopeType::QMLScope;
+ e.setSemanticScope(usePropertyDefinitionScopeInsteadOfTheBindingScope
+ ? scope->parentScope()
+ : scope);
+ }
+ },
+ m_domCreator.currentNodeEl(1).item.value);
+ }
+ if (m_domCreator.nodeStack.size() > 0) {
+ std::visit(
+ [&scope](auto &&e) {
+ using U = std::remove_cv_t<std::remove_reference_t<decltype(e)>>;
+ if constexpr (std::is_same_v<U, PropertyDefinition>) {
+ e.setSemanticScope(scope);
+ Q_ASSERT(e.semanticScope());
+ } else if constexpr (std::is_same_v<U, MethodInfo>) {
+ if (e.methodType == MethodInfo::Signal) {
+ e.setSemanticScope(scope);
+ }
+ }
+ },
+ m_domCreator.currentNodeEl().item.value);
+ }
+}
+
+void QQmlDomAstCreatorWithQQmlJSScope::throwRecursionDepthError()
+{
}
} // end namespace Dom
} // end namespace QQmlJS
+
+#undef Q_SCRIPTELEMENT_DISABLE
+#undef Q_SCRIPTELEMENT_EXIT_IF
+
QT_END_NAMESPACE
diff --git a/src/qmldom/qqmldomastcreator_p.h b/src/qmldom/qqmldomastcreator_p.h
index 528304b83f..8a050b4c2d 100644
--- a/src/qmldom/qqmldomastcreator_p.h
+++ b/src/qmldom/qqmldomastcreator_p.h
@@ -15,22 +15,728 @@
// We mean it.
//
-#include "qqmldom_global.h"
+#include "qqmldomelements_p.h"
#include "qqmldomitem_p.h"
-#include "qqmldomastcreator_p.h"
-#include "qqmldomcomments_p.h"
+#include "qqmldompath_p.h"
+#include "qqmldomscriptelements_p.h"
+
+#include <QtQmlCompiler/private/qqmljsimportvisitor_p.h>
#include <QtQml/private/qqmljsastvisitor_p.h>
+#include <memory>
+#include <type_traits>
+#include <variant>
QT_BEGIN_NAMESPACE
namespace QQmlJS {
namespace Dom {
-SourceLocation combineLocations(SourceLocation s1, SourceLocation s2);
-SourceLocation combineLocations(AST::Node *n);
+class QQmlDomAstCreator final : public AST::Visitor
+{
+ Q_DECLARE_TR_FUNCTIONS(QQmlDomAstCreator)
+ using AST::Visitor::endVisit;
+ using AST::Visitor::visit;
+
+ static constexpr const auto className = "QmlDomAstCreator";
+
+ class DomValue
+ {
+ public:
+ template<typename T>
+ DomValue(const T &obj) : kind(T::kindValue), value(obj)
+ {
+ }
+ DomType kind;
+ std::variant<QmlObject, MethodInfo, QmlComponent, PropertyDefinition, Binding, EnumDecl,
+ EnumItem, ConstantData, Id>
+ value;
+ };
+
+ class QmlStackElement
+ {
+ public:
+ Path path;
+ DomValue item;
+ FileLocations::Tree fileLocations;
+ };
+
+ /*!
+ \internal
+ Contains a ScriptElementVariant, that can be used everywhere in the DOM representation, or a
+ List that should always be inside of something else, e.g., that cannot be the root of the
+ script element DOM representation.
+
+ Also, it makes sure you do not mistreat a list as a regular script element and vice versa.
+
+ The reason for this is that Lists can get pretty unintuitive, as a List could be a Block of
+ statements or a list of variable declarations (let i = 3, j = 4, ...) or something completely
+ different. Instead, always put lists inside named construct (BlockStatement,
+ VariableDeclaration, ...).
+ */
+ class ScriptStackElement
+ {
+ public:
+ template<typename T>
+ static ScriptStackElement from(const T &obj)
+ {
+ if constexpr (std::is_same_v<T, ScriptElements::ScriptList>) {
+ ScriptStackElement s{ ScriptElements::ScriptList::kindValue, obj };
+ return s;
+ } else {
+ ScriptStackElement s{ obj->kind(), ScriptElementVariant::fromElement(obj) };
+ return s;
+ }
+ Q_UNREACHABLE();
+ }
+
+ DomType kind;
+ using Variant = std::variant<ScriptElementVariant, ScriptElements::ScriptList>;
+ Variant value;
+
+ ScriptElementVariant takeVariant()
+ {
+ Q_ASSERT_X(std::holds_alternative<ScriptElementVariant>(value), "takeVariant",
+ "Should be a variant, did the parser change?");
+ return std::get<ScriptElementVariant>(std::move(value));
+ }
+
+ bool isList() const { return std::holds_alternative<ScriptElements::ScriptList>(value); };
+
+ ScriptElements::ScriptList takeList()
+ {
+ Q_ASSERT_X(std::holds_alternative<ScriptElements::ScriptList>(value), "takeList",
+ "Should be a List, did the parser change?");
+ return std::get<ScriptElements::ScriptList>(std::move(value));
+ }
+
+ void setSemanticScope(const QQmlJSScope::ConstPtr &scope)
+ {
+ if (auto x = std::get_if<ScriptElementVariant>(&value)) {
+ x->base()->setSemanticScope(scope);
+ return;
+ } else if (auto x = std::get_if<ScriptElements::ScriptList>(&value)) {
+ x->setSemanticScope(scope);
+ return;
+ }
+ Q_UNREACHABLE();
+ }
+ };
+
+public:
+ void enableScriptExpressions(bool enable = true) { m_enableScriptExpressions = enable; }
+ void enableLoadFileLazily(bool enable = true) { m_loadFileLazily = enable; }
+
+private:
+
+ MutableDomItem qmlFile;
+ std::shared_ptr<QmlFile> qmlFilePtr;
+ QVector<QmlStackElement> nodeStack;
+ QList<ScriptStackElement> scriptNodeStack;
+ QVector<int> arrayBindingLevels;
+ FileLocations::Tree rootMap;
+ int m_nestedFunctionDepth = 0;
+ bool m_enableScriptExpressions = false;
+ bool m_loadFileLazily = false;
+
+ // A Binding inside a UiPublicMember (= a Property definition) will shadow the
+ // propertydefinition's binding identifiers with its own binding identifiers. Therefore, disable
+ // bindingIdentifiers for the Binding inside a Property definition by using this flag.
+ bool m_skipBindingIdentifiers = false;
+
+ void setBindingIdentifiers(const Path &pathFromOwner, const AST::UiQualifiedId *identifiers,
+ Binding *bindingPtr);
+ template<typename T>
+ QmlStackElement &currentEl(int idx = 0)
+ {
+ Q_ASSERT_X(idx < nodeStack.size() && idx >= 0, "currentQmlObjectOrComponentEl",
+ "Stack does not contain enough elements!");
+ int i = nodeStack.size() - idx;
+ while (i-- > 0) {
+ DomType k = nodeStack.at(i).item.kind;
+ if (k == T::kindValue)
+ return nodeStack[i];
+ }
+ Q_ASSERT_X(false, "currentEl", "Stack does not contan object of type ");
+ return nodeStack.last();
+ }
+
+ template<typename T>
+ ScriptStackElement &currentScriptEl(int idx = 0)
+ {
+ Q_ASSERT_X(m_enableScriptExpressions, "currentScriptEl",
+ "Cannot access script elements when they are disabled!");
+
+ Q_ASSERT_X(idx < scriptNodeStack.size() && idx >= 0, "currentQmlObjectOrComponentEl",
+ "Stack does not contain enough elements!");
+ int i = scriptNodeStack.size() - idx;
+ while (i-- > 0) {
+ DomType k = scriptNodeStack.at(i).kind;
+ if (k == T::element_type::kindValue)
+ return scriptNodeStack[i];
+ }
+ Q_ASSERT_X(false, "currentEl", "Stack does not contain object of type ");
+ return scriptNodeStack.last();
+ }
+
+ template<typename T>
+ T &current(int idx = 0)
+ {
+ return std::get<T>(currentEl<T>(idx).item.value);
+ }
+
+ index_type currentIndex() { return currentNodeEl().path.last().headIndex(); }
+
+ QmlStackElement &currentQmlObjectOrComponentEl(int idx = 0);
+
+ QmlStackElement &currentNodeEl(int i = 0);
+ ScriptStackElement &currentScriptNodeEl(int i = 0);
+
+ DomValue &currentNode(int i = 0);
+
+ void removeCurrentNode(std::optional<DomType> expectedType);
+ void removeCurrentScriptNode(std::optional<DomType> expectedType);
+
+ void pushEl(const Path &p, const DomValue &it, AST::Node *n)
+ {
+ nodeStack.append({ p, it, createMap(it.kind, p, n) });
+ }
+
+ FileLocations::Tree createMap(const FileLocations::Tree &base, const Path &p, AST::Node *n);
+
+ FileLocations::Tree createMap(DomType k, const Path &p, AST::Node *n);
+
+ const ScriptElementVariant &
+ finalizeScriptExpression(const ScriptElementVariant &element, const Path &pathFromOwner,
+ const FileLocations::Tree &ownerFileLocations);
+
+ void setScriptExpression (const std::shared_ptr<ScriptExpression>& value);
+
+ Path pathOfLastScriptNode() const;
+
+ /*!
+ \internal
+ Helper to create string literals from AST nodes.
+ */
+ template<typename AstNodeT>
+ static std::shared_ptr<ScriptElements::Literal> makeStringLiteral(QStringView value,
+ AstNodeT *ast)
+ {
+ auto myExp = std::make_shared<ScriptElements::Literal>(ast->firstSourceLocation(),
+ ast->lastSourceLocation());
+ myExp->setLiteralValue(value.toString());
+ return myExp;
+ }
+
+ static std::shared_ptr<ScriptElements::Literal> makeStringLiteral(QStringView value,
+ QQmlJS::SourceLocation loc)
+ {
+ auto myExp = std::make_shared<ScriptElements::Literal>(loc);
+ myExp->setLiteralValue(value.toString());
+ return myExp;
+ }
+
+ /*!
+ \internal
+ Helper to create script elements from AST nodes, as the DOM classes should be completely
+ dependency-free from AST and parser classes. Using the AST classes in qqmldomastcreator is
+ fine because it needs them for the construction/visit. \sa makeScriptList
+ */
+ template<typename ScriptElementT, typename AstNodeT,
+ typename Enable =
+ std::enable_if_t<!std::is_same_v<ScriptElementT, ScriptElements::ScriptList>>>
+ static decltype(auto) makeScriptElement(AstNodeT *ast)
+ {
+ auto myExp = std::make_shared<ScriptElementT>(ast->firstSourceLocation(),
+ ast->lastSourceLocation());
+ return myExp;
+ }
+
+ /*!
+ \internal
+ Helper to create generic script elements from AST nodes.
+ \sa makeScriptElement
+ */
+ template<typename AstNodeT>
+ static std::shared_ptr<ScriptElements::GenericScriptElement>
+ makeGenericScriptElement(AstNodeT *ast, DomType kind)
+ {
+ auto myExp = std::make_shared<ScriptElements::GenericScriptElement>(
+ ast->firstSourceLocation(), ast->lastSourceLocation());
+ myExp->setKind(kind);
+ return myExp;
+ }
+
+ enum UnaryExpressionKind { Prefix, Postfix };
+ std::shared_ptr<ScriptElements::GenericScriptElement>
+ makeUnaryExpression(AST::Node *expression, QQmlJS::SourceLocation operatorToken,
+ bool hasExpression, UnaryExpressionKind type);
+
+ static std::shared_ptr<ScriptElements::GenericScriptElement>
+ makeGenericScriptElement(SourceLocation location, DomType kind)
+ {
+ auto myExp = std::make_shared<ScriptElements::GenericScriptElement>(location);
+ myExp->setKind(kind);
+ return myExp;
+ }
+
+ /*!
+ \internal
+ Helper to create script lists from AST nodes.
+ \sa makeScriptElement
+ */
+ template<typename AstNodeT>
+ static decltype(auto) makeScriptList(AstNodeT *ast)
+ {
+ auto myExp =
+ ScriptElements::ScriptList(ast->firstSourceLocation(), ast->lastSourceLocation());
+ return myExp;
+ }
+
+ template<typename ScriptElementT>
+ void pushScriptElement(const ScriptElementT &element)
+ {
+ Q_ASSERT_X(m_enableScriptExpressions, "pushScriptElement",
+ "Cannot create script elements when they are disabled!");
+ scriptNodeStack.append(ScriptStackElement::from(element));
+ }
+
+ void disableScriptElements()
+ {
+ m_enableScriptExpressions = false;
+ scriptNodeStack.clear();
+ }
+
+ ScriptElementVariant scriptElementForQualifiedId(AST::UiQualifiedId *expression);
+
+public:
+ explicit QQmlDomAstCreator(const MutableDomItem &qmlFile);
+
+ bool visit(AST::UiProgram *program) override;
+ void endVisit(AST::UiProgram *) override;
+
+ bool visit(AST::UiPragma *el) override;
+
+ bool visit(AST::UiImport *el) override;
+
+ bool visit(AST::UiPublicMember *el) override;
+ void endVisit(AST::UiPublicMember *el) override;
+
+private:
+ ScriptElementVariant prepareBodyForFunction(AST::FunctionExpression *fExpression);
+
+public:
+ bool visit(AST::FunctionExpression *el) override;
+ void endVisit(AST::FunctionExpression *) override;
+
+ bool visit(AST::FunctionDeclaration *el) override;
+ void endVisit(AST::FunctionDeclaration *) override;
+
+ bool visit(AST::UiSourceElement *el) override;
+ void endVisit(AST::UiSourceElement *) override;
+
+ void loadAnnotations(AST::UiObjectMember *el) { AST::Node::accept(el->annotations, this); }
+
+ bool visit(AST::UiObjectDefinition *el) override;
+ void endVisit(AST::UiObjectDefinition *) override;
+
+ bool visit(AST::UiObjectBinding *el) override;
+ void endVisit(AST::UiObjectBinding *) override;
+
+ bool visit(AST::UiScriptBinding *el) override;
+ void endVisit(AST::UiScriptBinding *) override;
+
+ bool visit(AST::UiArrayBinding *el) override;
+ void endVisit(AST::UiArrayBinding *) override;
+
+ bool visit(AST::UiQualifiedId *) override;
+
+ bool visit(AST::UiEnumDeclaration *el) override;
+ void endVisit(AST::UiEnumDeclaration *) override;
+
+ bool visit(AST::UiEnumMemberList *el) override;
+ void endVisit(AST::UiEnumMemberList *el) override;
+
+ bool visit(AST::UiInlineComponent *el) override;
+ void endVisit(AST::UiInlineComponent *) override;
+
+ bool visit(AST::UiRequired *el) override;
+
+ bool visit(AST::UiAnnotation *el) override;
+ void endVisit(AST::UiAnnotation *) override;
+
+ // for Script elements:
+ bool visit(AST::BinaryExpression *exp) override;
+ void endVisit(AST::BinaryExpression *exp) override;
+
+ bool visit(AST::Block *block) override;
+ void endVisit(AST::Block *) override;
+
+ bool visit(AST::YieldExpression *block) override;
+ void endVisit(AST::YieldExpression *) override;
+
+ bool visit(AST::ReturnStatement *block) override;
+ void endVisit(AST::ReturnStatement *) override;
+
+ bool visit(AST::ForStatement *forStatement) override;
+ void endVisit(AST::ForStatement *forStatement) override;
+
+ bool visit(AST::PatternElement *pe) override;
+ void endVisit(AST::PatternElement *pe) override;
+ void endVisitHelper(AST::PatternElement *pe,
+ const std::shared_ptr<ScriptElements::GenericScriptElement> &element);
+
+ bool visit(AST::IfStatement *) override;
+ void endVisit(AST::IfStatement *) override;
+
+ bool visit(AST::FieldMemberExpression *) override;
+ void endVisit(AST::FieldMemberExpression *) override;
+
+ bool visit(AST::ArrayMemberExpression *) override;
+ void endVisit(AST::ArrayMemberExpression *) override;
+
+ bool visit(AST::CallExpression *) override;
+ void endVisit(AST::CallExpression *) override;
+
+ bool visit(AST::ArrayPattern *) override;
+ void endVisit(AST::ArrayPattern *) override;
+
+ bool visit(AST::ObjectPattern *) override;
+ void endVisit(AST::ObjectPattern *) override;
+
+ bool visit(AST::PatternProperty *) override;
+ void endVisit(AST::PatternProperty *) override;
+
+ bool visit(AST::VariableStatement *) override;
+ void endVisit(AST::VariableStatement *) override;
+
+ bool visit(AST::Type *expression) override;
+ void endVisit(AST::Type *expression) override;
+
+ bool visit(AST::DefaultClause *) override;
+ void endVisit(AST::DefaultClause *) override;
+
+ bool visit(AST::CaseClause *) override;
+ void endVisit(AST::CaseClause *) override;
+
+ bool visit(AST::CaseClauses *) override;
+ void endVisit(AST::CaseClauses *) override;
+
+ bool visit(AST::CaseBlock *) override;
+ void endVisit(AST::CaseBlock *) override;
+
+ bool visit(AST::SwitchStatement *) override;
+ void endVisit(AST::SwitchStatement *) override;
+
+ bool visit(AST::WhileStatement *) override;
+ void endVisit(AST::WhileStatement *) override;
+
+ bool visit(AST::DoWhileStatement *) override;
+ void endVisit(AST::DoWhileStatement *) override;
+
+ bool visit(AST::ForEachStatement *) override;
+ void endVisit(AST::ForEachStatement *) override;
+
+ bool visit(AST::ClassExpression *) override;
+ void endVisit(AST::ClassExpression *) override;
+
+ bool visit(AST::TemplateLiteral *) override;
+
+ bool visit(AST::TryStatement *) override;
+ void endVisit(AST::TryStatement *) override;
+
+ bool visit(AST::Catch *) override;
+ void endVisit(AST::Catch *) override;
+
+ bool visit(AST::Finally *) override;
+ void endVisit(AST::Finally *) override;
+
+ bool visit(AST::ThrowStatement *) override;
+ void endVisit(AST::ThrowStatement *) override;
+
+ bool visit(AST::LabelledStatement *) override;
+ void endVisit(AST::LabelledStatement *) override;
+
+ bool visit(AST::ContinueStatement *) override;
+ void endVisit(AST::ContinueStatement *) override;
+
+ bool visit(AST::BreakStatement *) override;
+ void endVisit(AST::BreakStatement *) override;
+
+ bool visit(AST::Expression *) override;
+ void endVisit(AST::Expression *) override;
+
+ bool visit(AST::ConditionalExpression *) override;
+ void endVisit(AST::ConditionalExpression *) override;
+
+ bool visit(AST::UnaryMinusExpression *) override;
+ void endVisit(AST::UnaryMinusExpression *) override;
+
+ bool visit(AST::UnaryPlusExpression *) override;
+ void endVisit(AST::UnaryPlusExpression *) override;
+
+ bool visit(AST::TildeExpression *) override;
+ void endVisit(AST::TildeExpression *) override;
+
+ bool visit(AST::NotExpression *) override;
+ void endVisit(AST::NotExpression *) override;
+
+ bool visit(AST::TypeOfExpression *) override;
+ void endVisit(AST::TypeOfExpression *) override;
+
+ bool visit(AST::DeleteExpression *) override;
+ void endVisit(AST::DeleteExpression *) override;
+
+ bool visit(AST::VoidExpression *) override;
+ void endVisit(AST::VoidExpression *) override;
+
+ bool visit(AST::PostDecrementExpression *) override;
+ void endVisit(AST::PostDecrementExpression *) override;
+
+ bool visit(AST::PostIncrementExpression *) override;
+ void endVisit(AST::PostIncrementExpression *) override;
+
+ bool visit(AST::PreDecrementExpression *) override;
+ void endVisit(AST::PreDecrementExpression *) override;
+
+ bool visit(AST::PreIncrementExpression *) override;
+ void endVisit(AST::PreIncrementExpression *) override;
+
+ bool visit(AST::EmptyStatement *) override;
+ void endVisit(AST::EmptyStatement *) override;
+
+ bool visit(AST::NestedExpression *) override;
+ void endVisit(AST::NestedExpression *) override;
+
+
+ // lists of stuff whose children don't need a qqmljsscope: visitation order can be custom
+ bool visit(AST::UiParameterList *) override;
+ bool visit(AST::Elision *elision) override;
+
+
+ // lists of stuff whose children need a qqmljsscope: visitation order cannot be custom
+ void endVisit(AST::StatementList *list) override;
+ void endVisit(AST::VariableDeclarationList *vdl) override;
+ void endVisit(AST::ArgumentList *) override;
+ void endVisit(AST::PatternElementList *) override;
+ void endVisit(AST::PatternPropertyList *) override;
+ void endVisit(AST::FormalParameterList *el) override;
+
+
+ // literals and ids
+ bool visit(AST::IdentifierExpression *expression) override;
+ bool visit(AST::NumericLiteral *expression) override;
+ bool visit(AST::StringLiteral *expression) override;
+ bool visit(AST::NullExpression *expression) override;
+ bool visit(AST::TrueLiteral *expression) override;
+ bool visit(AST::FalseLiteral *expression) override;
+ bool visit(AST::ComputedPropertyName *expression) override;
+ bool visit(AST::IdentifierPropertyName *expression) override;
+ bool visit(AST::NumericLiteralPropertyName *expression) override;
+ bool visit(AST::StringLiteralPropertyName *expression) override;
+ bool visit(AST::TypeAnnotation *expression) override;
+
+ void throwRecursionDepthError() override;
+
+ bool stackHasScriptVariant() const
+ {
+ return !scriptNodeStack.isEmpty() && !scriptNodeStack.last().isList();
+ }
+ bool stackHasScriptList() const
+ {
+ return !scriptNodeStack.isEmpty() && scriptNodeStack.last().isList();
+ }
+
+private:
+ template<typename T>
+ void endVisitForLists(T *list, const std::function<int(T *)> &scriptElementsPerEntry = {});
+
+public:
+ friend class QQmlDomAstCreatorWithQQmlJSScope;
+};
+
+class QQmlDomAstCreatorWithQQmlJSScope : public AST::Visitor
+{
+public:
+ QQmlDomAstCreatorWithQQmlJSScope(const QQmlJSScope::Ptr &current, MutableDomItem &qmlFile,
+ QQmlJSLogger *logger, QQmlJSImporter *importer);
+
+#define X(name) \
+ bool visit(AST::name *) override; \
+ void endVisit(AST::name *) override;
+ QQmlJSASTClassListToVisit
+#undef X
+
+ virtual void throwRecursionDepthError() override;
+ /*!
+ \internal
+ Disable the DOM for scriptexpressions, as not yet unimplemented script elements might crash
+ the construction.
+ */
+ void enableScriptExpressions(bool enable = true)
+ {
+ m_enableScriptExpressions = enable;
+ m_domCreator.enableScriptExpressions(enable);
+ }
+
+ void enableLoadFileLazily(bool enable = true)
+ {
+ m_loadFileLazily = enable;
+ m_domCreator.enableLoadFileLazily(enable);
+ }
+
+ QQmlJSImportVisitor &scopeCreator() { return m_scopeCreator; }
+
+private:
+ void setScopeInDomAfterEndvisit();
+ void setScopeInDomBeforeEndvisit();
+
+ template<typename U, typename... V>
+ using IsInList = std::disjunction<std::is_same<U, V>...>;
+ template<typename U>
+ using RequiresCustomIteration =
+ IsInList<U, AST::PatternElementList, AST::PatternPropertyList, AST::FormalParameterList,
+ AST::VariableDeclarationList>;
+
+ enum VisitorKind : bool { DomCreator, ScopeCreator };
+ /*! \internal
+ \brief Holds the information to reactivate a visitor
+ This struct tracks a visitor during its inactive phases
+ and holds the information needed to reactivate the visitor.
+ */
+ struct InactiveVisitorMarker
+ {
+ qsizetype count;
+ AST::Node::Kind nodeKind;
+ VisitorKind inactiveVisitorKind;
+
+ VisitorKind stillActiveVisitorKind() const
+ {
+ return inactiveVisitorKind == DomCreator ? ScopeCreator : DomCreator;
+ }
+ };
+
+ template<typename T>
+ void customListIteration(T *t)
+ {
+ static_assert(RequiresCustomIteration<T>::value);
+ for (T* it = t; it; it = it->next) {
+ if constexpr (std::is_same_v<T, AST::PatternElementList>) {
+ AST::Node::accept(it->elision, this);
+ AST::Node::accept(it->element, this);
+ } else if constexpr (std::is_same_v<T, AST::PatternPropertyList>) {
+ AST::Node::accept(it->property, this);
+ } else if constexpr (std::is_same_v<T, AST::FormalParameterList>) {
+ AST::Node::accept(it->element, this);
+ } else if constexpr (std::is_same_v<T, AST::VariableDeclarationList>) {
+ AST::Node::accept(it->declaration, this);
+ } else if constexpr (std::is_same_v<T, AST::ArgumentList>) {
+ AST::Node::accept(it->expression, this);
+ } else if constexpr (std::is_same_v<T, AST::PatternElementList>) {
+ AST::Node::accept(it->elision, this);
+ AST::Node::accept(it->element, this);
+ } else {
+ Q_UNREACHABLE();
+ }
+ }
+ }
+
+ static void initMarkerForActiveVisitor(std::optional<InactiveVisitorMarker> &inactiveVisitorMarker,
+ AST::Node::Kind nodeKind, bool continueForDom)
+ {
+ inactiveVisitorMarker.emplace();
+ inactiveVisitorMarker->inactiveVisitorKind = continueForDom ? ScopeCreator : DomCreator;
+ inactiveVisitorMarker->count = 1;
+ inactiveVisitorMarker->nodeKind = nodeKind;
+ };
+
+ template<typename T>
+ bool performListIterationIfRequired(T *t)
+ {
+ if constexpr (RequiresCustomIteration<T>::value) {
+ customListIteration(t);
+ return false;
+ }
+ Q_UNUSED(t);
+ return true;
+ }
+
+ template<typename T>
+ bool visitT(T *t)
+ {
+ const auto handleVisitResult = [this, t](const bool continueVisit) {
+ if (m_inactiveVisitorMarker && m_inactiveVisitorMarker->nodeKind == t->kind)
+ m_inactiveVisitorMarker->count += 1;
+
+ if (continueVisit)
+ return performListIterationIfRequired(t);
+ return continueVisit;
+ };
+
+ // first case: no marker, both can visit
+ if (!m_inactiveVisitorMarker) {
+ bool continueForDom = m_domCreator.visit(t);
+ bool continueForScope = m_scopeCreator.visit(t);
+ if (!continueForDom && !continueForScope)
+ return false;
+ else if (continueForDom ^ continueForScope) {
+ initMarkerForActiveVisitor(m_inactiveVisitorMarker, AST::Node::Kind(t->kind),
+ continueForDom);
+ return performListIterationIfRequired(t);
+ } else {
+ Q_ASSERT(continueForDom && continueForScope);
+ return performListIterationIfRequired(t);
+ }
+ Q_UNREACHABLE();
+ }
+
+ // second case: a marker, just one visit
+ switch (m_inactiveVisitorMarker->stillActiveVisitorKind()) {
+ case DomCreator:
+ return handleVisitResult(m_domCreator.visit(t));
+ case ScopeCreator:
+ return handleVisitResult(m_scopeCreator.visit(t));
+ };
+ Q_UNREACHABLE();
+ }
+
+ template<typename T>
+ void endVisitT(T *t)
+ {
+ if (m_inactiveVisitorMarker && m_inactiveVisitorMarker->nodeKind == t->kind) {
+ m_inactiveVisitorMarker->count -= 1;
+ if (m_inactiveVisitorMarker->count == 0)
+ m_inactiveVisitorMarker.reset();
+ }
+ if (m_inactiveVisitorMarker) {
+ switch (m_inactiveVisitorMarker->stillActiveVisitorKind()) {
+ case DomCreator:
+ m_domCreator.endVisit(t);
+ return;
+ case ScopeCreator:
+ m_scopeCreator.endVisit(t);
+ return;
+ };
+ Q_UNREACHABLE();
+ }
+
+ setScopeInDomBeforeEndvisit();
+ m_domCreator.endVisit(t);
+ setScopeInDomAfterEndvisit();
+ m_scopeCreator.endVisit(t);
+ }
+
+ QQmlJSScope::Ptr m_root;
+ QQmlJSLogger *m_logger = nullptr;
+ QQmlJSImporter *m_importer = nullptr;
+ QString m_implicitImportDirectory;
+ QQmlJSImportVisitor m_scopeCreator;
+ QQmlDomAstCreator m_domCreator;
-void createDom(MutableDomItem qmlFile);
+ std::optional<InactiveVisitorMarker> m_inactiveVisitorMarker;
+ bool m_enableScriptExpressions = false;
+ bool m_loadFileLazily = false;
+};
} // end namespace Dom
} // end namespace QQmlJS
diff --git a/src/qmldom/qqmldomastdumper.cpp b/src/qmldom/qqmldomastdumper.cpp
index ffb776cf2d..b4986f7a71 100644
--- a/src/qmldom/qqmldomastdumper.cpp
+++ b/src/qmldom/qqmldomastdumper.cpp
@@ -132,6 +132,14 @@ public:
bool visit(UiHeaderItemList *) override { start(u"UiHeaderItemList"); return true; }
void endVisit(AST::UiHeaderItemList *) override { stop(u"UiHeaderItemList"); }
+#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
+ bool visit(UiPragmaValueList *el) override {
+ start(QLatin1String("UiPragmaValueList value=%1").arg(el->value));
+ return true;
+ }
+ void endVisit(AST::UiPragmaValueList *) override { stop(u"UiPragmaValueList"); }
+#endif
+
bool visit(UiPragma *el) override {
start(QLatin1String("UiPragma name=%1 pragmaToken=%2%3")
.arg(quotedString(el->name), loc(el->pragmaToken),
@@ -330,7 +338,7 @@ public:
void endVisit(AST::ThisExpression *) override { stop(u"ThisExpression"); }
bool visit(AST::IdentifierExpression *el) override {
- start(QLatin1String("IdentifierExpression name=%1 identiferToken=%2")
+ start(QLatin1String("IdentifierExpression name=%1 identifierToken=%2")
.arg(quotedString(el->name), loc(el->identifierToken)));
return true;
}
@@ -982,12 +990,6 @@ public:
}
void endVisit(AST::Type *) override { stop(u"Type"); }
- bool visit(AST::TypeArgument *) override {
- start(u"TypeArgument");
- return true;
- }
- void endVisit(AST::TypeArgument *) override { stop(u"TypeArgument"); }
-
bool visit(AST::TypeAnnotation *el) override {
start(QLatin1String("TypeAnnotation colonToken=%1")
.arg(loc(el->colonToken)));
@@ -1082,7 +1084,7 @@ QString astNodeDiff(AST::Node *n1, AST::Node *n2, int nContext, AstDumperOptions
return lineDiff(s1, s2, nContext);
}
-void astNodeDumper(Sink s, Node *n, AstDumperOptions opt, int indent, int baseIndent,
+void astNodeDumper(const Sink &s, Node *n, AstDumperOptions opt, int indent, int baseIndent,
function_ref<QStringView(SourceLocation)>loc2str)
{
AstDumper visitor=AstDumper(s, opt, indent, baseIndent, loc2str);
@@ -1092,7 +1094,10 @@ void astNodeDumper(Sink s, Node *n, AstDumperOptions opt, int indent, int baseIn
QString astNodeDump(Node *n, AstDumperOptions opt, int indent, int baseIndent,
function_ref<QStringView(SourceLocation)>loc2str)
{
- return dumperToString([n, opt, indent, baseIndent, loc2str](Sink s) { astNodeDumper(s, n, opt, indent, baseIndent, loc2str); });
+ return dumperToString(
+ [n, opt, indent, baseIndent, loc2str = std::move(loc2str)](const Sink &s) {
+ astNodeDumper(s, n, opt, indent, baseIndent, std::move(loc2str));
+ });
}
} // end namespace Dom
diff --git a/src/qmldom/qqmldomastdumper_p.h b/src/qmldom/qqmldomastdumper_p.h
index c942f53a0e..542f81b1dd 100644
--- a/src/qmldom/qqmldomastdumper_p.h
+++ b/src/qmldom/qqmldomastdumper_p.h
@@ -39,7 +39,7 @@ QMLDOM_EXPORT QString astNodeDiff(AST::Node *n1, AST::Node *n2, int nContext = 3
AstDumperOptions opt = AstDumperOption::None, int indent = 0,
function_ref<QStringView(SourceLocation)> loc2str1 = noStr,
function_ref<QStringView(SourceLocation)> loc2str2 = noStr);
-QMLDOM_EXPORT void astNodeDumper(Sink s, AST::Node *n, AstDumperOptions opt = AstDumperOption::None,
+QMLDOM_EXPORT void astNodeDumper(const Sink &s, AST::Node *n, AstDumperOptions opt = AstDumperOption::None,
int indent = 1, int baseIndent = 0,
function_ref<QStringView(SourceLocation)> loc2str = noStr);
QMLDOM_EXPORT QString astNodeDump(AST::Node *n, AstDumperOptions opt = AstDumperOption::None,
diff --git a/src/qmldom/qqmldomattachedinfo.cpp b/src/qmldom/qqmldomattachedinfo.cpp
index 838b373048..e86a2782a6 100644
--- a/src/qmldom/qqmldomattachedinfo.cpp
+++ b/src/qmldom/qqmldomattachedinfo.cpp
@@ -1,12 +1,17 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include "qqmldom_fwd_p.h"
#include "qqmldomlinewriter_p.h"
#include "qqmldomelements_p.h"
+#include "qqmldompath_p.h"
QT_BEGIN_NAMESPACE
namespace QQmlJS {
namespace Dom {
+using namespace Qt::StringLiterals;
+
+
/*!
\internal
\class QQmlJS::Dom::FileLocations
@@ -26,120 +31,120 @@ Attributes:
\sa QQmlJs::Dom::AttachedInfo
*/
-bool FileLocations::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool FileLocations::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = true;
-#ifdef QmlDomAddCodeStr
- bool hasCode = false;
- QString codeStr = self.fileObject().field(Fields::code).value().toString();
- auto loc2str = [&self, &codeStr](SourceLocation loc) {
- if (loc.offset < codeStr.length() && loc.end() <= codeStr.length())
- return QStringView(codeStr).mid(loc.offset, loc.length);
- return QStringView();
- };
-#else
- auto loc2str = [](SourceLocation) { return QStringView(); };
-#endif
cont = cont && self.dvValueLazyField(visitor, Fields::fullRegion, [this]() {
- return locationToData(fullRegion);
+ return sourceLocationToQCborValue(fullRegion);
});
- cont = cont && self.dvItemField(visitor, Fields::regions, [this, &self, &loc2str]() {
- return self.subMapItem(Map::fromMapRef<SourceLocation>(
- self.pathFromOwner().field(Fields::regions), regions,
- [&loc2str](DomItem &map, const PathEls::PathComponent &key, SourceLocation &el) {
- return map.subLocationItem(key, el, loc2str(el));
- }));
+ cont = cont && self.dvItemField(visitor, Fields::regions, [this, &self]() -> DomItem {
+ const Path pathFromOwner = self.pathFromOwner().field(Fields::regions);
+ auto map = Map::fromFileRegionMap(pathFromOwner, regions);
+ return self.subMapItem(map);
});
cont = cont
- && self.dvItemField(visitor, Fields::preCommentLocations, [this, &self, &loc2str]() {
- return self.subMapItem(Map::fromMapRef<QList<SourceLocation>>(
- self.pathFromOwner().field(Fields::preCommentLocations),
- preCommentLocations,
- [&loc2str](DomItem &map, const PathEls::PathComponent &key,
- QList<SourceLocation> &el) {
- return map.subListItem(List::fromQListRef<SourceLocation>(
- map.pathFromOwner().appendComponent(key), el,
- [&loc2str](DomItem &list, const PathEls::PathComponent &idx,
- SourceLocation &el) {
- return list.subLocationItem(idx, el, loc2str(el));
- }));
- }));
+ && self.dvItemField(visitor, Fields::preCommentLocations, [this, &self]() -> DomItem {
+ const Path pathFromOwner =
+ self.pathFromOwner().field(Fields::preCommentLocations);
+ auto map = Map::fromFileRegionListMap(pathFromOwner, preCommentLocations);
+ return self.subMapItem(map);
});
cont = cont
- && self.dvItemField(visitor, Fields::postCommentLocations, [this, &self, &loc2str]() {
- return self.subMapItem(Map::fromMapRef<QList<SourceLocation>>(
- self.pathFromOwner().field(Fields::postCommentLocations),
- postCommentLocations,
- [&loc2str](DomItem &map, const PathEls::PathComponent &key,
- QList<SourceLocation> &el) {
- return map.subListItem(List::fromQListRef<SourceLocation>(
- map.pathFromOwner().appendComponent(key), el,
- [&loc2str](DomItem &list, const PathEls::PathComponent &idx,
- SourceLocation &el) {
- return list.subLocationItem(idx, el, loc2str(el));
- }));
- }));
+ && self.dvItemField(visitor, Fields::postCommentLocations, [this, &self]() -> DomItem {
+ const Path pathFromOwner =
+ self.pathFromOwner().field(Fields::postCommentLocations);
+ auto map = Map::fromFileRegionListMap(pathFromOwner, postCommentLocations);
+ return self.subMapItem(map);
});
return cont;
}
-void FileLocations::ensureCommentLocations(QList<QString> keys)
-{
- for (auto k : keys) {
- preCommentLocations[k];
- postCommentLocations[k];
- }
-}
-
-FileLocations::Tree FileLocations::createTree(Path basePath){
+FileLocations::Tree FileLocations::createTree(const Path &basePath){
return AttachedInfoT<FileLocations>::createTree(basePath);
}
-FileLocations::Tree FileLocations::ensure(FileLocations::Tree base, Path basePath, AttachedInfo::PathType pType){
+FileLocations::Tree FileLocations::ensure(
+ const FileLocations::Tree &base, const Path &basePath, AttachedInfo::PathType pType)
+{
return AttachedInfoT<FileLocations>::ensure(base, basePath, pType);
}
+/*!
+\internal
+Allows to query information about the FileLocations::Tree obtained from item, such as path of
+the Tree root in the Dom, the path of this item's Tree in the Dom, and so on.
+
+\note You can use \c{qDebug() << item.path(FileLocations::findAttachedInfo(item).foundTreePath)} or
+\c{item.path(FileLocations::findAttachedInfo(item).foundTreePath).toString()} to print out the Tree
+of item, for example, as Tree's cannot be printed when outside the Dom.
+*/
AttachedInfoLookupResult<FileLocations::Tree>
-FileLocations::findAttachedInfo(DomItem &item, AttachedInfo::FindOptions options)
+FileLocations::findAttachedInfo(const DomItem &item)
{
- return AttachedInfoT<FileLocations>::findAttachedInfo(item, Fields::fileLocationsTree, options);
+ return AttachedInfoT<FileLocations>::findAttachedInfo(item, Fields::fileLocationsTree);
}
-FileLocations::Tree FileLocations::treePtr(DomItem &item)
+/*!
+ \internal
+ Returns the tree corresponding to a DomItem.
+ */
+FileLocations::Tree FileLocations::treeOf(const DomItem &item)
{
- return AttachedInfoT<FileLocations>::treePtr(item, Fields::fileLocationsTree);
+ return findAttachedInfo(item).foundTree;
}
-const FileLocations *FileLocations::fileLocationsPtr(DomItem &item)
+/*!
+ \internal
+ Returns the filelocation Info corresponding to a DomItem.
+ */
+const FileLocations *FileLocations::fileLocationsOf(const DomItem &item)
{
- if (FileLocations::Tree t = treePtr(item))
+ if (const FileLocations::Tree &t = treeOf(item))
return &(t->info());
return nullptr;
}
-void FileLocations::updateFullLocation(FileLocations::Tree fLoc, SourceLocation loc) {
+void FileLocations::updateFullLocation(const FileLocations::Tree &fLoc, SourceLocation loc)
+{
Q_ASSERT(fLoc);
if (loc != SourceLocation()) {
FileLocations::Tree p = fLoc;
while (p) {
SourceLocation &l = p->info().fullRegion;
- if (loc.begin() < l.begin() || loc.end() > l.end())
+ if (loc.begin() < l.begin() || loc.end() > l.end()) {
l = combine(l, loc);
- else
+ p->info().regions[MainRegion] = l;
+ } else {
break;
+ }
p = p->parent();
}
}
}
-void FileLocations::addRegion(FileLocations::Tree fLoc, QString locName, SourceLocation loc) {
+// Adding a new region to file location regions might break down qmlformat because
+// comments might be linked to new region undesirably. We might need to add an
+// exception to AstRangesVisitor::shouldSkipRegion when confronted those cases.
+void FileLocations::addRegion(const FileLocations::Tree &fLoc, FileLocationRegion region,
+ SourceLocation loc)
+{
Q_ASSERT(fLoc);
- fLoc->info().regions[locName] = loc;
+ fLoc->info().regions[region] = loc;
updateFullLocation(fLoc, loc);
}
-void FileLocations::addRegion(FileLocations::Tree fLoc, QStringView locName, SourceLocation loc) {
- addRegion(fLoc, locName.toString(), loc);
+SourceLocation FileLocations::region(const FileLocations::Tree &fLoc, FileLocationRegion region)
+{
+ Q_ASSERT(fLoc);
+ const auto &regions = fLoc->info().regions;
+ if (auto it = regions.constFind(region); it != regions.constEnd() && it->isValid()) {
+ return *it;
+ }
+
+ if (region == MainRegion)
+ return fLoc->info().fullRegion;
+
+ return SourceLocation{};
}
/*!
@@ -160,7 +165,7 @@ Attributes:
\sa QQmlJs::Dom::AttachedInfo
*/
-bool AttachedInfo::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool AttachedInfo::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = true;
if (Ptr p = parent())
@@ -172,13 +177,13 @@ bool AttachedInfo::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
cont = cont && self.dvItemField(visitor, Fields::subItems, [this, &self]() {
return self.subMapItem(Map(
Path::Field(Fields::subItems),
- [this](DomItem &map, QString key) {
+ [this](const DomItem &map, const QString &key) {
Path p = Path::fromString(key);
return map.copy(m_subItems.value(p), map.canonicalPath().key(key));
},
- [this](DomItem &) {
+ [this](const DomItem &) {
QSet<QString> res;
- for (auto p : m_subItems.keys())
+ for (const auto &p : m_subItems.keys())
res.insert(p.toString());
return res;
},
@@ -202,7 +207,9 @@ AttachedInfo::AttachedInfo(const AttachedInfo &o):
The path might be either a relative path or a canonical path, as specified by the PathType
*/
-AttachedInfo::Ptr AttachedInfo::ensure(AttachedInfo::Ptr self, Path path, AttachedInfo::PathType pType){
+AttachedInfo::Ptr AttachedInfo::ensure(
+ const AttachedInfo::Ptr &self, const Path &path, AttachedInfo::PathType pType){
+ Path relative;
switch (pType) {
case PathType::Canonical: {
if (!path)
@@ -210,14 +217,15 @@ AttachedInfo::Ptr AttachedInfo::ensure(AttachedInfo::Ptr self, Path path, Attach
Q_ASSERT(self);
Path removed = path.mid(0, self->path().length());
Q_ASSERT(removed == self->path());
- path = path.mid(self->path().length());
+ relative = path.mid(self->path().length());
} break;
case PathType::Relative:
Q_ASSERT(self);
+ relative = path;
break;
}
Ptr res = self;
- for (auto p : path) {
+ for (const auto &p : std::as_const(relative)) {
if (AttachedInfo::Ptr subEl = res->m_subItems.value(p)) {
res = subEl;
} else {
@@ -229,15 +237,21 @@ AttachedInfo::Ptr AttachedInfo::ensure(AttachedInfo::Ptr self, Path path, Attach
return res;
}
-AttachedInfo::Ptr AttachedInfo::find(AttachedInfo::Ptr self, Path p, AttachedInfo::PathType pType){
+AttachedInfo::Ptr AttachedInfo::find(
+ const AttachedInfo::Ptr &self, const Path &p, AttachedInfo::PathType pType)
+{
+ Path rest;
if (pType == PathType::Canonical) {
if (!self) return nullptr;
Path removed = p.mid(0, self->path().length());
if (removed != self->path())
return nullptr;
+ rest = p.dropFront(self->path().length());
+ } else {
+ rest = p;
}
+
AttachedInfo::Ptr res = self;
- Path rest = p;
while (rest) {
if (!res)
break;
@@ -248,8 +262,7 @@ AttachedInfo::Ptr AttachedInfo::find(AttachedInfo::Ptr self, Path p, AttachedInf
}
AttachedInfoLookupResult<AttachedInfo::Ptr>
-AttachedInfo::findAttachedInfo(DomItem &item, QStringView fieldName,
- AttachedInfo::FindOptions options)
+AttachedInfo::findAttachedInfo(const DomItem &item, QStringView fieldName)
{
Path p;
DomItem fLoc = item.field(fieldName);
@@ -272,60 +285,55 @@ AttachedInfo::findAttachedInfo(DomItem &item, QStringView fieldName,
if (AttachedInfo::Ptr foundTree =
AttachedInfo::find(fLocPtr, p, AttachedInfo::PathType::Relative))
res.foundTree = foundTree;
- if (options & (FindOption::SetRootTreePath | FindOption::SetFoundTreePath))
- res.rootTreePath = fLoc.canonicalPath();
- if (options & FindOption::SetFoundTreePath) {
- Path foundTreePath = res.rootTreePath.value();
- if (res.lookupPath) {
- foundTreePath = foundTreePath.key(res.lookupPath.head().toString());
- for (Path pEl : res.lookupPath.mid(1))
- foundTreePath = foundTreePath.field(Fields::subItems).key(pEl.toString());
- }
- res.foundTreePath = foundTreePath;
- }
+ res.rootTreePath = fLoc.canonicalPath();
+
+ res.foundTreePath = res.rootTreePath;
+ for (const Path &pEl : res.lookupPath)
+ res.foundTreePath = res.foundTreePath.field(Fields::subItems).key(pEl.toString());
return res;
}
-bool UpdatedScriptExpression::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool UpdatedScriptExpression::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = true;
cont = cont && self.dvWrapField(visitor, Fields::expr, expr);
return cont;
}
-UpdatedScriptExpression::Tree UpdatedScriptExpression::createTree(Path basePath)
+UpdatedScriptExpression::Tree UpdatedScriptExpression::createTree(const Path &basePath)
{
return AttachedInfoT<UpdatedScriptExpression>::createTree(basePath);
}
-UpdatedScriptExpression::Tree UpdatedScriptExpression::ensure(UpdatedScriptExpression::Tree base,
- Path basePath,
- AttachedInfo::PathType pType)
+UpdatedScriptExpression::Tree UpdatedScriptExpression::ensure(
+ const UpdatedScriptExpression::Tree &base, const Path &basePath,
+ AttachedInfo::PathType pType)
{
return AttachedInfoT<UpdatedScriptExpression>::ensure(base, basePath, pType);
}
AttachedInfoLookupResult<UpdatedScriptExpression::Tree>
-UpdatedScriptExpression::findAttachedInfo(DomItem &item, AttachedInfo::FindOptions options)
+UpdatedScriptExpression::findAttachedInfo(const DomItem &item)
{
return AttachedInfoT<UpdatedScriptExpression>::findAttachedInfo(
- item, Fields::updatedScriptExpressions, options);
+ item, Fields::updatedScriptExpressions);
}
-UpdatedScriptExpression::Tree UpdatedScriptExpression::treePtr(DomItem &item)
+UpdatedScriptExpression::Tree UpdatedScriptExpression::treePtr(const DomItem &item)
{
return AttachedInfoT<UpdatedScriptExpression>::treePtr(item, Fields::updatedScriptExpressions);
}
-const UpdatedScriptExpression *UpdatedScriptExpression::exprPtr(DomItem &item)
+const UpdatedScriptExpression *UpdatedScriptExpression::exprPtr(const DomItem &item)
{
if (UpdatedScriptExpression::Tree t = treePtr(item))
return &(t->info());
return nullptr;
}
-bool UpdatedScriptExpression::visitTree(Tree base, function_ref<bool(Path, Tree)> visitor,
- Path basePath)
+bool UpdatedScriptExpression::visitTree(
+ const Tree &base, function_ref<bool(const Path &, const Tree &)> visitor,
+ const Path &basePath)
{
return AttachedInfoT<UpdatedScriptExpression>::visitTree(base, visitor, basePath);
}
diff --git a/src/qmldom/qqmldomattachedinfo_p.h b/src/qmldom/qqmldomattachedinfo_p.h
index 808d0db467..8412c3ab9b 100644
--- a/src/qmldom/qqmldomattachedinfo_p.h
+++ b/src/qmldom/qqmldomattachedinfo_p.h
@@ -25,22 +25,25 @@ QT_BEGIN_NAMESPACE
namespace QQmlJS {
namespace Dom {
+struct AttachedInfoLookupResultBase
+{
+ Path lookupPath;
+ Path rootTreePath;
+ Path foundTreePath;
+};
template<typename TreePtr>
-class AttachedInfoLookupResult
+class AttachedInfoLookupResult: public AttachedInfoLookupResultBase
{
public:
TreePtr foundTree;
- Path lookupPath; // relative path used to reach result
- std::optional<Path> rootTreePath; // path of the root TreePath
- std::optional<Path> foundTreePath;
+
operator bool() { return bool(foundTree); }
template<typename T>
AttachedInfoLookupResult<std::shared_ptr<T>> as() const
{
AttachedInfoLookupResult<std::shared_ptr<T>> res;
+ res.AttachedInfoLookupResultBase::operator=(*this);
res.foundTree = std::static_pointer_cast<T>(foundTree);
- res.lookupPath = lookupPath;
- res.rootTreePath = rootTreePath;
return res;
}
};
@@ -53,51 +56,44 @@ public:
Canonical
};
Q_ENUM(PathType)
- enum class FindOption {
- None = 0,
- SetRootTreePath = 0x1,
- SetFoundTreePath = 0x2,
- Default = 0x3
- };
- Q_DECLARE_FLAGS(FindOptions, FindOption)
- Q_FLAG(FindOptions)
constexpr static DomType kindValue = DomType::AttachedInfo;
using Ptr = std::shared_ptr<AttachedInfo>;
DomType kind() const override { return kindValue; }
- Path canonicalPath(DomItem &self) const override { return self.m_ownerPath; }
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) override;
+ Path canonicalPath(const DomItem &self) const override { return self.m_ownerPath; }
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override;
- AttachedInfo::Ptr makeCopy(DomItem &self) const
+ AttachedInfo::Ptr makeCopy(const DomItem &self) const
{
return std::static_pointer_cast<AttachedInfo>(doCopy(self));
}
Ptr parent() const { return m_parent.lock(); }
Path path() const { return m_path; }
- void setPath(Path p) { m_path = p; }
+ void setPath(const Path &p) { m_path = p; }
+
+ AttachedInfo(const Ptr &parent = nullptr, const Path &p = Path())
+ : m_path(p), m_parent(parent)
+ {}
- AttachedInfo(Ptr parent = nullptr, Path p = Path()) : m_path(p), m_parent(parent) {}
AttachedInfo(const AttachedInfo &o);
- static Ptr ensure(Ptr self, Path path, PathType pType = PathType::Relative);
- static Ptr find(Ptr self, Path p, PathType pType = PathType::Relative);
- static AttachedInfoLookupResult<Ptr>
- findAttachedInfo(DomItem &item, QStringView treeFieldName,
- FindOptions options = AttachedInfo::FindOption::None);
- static Ptr treePtr(DomItem &item, QStringView fieldName)
+ static Ptr ensure(const Ptr &self, const Path &path, PathType pType = PathType::Relative);
+ static Ptr find(const Ptr &self, const Path &p, PathType pType = PathType::Relative);
+ static AttachedInfoLookupResult<Ptr> findAttachedInfo(const DomItem &item,
+ QStringView treeFieldName);
+ static Ptr treePtr(const DomItem &item, QStringView fieldName)
{
- return findAttachedInfo(item, fieldName, FindOption::None).foundTree;
+ return findAttachedInfo(item, fieldName).foundTree;
}
- DomItem itemAtPath(DomItem &self, Path p, PathType pType = PathType::Relative) const
+ DomItem itemAtPath(const DomItem &self, const Path &p, PathType pType = PathType::Relative) const
{
if (Ptr resPtr = find(self.ownerAs<AttachedInfo>(), p, pType)) {
- if (pType == PathType::Canonical)
- p = p.mid(m_path.length());
+ const Path relative = (pType == PathType::Canonical) ? p.mid(m_path.length()) : p;
Path resPath = self.canonicalPath();
- for (Path pEl : p) {
+ for (const Path &pEl : relative) {
resPath = resPath.field(Fields::subItems).key(pEl.toString());
}
return self.copy(resPtr, resPath);
@@ -105,19 +101,18 @@ public:
return DomItem();
}
- DomItem infoAtPath(DomItem &self, Path p, PathType pType = PathType::Relative) const
+ DomItem infoAtPath(const DomItem &self, const Path &p, PathType pType = PathType::Relative) const
{
return itemAtPath(self, p, pType).field(Fields::infoItem);
}
- MutableDomItem ensureItemAtPath(MutableDomItem &self, Path p,
+ MutableDomItem ensureItemAtPath(MutableDomItem &self, const Path &p,
PathType pType = PathType::Relative)
{
if (Ptr resPtr = ensure(self.ownerAs<AttachedInfo>(), p, pType)) {
- if (pType == PathType::Canonical)
- p = p.mid(m_path.length());
+ const Path relative = (pType == PathType::Canonical) ? p.mid(m_path.length()) : p;
Path resPath = self.canonicalPath();
- for (Path pEl : p) {
+ for (const Path &pEl : relative) {
resPath = resPath.field(Fields::subItems).key(pEl.toString());
}
return MutableDomItem(self.item().copy(resPtr, resPath));
@@ -125,18 +120,15 @@ public:
return MutableDomItem();
}
- MutableDomItem ensureInfoAtPath(MutableDomItem &self, Path p,
+ MutableDomItem ensureInfoAtPath(MutableDomItem &self, const Path &p,
PathType pType = PathType::Relative)
{
return ensureItemAtPath(self, p, pType).field(Fields::infoItem);
}
- virtual AttachedInfo::Ptr instantiate(AttachedInfo::Ptr parent, Path p = Path()) const = 0;
- virtual DomItem infoItem(DomItem &self) = 0;
- DomItem infoItem(DomItem &self) const
- {
- return const_cast<AttachedInfo *>(this)->infoItem(self);
- }
+ virtual AttachedInfo::Ptr instantiate(
+ const AttachedInfo::Ptr &parent, const Path &p = Path()) const = 0;
+ virtual DomItem infoItem(const DomItem &self) const = 0;
QMap<Path, Ptr> subItems() const {
return m_subItems;
}
@@ -148,7 +140,6 @@ protected:
std::weak_ptr<AttachedInfo> m_parent;
QMap<Path, Ptr> m_subItems;
};
-Q_DECLARE_OPERATORS_FOR_FLAGS(AttachedInfo::FindOptions)
template<typename Info>
class QMLDOM_EXPORT AttachedInfoT final : public AttachedInfo
@@ -158,7 +149,7 @@ public:
using Ptr = std::shared_ptr<AttachedInfoT>;
using InfoType = Info;
- AttachedInfoT(Ptr parent = nullptr, Path p = Path()) : AttachedInfo(parent, p) {}
+ AttachedInfoT(const Ptr &parent = nullptr, const Path &p = Path()) : AttachedInfo(parent, p) {}
AttachedInfoT(const AttachedInfoT &o):
AttachedInfo(o),
m_info(o.m_info)
@@ -171,29 +162,32 @@ public:
}
}
- static Ptr createTree(Path p = Path()) {
+ static Ptr createTree(const Path &p = Path()) {
return Ptr(new AttachedInfoT(nullptr, p));
}
- static Ptr ensure(Ptr self, Path path, PathType pType = PathType::Relative){
+ static Ptr ensure(const Ptr &self, const Path &path, PathType pType = PathType::Relative)
+ {
return std::static_pointer_cast<AttachedInfoT>(AttachedInfo::ensure(self, path, pType));
}
- static Ptr find(Ptr self, Path p, PathType pType = PathType::Relative){
+ static Ptr find(const Ptr &self, const Path &p, PathType pType = PathType::Relative)
+ {
return std::static_pointer_cast<AttachedInfoT>(AttachedInfo::find(self, p, pType));
}
- static AttachedInfoLookupResult<Ptr> findAttachedInfo(DomItem &item, QStringView fieldName,
- AttachedInfo::FindOptions options)
+ static AttachedInfoLookupResult<Ptr> findAttachedInfo(const DomItem &item,
+ QStringView fieldName)
{
- return AttachedInfo::findAttachedInfo(item, fieldName, options)
- .template as<AttachedInfoT>();
+ return AttachedInfo::findAttachedInfo(item, fieldName).template as<AttachedInfoT>();
}
- static Ptr treePtr(DomItem &item, QStringView fieldName)
+ static Ptr treePtr(const DomItem &item, QStringView fieldName)
{
return std::static_pointer_cast<AttachedInfoT>(AttachedInfo::treePtr(item, fieldName));
}
- static bool visitTree(Ptr base, function_ref<bool(Path, Ptr)>visitor, Path basePath = Path()) {
+ static bool visitTree(
+ const Ptr &base, function_ref<bool(const Path &, const Ptr &)> visitor,
+ const Path &basePath = Path()) {
if (base) {
Path pNow = basePath.path(base->path());
if (visitor(pNow, base)) {
@@ -211,12 +205,15 @@ public:
return true;
}
- AttachedInfo::Ptr instantiate(AttachedInfo::Ptr parent, Path p = Path()) const override {
+ AttachedInfo::Ptr instantiate(
+ const AttachedInfo::Ptr &parent, const Path &p = Path()) const override
+ {
return Ptr(new AttachedInfoT(std::static_pointer_cast<AttachedInfoT>(parent), p));
}
- DomItem infoItem(DomItem &self) override { return self.wrapField(Fields::infoItem, m_info); }
- Ptr makeCopy(DomItem &self) const
+ DomItem infoItem(const DomItem &self) const override { return self.wrapField(Fields::infoItem, m_info); }
+
+ Ptr makeCopy(const DomItem &self) const
{
return std::static_pointer_cast<AttachedInfoT>(doCopy(self));
}
@@ -225,8 +222,18 @@ public:
const Info &info() const { return m_info; }
Info &info() { return m_info; }
+
+ QString canonicalPathForTesting() const
+ {
+ QString result;
+ for (auto *it = this; it; it = it->parent().get()) {
+ result.prepend(it->path().toString());
+ }
+ return result;
+ }
+
protected:
- std::shared_ptr<OwningItem> doCopy(DomItem &) const override
+ std::shared_ptr<OwningItem> doCopy(const DomItem &) const override
{
return Ptr(new AttachedInfoT(*this));
}
@@ -240,34 +247,34 @@ public:
using Tree = std::shared_ptr<AttachedInfoT<FileLocations>>;
constexpr static DomType kindValue = DomType::FileLocations;
DomType kind() const { return kindValue; }
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor);
- void ensureCommentLocations(QList<QString> keys);
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const;
- static Tree createTree(Path basePath);
- static Tree ensure(Tree base, Path basePath, AttachedInfo::PathType pType);
- static Tree find(Tree self, Path p,
+ static Tree createTree(const Path &basePath);
+ static Tree ensure(const Tree &base, const Path &basePath,
+ AttachedInfo::PathType pType = AttachedInfo::PathType::Relative);
+ static Tree find(const Tree &self, const Path &p,
AttachedInfo::PathType pType = AttachedInfo::PathType::Relative)
{
return AttachedInfoT<FileLocations>::find(self, p, pType);
}
// returns the path looked up and the found tree when looking for the info attached to item
- static AttachedInfoLookupResult<Tree>
- findAttachedInfo(DomItem &item,
- AttachedInfo::FindOptions options = AttachedInfo::FindOption::Default);
- // convenience: find FileLocations::Tree attached to the given item
- static FileLocations::Tree treePtr(DomItem &);
- // convenience: find FileLocations* attached to the given item (if there is one)
- static const FileLocations *fileLocationsPtr(DomItem &);
+ static AttachedInfoLookupResult<Tree> findAttachedInfo(const DomItem &item);
+ static FileLocations::Tree treeOf(const DomItem &);
+ static const FileLocations *fileLocationsOf(const DomItem &);
- static void updateFullLocation(Tree fLoc, SourceLocation loc);
- static void addRegion(Tree fLoc, QString locName, SourceLocation loc);
- static void addRegion(Tree fLoc, QStringView locName, SourceLocation loc);
+ static void updateFullLocation(const Tree &fLoc, SourceLocation loc);
+ static void addRegion(const Tree &fLoc, FileLocationRegion region, SourceLocation loc);
+ static QQmlJS::SourceLocation region(const Tree &fLoc, FileLocationRegion region);
+private:
+ static QMetaEnum regionEnum;
+
+public:
SourceLocation fullRegion;
- QMap<QString, SourceLocation> regions;
- QMap<QString, QList<SourceLocation>> preCommentLocations;
- QMap<QString, QList<SourceLocation>> postCommentLocations;
+ QMap<FileLocationRegion, SourceLocation> regions;
+ QMap<FileLocationRegion, QList<SourceLocation>> preCommentLocations;
+ QMap<FileLocationRegion, QList<SourceLocation>> postCommentLocations;
};
class QMLDOM_EXPORT UpdatedScriptExpression
@@ -277,22 +284,22 @@ public:
using Tree = std::shared_ptr<AttachedInfoT<UpdatedScriptExpression>>;
constexpr static DomType kindValue = DomType::UpdatedScriptExpression;
DomType kind() const { return kindValue; }
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor);
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const;
- static Tree createTree(Path basePath);
- static Tree ensure(Tree base, Path basePath, AttachedInfo::PathType pType);
+ static Tree createTree(const Path &basePath);
+ static Tree ensure(const Tree &base, const Path &basePath, AttachedInfo::PathType pType);
// returns the path looked up and the found tree when looking for the info attached to item
static AttachedInfoLookupResult<Tree>
- findAttachedInfo(DomItem &item,
- AttachedInfo::FindOptions options = AttachedInfo::FindOption::Default);
+ findAttachedInfo(const DomItem &item);
// convenience: find FileLocations::Tree attached to the given item
- static Tree treePtr(DomItem &);
+ static Tree treePtr(const DomItem &);
// convenience: find FileLocations* attached to the given item (if there is one)
- static const UpdatedScriptExpression *exprPtr(DomItem &);
+ static const UpdatedScriptExpression *exprPtr(const DomItem &);
- static bool visitTree(Tree base, function_ref<bool(Path, Tree)> visitor,
- Path basePath = Path());
+ static bool visitTree(
+ const Tree &base, function_ref<bool(const Path &, const Tree &)> visitor,
+ const Path &basePath = Path());
std::shared_ptr<ScriptExpression> expr;
};
diff --git a/src/qmldom/qqmldomcodeformatter.cpp b/src/qmldom/qqmldomcodeformatter.cpp
index 9997905a5e..27279ce7c0 100644
--- a/src/qmldom/qqmldomcodeformatter.cpp
+++ b/src/qmldom/qqmldomcodeformatter.cpp
@@ -6,7 +6,7 @@
#include <QLoggingCategory>
#include <QMetaEnum>
-static Q_LOGGING_CATEGORY(formatterLog, "qt.qmldom.formatter", QtWarningMsg);
+Q_STATIC_LOGGING_CATEGORY(formatterLog, "qt.qmldom.formatter", QtWarningMsg);
QT_BEGIN_NAMESPACE
namespace QQmlJS {
@@ -224,9 +224,8 @@ void FormatPartialStatus::dump() const
{
qCDebug(formatterLog) << "Current token index" << tokenIndex;
qCDebug(formatterLog) << "Current state:";
- foreach (const State &s, currentStatus.states) {
+ for (const State &s : currentStatus.states)
qCDebug(formatterLog) << FormatTextStatus::stateToString(s.type) << s.savedIndentDepth;
- }
qCDebug(formatterLog) << "Current lexerState:" << currentStatus.lexerState.state;
qCDebug(formatterLog) << "Current indent:" << currentIndent;
}
diff --git a/src/qmldom/qqmldomcomments.cpp b/src/qmldom/qqmldomcomments.cpp
index 3eee7adb28..8e94758b57 100644
--- a/src/qmldom/qqmldomcomments.cpp
+++ b/src/qmldom/qqmldomcomments.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmldomcomments_p.h"
#include "qqmldomoutwriter_p.h"
@@ -17,7 +17,7 @@
#include <variant>
-static Q_LOGGING_CATEGORY(commentsLog, "qt.qmldom.comments", QtWarningMsg);
+Q_STATIC_LOGGING_CATEGORY(commentsLog, "qt.qmldom.comments", QtWarningMsg);
QT_BEGIN_NAMESPACE
namespace QQmlJS {
@@ -65,7 +65,8 @@ Comments store a string (rawComment) with comment characters (//,..) and spaces.
Sometime one wants just the comment, the commentcharacters, the space before the comment,....
CommentInfo gets such a raw comment string and makes the various pieces available
*/
-CommentInfo::CommentInfo(QStringView rawComment) : rawComment(rawComment)
+CommentInfo::CommentInfo(QStringView rawComment, QQmlJS::SourceLocation loc)
+ : rawComment(rawComment), commentLocation(loc)
{
commentBegin = 0;
while (commentBegin < quint32(rawComment.size()) && rawComment.at(commentBegin).isSpace()) {
@@ -97,10 +98,9 @@ CommentInfo::CommentInfo(QStringView rawComment) : rawComment(rawComment)
warnings.append(tr("Unexpected comment start %1").arg(commentStartStr));
break;
}
+
commentEnd = commentBegin + commentStartStr.size();
quint32 rawEnd = quint32(rawComment.size());
- while (commentEnd < rawEnd && rawComment.at(commentEnd).isSpace())
- ++commentEnd;
commentContentEnd = commentContentBegin = commentEnd;
QChar e1 = ((expectedEnd.isEmpty()) ? QChar::fromLatin1(0) : expectedEnd.at(0));
while (commentEnd < rawEnd) {
@@ -115,7 +115,8 @@ CommentInfo::CommentInfo(QStringView rawComment) : rawComment(rawComment)
commentContentEnd = commentEnd;
}
} else {
- commentEndStr = rawComment.mid(++commentEnd - 1, 1);
+ // Comment ends with \n, treat as it is not part of the comment but post whitespace
+ commentEndStr = rawComment.mid(commentEnd - 1, 1);
break;
}
} else if (!c.isSpace()) {
@@ -156,6 +157,11 @@ CommentInfo::CommentInfo(QStringView rawComment) : rawComment(rawComment)
.arg(i));
}
}
+
+ // Post process comment source location
+ commentLocation.offset -= commentStartStr.size();
+ commentLocation.startColumn -= commentStartStr.size();
+ commentLocation.length = commentEnd - commentBegin;
}
/*!
@@ -191,7 +197,7 @@ A comment has methods to write it out again (write) and expose it to the Dom
/*!
\brief Expose attributes to the Dom
*/
-bool Comment::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool Comment::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = true;
cont = cont && self.dvValueField(visitor, Fields::rawComment, rawComment());
@@ -236,55 +242,39 @@ Every region has a name, and should be written out using the OutWriter.writeRegi
startRegion/ EndRegion). Region comments keeps a mapping containing them.
*/
-bool CommentedElement::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool CommentedElement::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = true;
- cont = cont && self.dvWrapField(visitor, Fields::preComments, preComments);
- cont = cont && self.dvWrapField(visitor, Fields::postComments, postComments);
+ cont = cont && self.dvWrapField(visitor, Fields::preComments, m_preComments);
+ cont = cont && self.dvWrapField(visitor, Fields::postComments, m_postComments);
return cont;
}
void CommentedElement::writePre(OutWriter &lw, QList<SourceLocation> *locs) const
{
if (locs)
- locs->resize(preComments.size());
+ locs->resize(m_preComments.size());
int i = 0;
- for (const Comment &c : preComments)
+ for (const Comment &c : m_preComments)
c.write(lw, (locs ? &((*locs)[i++]) : nullptr));
}
void CommentedElement::writePost(OutWriter &lw, QList<SourceLocation> *locs) const
{
if (locs)
- locs->resize(postComments.size());
+ locs->resize(m_postComments.size());
int i = 0;
- for (const Comment &c : postComments)
+ for (const Comment &c : m_postComments)
c.write(lw, (locs ? &((*locs)[i++]) : nullptr));
}
-/*!
-\brief Given the SourceLocation of the current element returns the comments associated with the
-start and end of item
-
-The map uses an index that is based on 2*the location. Thus for every location l it is possible
-to have two indexes: 2*l (just before) and 2*l+1 (just after).
-This allows to attach comments to indexes representing either just before or after any location
-*/
-QMultiMap<quint32, const QList<Comment> *>
-CommentedElement::commentGroups(SourceLocation elLocation) const
-{
- return QMultiMap<quint32, const QList<Comment> *>(
- { { elLocation.begin() * 2, &preComments },
- { elLocation.end() * 2 + 1, &postComments } });
-}
-
using namespace QQmlJS::AST;
class RegionRef
{
public:
Path path; // store the MutableDomItem instead?
- QString regionName;
+ FileLocationRegion regionName;
};
// internal class to keep a reference either to an AST::Node* or a region of a DomItem and the
@@ -293,8 +283,8 @@ class ElementRef
{
public:
ElementRef(AST::Node *node, quint32 size) : element(node), size(size) { }
- ElementRef(Path path, QString region, quint32 size)
- : element(RegionRef { path, region }), size(size)
+ ElementRef(const Path &path, FileLocationRegion region, quint32 size)
+ : element(RegionRef{ path, region }), size(size)
{
}
operator bool() const
@@ -331,6 +321,9 @@ QSet<int> VisitAll::uiKinds()
AST::Node::Kind_UiArrayBinding, AST::Node::Kind_UiImport,
AST::Node::Kind_UiObjectBinding, AST::Node::Kind_UiObjectDefinition,
AST::Node::Kind_UiInlineComponent, AST::Node::Kind_UiObjectInitializer,
+#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
+ AST::Node::Kind_UiPragmaValueList,
+#endif
AST::Node::Kind_UiPragma, AST::Node::Kind_UiProgram,
AST::Node::Kind_UiPublicMember, AST::Node::Kind_UiQualifiedId,
AST::Node::Kind_UiScriptBinding, AST::Node::Kind_UiSourceElement,
@@ -346,11 +339,13 @@ public:
AstRangesVisitor() = default;
void addNodeRanges(AST::Node *rootNode);
- void addItemRanges(DomItem item, FileLocations::Tree itemLocations, Path currentP);
+ void addItemRanges(
+ const DomItem &item, const FileLocations::Tree &itemLocations, const Path &currentP);
void throwRecursionDepthError() override { }
static const QSet<int> kindsToSkip();
+ static bool shouldSkipRegion(const DomItem &item, FileLocationRegion region);
bool preVisit(Node *n) override
{
@@ -365,8 +360,6 @@ public:
return true;
}
- QQmlJS::Engine *engine;
- FileLocations::Tree rootItemLocations;
QMap<quint32, ElementRef> starts;
QMap<quint32, ElementRef> ends;
};
@@ -376,7 +369,8 @@ void AstRangesVisitor::addNodeRanges(AST::Node *rootNode)
AST::Node::accept(rootNode, this);
}
-void AstRangesVisitor::addItemRanges(DomItem item, FileLocations::Tree itemLocations, Path currentP)
+void AstRangesVisitor::addItemRanges(
+ const DomItem &item, const FileLocations::Tree &itemLocations, const Path &currentP)
{
if (!itemLocations) {
if (item)
@@ -389,10 +383,13 @@ void AstRangesVisitor::addItemRanges(DomItem item, FileLocations::Tree itemLocat
for (auto it = regs.cbegin(), end = regs.cend(); it != end; ++it) {
quint32 startI = it.value().begin();
quint32 endI = it.value().end();
- if (!starts.contains(startI))
- starts.insert(startI, { currentP, it.key(), quint32(endI - startI) });
- if (!ends.contains(endI))
- ends.insert(endI, { currentP, it.key(), endI - startI });
+
+ if (!shouldSkipRegion(item, it.key())) {
+ if (!starts.contains(startI))
+ starts.insert(startI, { currentP, it.key(), quint32(endI - startI) });
+ if (!ends.contains(endI))
+ ends.insert(endI, { currentP, it.key(), endI - startI });
+ }
}
}
{
@@ -425,88 +422,99 @@ const QSet<int> AstRangesVisitor::kindsToSkip()
return res;
}
-/*!
-\class QQmlJS::Dom::AstComments
-\brief Stores the comments associated with javascript AST::Node pointers
+/*! \internal
+ \brief returns true if comments should skip attaching to this region
*/
-
-bool AstComments::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool AstRangesVisitor::shouldSkipRegion(const DomItem &item, FileLocationRegion region)
{
- bool cont = self.dvItemField(visitor, Fields::commentedElements, [this, &self]() {
- return self.subMapItem(Map(
- self.pathFromOwner().field(Fields::commentedElements),
- [this](DomItem &map, QString key) {
- bool ok;
- // we expose the comments as map just for debugging purposes,
- // as key we use the address hex value as key (keys must be strings)
- quintptr v = key.split(QLatin1Char('_')).last().toULong(&ok, 16);
- // recover the actual key, and check if it is in the map
- AST::Node *n = reinterpret_cast<AST::Node *>(v);
- if (ok && m_commentedElements.contains(n))
- return map.wrap(PathEls::Key(key), m_commentedElements[n]);
- return DomItem();
- },
- [this](DomItem &) {
- QSet<QString> res;
- for (AST::Node *n : m_commentedElements.keys()) {
- QString name;
- if (n)
- name = QString::number(n->kind); // we should add mapping to
- // string for this
- res.insert(name + QStringLiteral(u"_") + QString::number(quintptr(n), 16));
- }
- return res;
- },
- QLatin1String("CommentedElements")));
- });
- return cont;
+ switch (item.internalKind()) {
+ case DomType::EnumDecl: {
+ return (region == FileLocationRegion::IdentifierRegion)
+ || (region == FileLocationRegion::EnumKeywordRegion);
+ }
+ case DomType::EnumItem: {
+ return (region == FileLocationRegion::IdentifierRegion)
+ || (region == FileLocationRegion::EnumValueRegion);
+ }
+ case DomType::QmlObject: {
+ return (region == FileLocationRegion::RightBraceRegion
+ || region == FileLocationRegion::LeftBraceRegion);
+ }
+ case DomType::Import:
+ case DomType::ImportScope:
+ return region == FileLocationRegion::IdentifierRegion;
+ default:
+ return false;
+ }
+ Q_UNREACHABLE_RETURN(false);
}
-void AstComments::collectComments(MutableDomItem &item)
+class CommentLinker
{
- if (std::shared_ptr<ScriptExpression> scriptPtr = item.ownerAs<ScriptExpression>()) {
- DomItem itemItem = item.item();
- return collectComments(scriptPtr->engine(), scriptPtr->ast(), scriptPtr->astComments(),
- item, FileLocations::treePtr(itemItem));
- } else if (std::shared_ptr<QmlFile> qmlFilePtr = item.ownerAs<QmlFile>()) {
- return collectComments(qmlFilePtr->engine(), qmlFilePtr->ast(), qmlFilePtr->astComments(),
- item, qmlFilePtr->fileLocationsTree());
- } else {
- qCWarning(commentsLog)
- << "collectComments works with QmlFile and ScriptExpression, not with"
- << item.internalKindStr();
+public:
+ CommentLinker(QStringView code, ElementRef &commentedElement, const AstRangesVisitor &ranges, quint32 &lastPostCommentPostEnd,
+ const SourceLocation &commentLocation)
+ : m_code{ code },
+ m_commentedElement{ commentedElement },
+ m_lastPostCommentPostEnd{ lastPostCommentPostEnd },
+ m_ranges{ ranges },
+ m_commentLocation { commentLocation },
+ m_startElement{ m_ranges.starts.lowerBound(commentLocation.begin()) },
+ m_endElement{ m_ranges.ends.lowerBound(commentLocation.end()) },
+ m_spaces{findSpacesAroundComment()}
+ {
}
-}
-/*!
-\brief
-Collects and associates comments with javascript AST::Node pointers and MutableDomItem in
-rootItem
-*/
-void AstComments::collectComments(std::shared_ptr<Engine> engine, AST::Node *n,
- std::shared_ptr<AstComments> ccomm, MutableDomItem rootItem,
- FileLocations::Tree rootItemLocations)
-{
- if (!n)
- return;
- AstRangesVisitor ranges;
- ranges.addItemRanges(rootItem.item(), rootItemLocations, Path());
- ranges.addNodeRanges(n);
- QStringView code = engine->code();
- QHash<AST::Node *, CommentedElement> &commentedElements = ccomm->m_commentedElements;
- quint32 lastPostCommentPostEnd = 0;
- for (SourceLocation cLoc : engine->comments()) {
- // collect whitespace before and after cLoc -> iPre..iPost contains whitespace,
- // do not add newline before, but add the one after
- quint32 iPre = cLoc.begin();
+ void linkCommentWithElement()
+ {
+ if (m_spaces.preNewline < 1) {
+ checkElementBeforeComment();
+ checkElementAfterComment();
+ } else {
+ checkElementAfterComment();
+ checkElementBeforeComment();
+ }
+ if (!m_commentedElement)
+ checkElementInside();
+ }
+
+ [[nodiscard]] Comment createComment() const
+ {
+ const auto [preSpacesIndex, postSpacesIndex, preNewlineCount] = m_spaces;
+ return Comment{ m_code.mid(preSpacesIndex, quint32(postSpacesIndex) - preSpacesIndex),
+ m_commentLocation,
+ static_cast<int>(preNewlineCount),
+ m_commentType};
+ }
+
+private:
+ struct SpaceTrace
+ {
+ quint32 iPre;
+ qsizetype iPost;
+ int preNewline;
+ };
+
+ /*! \internal
+ \brief Returns a Comment data
+ Comment starts from the first non-newline and non-space character preceding
+ the comment start characters. For example, "\n\n // A comment \n\n\n", we
+ hold the prenewlines count (2). PostNewlines are part of the Comment structure
+ but they are not regarded while writing since they could be a part of prenewlines
+ of a following comment.
+ */
+ [[nodiscard]] SpaceTrace findSpacesAroundComment() const
+ {
+ quint32 iPre = m_commentLocation.begin();
int preNewline = 0;
+ int postNewline = 0;
QStringView commentStartStr;
while (iPre > 0) {
- QChar c = code.at(iPre - 1);
+ QChar c = m_code.at(iPre - 1);
if (!c.isSpace()) {
if (commentStartStr.isEmpty() && (c == QLatin1Char('*') || c == QLatin1Char('/'))
- && iPre - 1 > 0 && code.at(iPre - 2) == QLatin1Char('/')) {
- commentStartStr = code.mid(iPre - 2, 2);
+ && iPre - 1 > 0 && m_code.at(iPre - 2) == QLatin1Char('/')) {
+ commentStartStr = m_code.mid(iPre - 2, 2);
--iPre;
} else {
break;
@@ -515,10 +523,10 @@ void AstComments::collectComments(std::shared_ptr<Engine> engine, AST::Node *n,
preNewline = 1;
// possibly add an empty line if it was there (but never more than one)
int i = iPre - 1;
- if (c == QLatin1Char('\n') && i > 0 && code.at(i - 1) == QLatin1Char('\r'))
+ if (c == QLatin1Char('\n') && i > 0 && m_code.at(i - 1) == QLatin1Char('\r'))
--i;
- while (i > 0 && code.at(--i).isSpace()) {
- c = code.at(i);
+ while (i > 0 && m_code.at(--i).isSpace()) {
+ c = m_code.at(i);
if (c == QLatin1Char('\n') || c == QLatin1Char('\r')) {
++preNewline;
break;
@@ -530,194 +538,233 @@ void AstComments::collectComments(std::shared_ptr<Engine> engine, AST::Node *n,
}
if (iPre == 0)
preNewline = 1;
- qsizetype iPost = cLoc.end();
- while (iPost < code.size()) {
- QChar c = code.at(iPost);
+ qsizetype iPost = m_commentLocation.end();
+ while (iPost < m_code.size()) {
+ QChar c = m_code.at(iPost);
if (!c.isSpace()) {
if (!commentStartStr.isEmpty() && commentStartStr.at(1) == QLatin1Char('*')
- && c == QLatin1Char('*') && iPost + 1 < code.size()
- && code.at(iPost + 1) == QLatin1Char('/')) {
+ && c == QLatin1Char('*') && iPost + 1 < m_code.size()
+ && m_code.at(iPost + 1) == QLatin1Char('/')) {
commentStartStr = QStringView();
++iPost;
} else {
break;
}
+ } else {
+ if (c == QLatin1Char('\n')) {
+ ++postNewline;
+ if (iPost + 1 < m_code.size() && m_code.at(iPost + 1) == QLatin1Char('\n')) {
+ ++iPost;
+ ++postNewline;
+ }
+ } else if (c == QLatin1Char('\r')) {
+ if (iPost + 1 < m_code.size() && m_code.at(iPost + 1) == QLatin1Char('\n')) {
+ ++iPost;
+ ++postNewline;
+ }
+ }
}
++iPost;
- if (c == QLatin1Char('\n'))
- break;
- if (c == QLatin1Char('\r')) {
- if (iPost < code.size() && code.at(iPost) == QLatin1Char('\n'))
- ++iPost;
+ if (postNewline > 1)
break;
- }
}
- ElementRef commentEl;
- bool pre = true;
- auto iStart = ranges.starts.lowerBound(cLoc.begin());
- auto iEnd = ranges.ends.lowerBound(cLoc.begin());
- Q_ASSERT(!ranges.ends.isEmpty() && !ranges.starts.isEmpty());
-
- auto checkElementBefore = [&]() {
- if (commentEl)
- return;
- // prefer post comment attached to preceding element
- auto preEnd = iEnd;
- auto preStart = iStart;
- if (preEnd != ranges.ends.begin()) {
- --preEnd;
- if (iStart == ranges.starts.begin() || (--preStart).key() < preEnd.key()) {
- // iStart == begin should never happen
- // check that we do not have operators (or in general other things) between
- // preEnd and this because inserting a newline too ealy might invalidate the
- // expression (think a + //comment\n b ==> a // comment\n + b), in this
- // case attaching as preComment of iStart (b in the example) should be
- // preferred as it is safe
- quint32 i = iPre;
- while (i != 0 && code.at(--i).isSpace())
- ;
- if (i <= preEnd.key() || i < lastPostCommentPostEnd
- || iEnd == ranges.ends.end()) {
- commentEl = preEnd.value();
- pre = false;
- lastPostCommentPostEnd = iPost + 1; // ensure the previous check works
- // with multiple post comments
- }
- }
- }
- };
- auto checkElementAfter = [&]() {
- if (commentEl)
- return;
- if (iStart != ranges.starts.end()) {
- // try to add a pre comment of following element
- if (iEnd == ranges.ends.end() || iEnd.key() > iStart.key()) {
- // there is no end of element before iStart begins
- // associate the comment as preComment of iStart
- // (btw iEnd == end should never happen here)
- commentEl = iStart.value();
- return;
+
+ return {iPre, iPost, preNewline};
+ }
+
+ // tries to associate comment as a postComment to currentElement
+ void checkElementBeforeComment()
+ {
+ if (m_commentedElement)
+ return;
+ // prefer post comment attached to preceding element
+ auto preEnd = m_endElement;
+ auto preStart = m_startElement;
+ if (preEnd != m_ranges.ends.begin()) {
+ --preEnd;
+ if (m_startElement == m_ranges.starts.begin() || (--preStart).key() < preEnd.key()) {
+ // iStart == begin should never happen
+ // check that we do not have operators (or in general other things) between
+ // preEnd and this because inserting a newline too ealy might invalidate the
+ // expression (think a + //comment\n b ==> a // comment\n + b), in this
+ // case attaching as preComment of iStart (b in the example) should be
+ // preferred as it is safe
+ quint32 i = m_spaces.iPre;
+ while (i != 0 && m_code.at(--i).isSpace())
+ ;
+ if (i <= preEnd.key() || i < m_lastPostCommentPostEnd
+ || m_endElement == m_ranges.ends.end()) {
+ m_commentedElement = preEnd.value();
+ m_commentType = Comment::Post;
+ m_lastPostCommentPostEnd = m_spaces.iPost + 1; // ensure the previous check works
+ // with multiple post comments
}
}
- if (iStart == ranges.starts.begin()) {
- Q_ASSERT(iStart != ranges.starts.end());
- // we are before the first node (should be handled already by previous case)
- commentEl = iStart.value();
- }
- };
- auto checkInsideEl = [&]() {
- if (commentEl)
- return;
- auto preIStart = iStart;
- if (iStart == ranges.starts.begin()) {
- commentEl = iStart.value(); // checkElementAfter should have handled this
+ }
+ }
+ // tries to associate comment as a preComment to currentElement
+ void checkElementAfterComment()
+ {
+ if (m_commentedElement)
+ return;
+ if (m_startElement != m_ranges.starts.end()) {
+ // try to add a pre comment of following element
+ if (m_endElement == m_ranges.ends.end() || m_endElement.key() > m_startElement.key()) {
+ // there is no end of element before iStart begins
+ // associate the comment as preComment of iStart
+ // (btw iEnd == end should never happen here)
+ m_commentedElement = m_startElement.value();
return;
- } else {
- --preIStart;
}
- // we are inside a node, actually inside both n1 and n2 (which might be the same)
- // add to pre of the smallest between n1 and n2.
- // This is needed because if there are multiple nodes starting/ending at the same
- // place we store only the first (i.e. largest)
- ElementRef n1 = preIStart.value();
- ElementRef n2 = iEnd.value();
- if (n1.size > n2.size)
- commentEl = n2;
- else
- commentEl = n1;
- };
- if (!preNewline) {
- checkElementBefore();
- checkElementAfter();
- } else {
- checkElementAfter();
- checkElementBefore();
}
- if (!commentEl)
- checkInsideEl();
- if (!commentEl) {
- qCWarning(commentsLog) << "Could not assign comment at" << locationToData(cLoc)
- << "adding before root node";
- if (rootItem && (rootItemLocations || !n)) {
- commentEl.element = RegionRef { Path(), QString() };
- commentEl.size =
- rootItemLocations->info()
- .regions.value(QString(), rootItemLocations->info().fullRegion)
- .length;
- // attach to rootItem
- } else if (n) {
- commentEl.element = n;
- commentEl.size = n->lastSourceLocation().end() - n->firstSourceLocation().begin();
- }
+ if (m_startElement == m_ranges.starts.begin()) {
+ Q_ASSERT(m_startElement != m_ranges.starts.end());
+ // we are before the first node (should be handled already by previous case)
+ m_commentedElement = m_startElement.value();
}
- Comment comment(code.mid(iPre, iPost - iPre), preNewline);
- if (commentEl.element.index() == 0 && std::get<0>(commentEl.element)) {
- CommentedElement &cEl = commentedElements[std::get<0>(commentEl.element)];
- if (pre)
- cEl.preComments.append(comment);
- else
- cEl.postComments.append(comment);
- } else if (commentEl.element.index() == 1) {
- DomItem rComments = rootItem.item()
- .path(std::get<1>(commentEl.element).path)
- .field(Fields::comments);
- if (RegionComments *rCommentsPtr = rComments.mutableAs<RegionComments>()) {
- if (pre)
- rCommentsPtr->addPreComment(comment, std::get<1>(commentEl.element).regionName);
- else
- rCommentsPtr->addPostComment(comment,
- std::get<1>(commentEl.element).regionName);
- } else {
- Q_ASSERT(false);
- }
+ }
+ void checkElementInside()
+ {
+ if (m_commentedElement)
+ return;
+ auto preStart = m_startElement;
+ if (m_startElement == m_ranges.starts.begin()) {
+ m_commentedElement = m_startElement.value(); // checkElementAfter should have handled this
+ return;
} else {
- qCWarning(commentsLog)
- << "Failed: no item or node to attach comment" << comment.rawComment();
+ --preStart;
}
+ // we are inside a node, actually inside both n1 and n2 (which might be the same)
+ // add to pre of the smallest between n1 and n2.
+ // This is needed because if there are multiple nodes starting/ending at the same
+ // place we store only the first (i.e. largest)
+ ElementRef n1 = preStart.value();
+ ElementRef n2 = m_endElement.value();
+ if (n1.size > n2.size)
+ m_commentedElement = n2;
+ else
+ m_commentedElement = n1;
}
-}
+private:
+ QStringView m_code;
+ ElementRef &m_commentedElement;
+ quint32 &m_lastPostCommentPostEnd;
+ Comment::CommentType m_commentType = Comment::Pre;
+ const AstRangesVisitor &m_ranges;
+ const SourceLocation &m_commentLocation;
+
+ using RangesIterator = decltype(m_ranges.starts.begin());
+ const RangesIterator m_startElement;
+ const RangesIterator m_endElement;
+ SpaceTrace m_spaces;
+};
-// internal class to collect all comments in a node or its subnodes
-class CommentCollectorVisitor : protected VisitAll
+/*!
+\class QQmlJS::Dom::AstComments
+\brief Stores the comments associated with javascript AST::Node pointers
+*/
+bool AstComments::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
-public:
- CommentCollectorVisitor(AstComments *comments, AST::Node *n) : comments(comments)
- {
- AST::Node::accept(n, this);
+ // TODO: QTBUG-123645
+ // Revert this commit to reproduce crash with tst_qmldomitem::doNotCrashAtAstComments
+ QList<Comment> pre;
+ QList<Comment> post;
+ for (const auto &commentedElement : commentedElements().values()) {
+ pre.append(commentedElement.preComments());
+ post.append(commentedElement.postComments());
}
+ if (!pre.isEmpty())
+ self.dvWrapField(visitor, Fields::preComments, pre);
+ if (!post.isEmpty())
+ self.dvWrapField(visitor, Fields::postComments, post);
- void throwRecursionDepthError() override { }
-
- bool preVisit(Node *n) override
- {
- auto &cEls = comments->commentedElements();
- if (cEls.contains(n))
- nodeComments += cEls[n].commentGroups(
- combine(n->firstSourceLocation(), n->lastSourceLocation()));
- return true;
- }
+ return false;
+}
- AstComments *comments;
- QMultiMap<quint32, const QList<Comment> *> nodeComments;
-};
+CommentCollector::CommentCollector(MutableDomItem item)
+ : m_rootItem{ std::move(item) },
+ m_fileLocations{ FileLocations::treeOf(m_rootItem.item()) }
+{
+}
-/*!
-\brief low level method returns all comments in a node (including its subnodes)
+void CommentCollector::collectComments()
+{
+ if (std::shared_ptr<ScriptExpression> scriptPtr = m_rootItem.ownerAs<ScriptExpression>()) {
+ return collectComments(scriptPtr->engine(), scriptPtr->ast(), scriptPtr->astComments());
+ } else if (std::shared_ptr<QmlFile> qmlFilePtr = m_rootItem.ownerAs<QmlFile>()) {
+ return collectComments(qmlFilePtr->engine(), qmlFilePtr->ast(), qmlFilePtr->astComments());
+ } else {
+ qCWarning(commentsLog)
+ << "collectComments works with QmlFile and ScriptExpression, not with"
+ << m_rootItem.item().internalKindStr();
+ }
+}
-The comments are roughly ordered in the order they appear in the file.
-Multiple values are in reverse order if the index is even.
+/*! \internal
+ \brief Collects and associates comments with javascript AST::Node pointers
+ or with MutableDomItem
*/
-QMultiMap<quint32, const QList<Comment> *> AstComments::allCommentsInNode(AST::Node *n)
+void CommentCollector::collectComments(
+ const std::shared_ptr<Engine> &engine, AST::Node *rootNode,
+ const std::shared_ptr<AstComments> &astComments)
{
- CommentCollectorVisitor v(this, n);
- return v.nodeComments;
+ if (!rootNode)
+ return;
+ AstRangesVisitor ranges;
+ ranges.addItemRanges(m_rootItem.item(), m_fileLocations, Path());
+ ranges.addNodeRanges(rootNode);
+ QStringView code = engine->code();
+ quint32 lastPostCommentPostEnd = 0;
+ for (const SourceLocation &commentLocation : engine->comments()) {
+ // collect whitespace before and after cLoc -> iPre..iPost contains whitespace,
+ // do not add newline before, but add the one after
+ ElementRef elementToBeLinked;
+ CommentLinker linker(code, elementToBeLinked, ranges, lastPostCommentPostEnd, commentLocation);
+ linker.linkCommentWithElement();
+ const auto comment = linker.createComment();
+
+ if (!elementToBeLinked) {
+ qCWarning(commentsLog) << "Could not assign comment at" << sourceLocationToQCborValue(commentLocation)
+ << "adding before root node";
+ if (m_rootItem && (m_fileLocations || !rootNode)) {
+ elementToBeLinked.element = RegionRef{ Path(), MainRegion };
+ elementToBeLinked.size = FileLocations::region(m_fileLocations, MainRegion).length;
+ } else if (rootNode) {
+ elementToBeLinked.element = rootNode;
+ elementToBeLinked.size = rootNode->lastSourceLocation().end() - rootNode->firstSourceLocation().begin();
+ }
+ }
+
+ if (const auto *const commentNode = std::get_if<AST::Node *>(&elementToBeLinked.element)) {
+ auto &commentedElement = astComments->commentedElements()[*commentNode];
+ commentedElement.addComment(comment);
+ } else if (const auto * const regionRef = std::get_if<RegionRef>(&elementToBeLinked.element)) {
+ MutableDomItem regionComments = m_rootItem.item()
+ .path(regionRef->path)
+ .field(Fields::comments);
+ if (auto *regionCommentsPtr = regionComments.mutableAs<RegionComments>())
+ regionCommentsPtr->addComment(comment, regionRef->regionName);
+ else
+ Q_ASSERT(false && "Cannot attach to region comments");
+ } else {
+ qCWarning(commentsLog)
+ << "Failed: no item or node to attach comment" << comment.rawComment();
+ }
+ }
}
-bool RegionComments::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool RegionComments::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = true;
- if (!regionComments.isEmpty())
- cont = cont && self.dvWrapField(visitor, Fields::regionComments, regionComments);
+ if (!m_regionComments.isEmpty()) {
+ cont = cont
+ && self.dvItemField(visitor, Fields::regionComments, [this, &self]() -> DomItem {
+ const Path pathFromOwner =
+ self.pathFromOwner().field(Fields::regionComments);
+ auto map = Map::fromFileRegionMap(pathFromOwner, m_regionComments);
+ return self.subMapItem(map);
+ });
+ }
return cont;
}
diff --git a/src/qmldom/qqmldomcomments_p.h b/src/qmldom/qqmldomcomments_p.h
index e4f85fa3e3..f8fe46c098 100644
--- a/src/qmldom/qqmldomcomments_p.h
+++ b/src/qmldom/qqmldomcomments_p.h
@@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLDOMCOMMENTS_P_H
#define QQMLDOMCOMMENTS_P_H
@@ -17,7 +17,6 @@
#include "qqmldom_fwd_p.h"
#include "qqmldomconstants_p.h"
-#include "qqmldomfunctionref_p.h"
#include "qqmldomitem_p.h"
#include "qqmldomattachedinfo_p.h"
@@ -39,7 +38,7 @@ class QMLDOM_EXPORT CommentInfo
{
Q_DECLARE_TR_FUNCTIONS(CommentInfo)
public:
- CommentInfo(QStringView);
+ CommentInfo(QStringView, QQmlJS::SourceLocation loc);
QStringView preWhitespace() const { return rawComment.mid(0, commentBegin); }
@@ -55,17 +54,22 @@ public:
return rawComment.mid(commentEnd, rawComment.size() - commentEnd);
}
- quint32 commentBegin;
- quint32 commentEnd;
- quint32 commentContentBegin;
- quint32 commentContentEnd;
+ // Comment source location populated during lexing doesn't include start strings // or /*
+ // Returns the location starting from // or /*
+ QQmlJS::SourceLocation sourceLocation() const { return commentLocation; }
+
+ quint32 commentBegin = 0;
+ quint32 commentEnd = 0;
+ quint32 commentContentBegin = 0;
+ quint32 commentContentEnd = 0;
QStringView commentStartStr;
QStringView commentEndStr;
bool hasStartNewline = false;
bool hasEndNewline = false;
- int nContentNewlines;
+ int nContentNewlines = 0;
QStringView rawComment;
QStringList warnings;
+ QQmlJS::SourceLocation commentLocation;
};
class QMLDOM_EXPORT Comment
@@ -74,21 +78,28 @@ public:
constexpr static DomType kindValue = DomType::Comment;
DomType kind() const { return kindValue; }
- Comment(QString c, int newlinesBefore = 1)
- : m_commentStr(c), m_comment(m_commentStr), m_newlinesBefore(newlinesBefore)
+ enum CommentType {Pre, Post};
+
+ Comment(const QString &c, const QQmlJS::SourceLocation &loc, int newlinesBefore = 1,
+ CommentType type = Pre)
+ : m_comment(c), m_location(loc), m_newlinesBefore(newlinesBefore), m_type(type)
{
}
- Comment(QStringView c, int newlinesBefore = 1) : m_comment(c), m_newlinesBefore(newlinesBefore)
+ Comment(QStringView c, const QQmlJS::SourceLocation &loc, int newlinesBefore = 1,
+ CommentType type = Pre)
+ : m_comment(c), m_location(loc), m_newlinesBefore(newlinesBefore), m_type(type)
{
}
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor);
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const;
int newlinesBefore() const { return m_newlinesBefore; }
void setNewlinesBefore(int n) { m_newlinesBefore = n; }
QStringView rawComment() const { return m_comment; }
- CommentInfo info() const { return CommentInfo(m_comment); }
+ CommentInfo info() const { return CommentInfo(m_comment, m_location); }
void write(OutWriter &lw, SourceLocation *commentLocation = nullptr) const;
+ CommentType type() const { return m_type; }
+
friend bool operator==(const Comment &c1, const Comment &c2)
{
return c1.m_newlinesBefore == c2.m_newlinesBefore && c1.m_comment == c2.m_comment;
@@ -96,9 +107,10 @@ public:
friend bool operator!=(const Comment &c1, const Comment &c2) { return !(c1 == c2); }
private:
- QString m_commentStr;
QStringView m_comment;
+ QQmlJS::SourceLocation m_location;
int m_newlinesBefore;
+ CommentType m_type;
};
class QMLDOM_EXPORT CommentedElement
@@ -107,22 +119,33 @@ public:
constexpr static DomType kindValue = DomType::CommentedElement;
DomType kind() const { return kindValue; }
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor);
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const;
void writePre(OutWriter &lw, QList<SourceLocation> *locations = nullptr) const;
void writePost(OutWriter &lw, QList<SourceLocation> *locations = nullptr) const;
- QMultiMap<quint32, const QList<Comment> *> commentGroups(SourceLocation elLocation) const;
friend bool operator==(const CommentedElement &c1, const CommentedElement &c2)
{
- return c1.preComments == c2.preComments && c1.postComments == c2.postComments;
+ return c1.m_preComments == c2.m_preComments && c1.m_postComments == c2.m_postComments;
}
friend bool operator!=(const CommentedElement &c1, const CommentedElement &c2)
{
return !(c1 == c2);
}
- QList<Comment> preComments;
- QList<Comment> postComments;
+ void addComment(const Comment &comment)
+ {
+ if (comment.type() == Comment::CommentType::Pre)
+ m_preComments.append(comment);
+ else
+ m_postComments.append(comment);
+ }
+
+ const QList<Comment> &preComments() const { return m_preComments;}
+ const QList<Comment> &postComments() const { return m_postComments;}
+
+private:
+ QList<Comment> m_preComments;
+ QList<Comment> m_postComments;
};
class QMLDOM_EXPORT RegionComments
@@ -131,46 +154,56 @@ public:
constexpr static DomType kindValue = DomType::RegionComments;
DomType kind() const { return kindValue; }
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor);
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const;
friend bool operator==(const RegionComments &c1, const RegionComments &c2)
{
- return c1.regionComments == c2.regionComments;
+ return c1.m_regionComments == c2.m_regionComments;
}
friend bool operator!=(const RegionComments &c1, const RegionComments &c2)
{
return !(c1 == c2);
}
- Path addPreComment(const Comment &comment, QString regionName)
+ const QMap<FileLocationRegion, CommentedElement> &regionComments() const { return m_regionComments;}
+ Path addComment(const Comment &comment, FileLocationRegion region)
+ {
+ if (comment.type() == Comment::CommentType::Pre)
+ return addPreComment(comment, region);
+ else
+ return addPostComment(comment, region);
+ }
+
+private:
+ Path addPreComment(const Comment &comment, FileLocationRegion region)
{
- auto &preList = regionComments[regionName].preComments;
+ auto &preList = m_regionComments[region].preComments();
index_type idx = preList.size();
- preList.append(comment);
+ m_regionComments[region].addComment(comment);
return Path::Field(Fields::regionComments)
- .key(regionName)
+ .key(fileLocationRegionName(region))
.field(Fields::preComments)
.index(idx);
}
- Path addPostComment(const Comment &comment, QString regionName)
+ Path addPostComment(const Comment &comment, FileLocationRegion region)
{
- auto &postList = regionComments[regionName].postComments;
+ auto &postList = m_regionComments[region].postComments();
index_type idx = postList.size();
- postList.append(comment);
+ m_regionComments[region].addComment(comment);
return Path::Field(Fields::regionComments)
- .key(regionName)
+ .key(fileLocationRegionName(region))
.field(Fields::postComments)
.index(idx);
}
- QMap<QString, CommentedElement> regionComments;
+ QMap<FileLocationRegion, CommentedElement> m_regionComments;
};
class QMLDOM_EXPORT AstComments final : public OwningItem
{
protected:
- std::shared_ptr<OwningItem> doCopy(DomItem &) const override
+ std::shared_ptr<OwningItem> doCopy(const DomItem &) const override
{
return std::make_shared<AstComments>(*this);
}
@@ -178,18 +211,14 @@ protected:
public:
constexpr static DomType kindValue = DomType::AstComments;
DomType kind() const override { return kindValue; }
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override;
- std::shared_ptr<AstComments> makeCopy(DomItem &self) const
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override;
+ std::shared_ptr<AstComments> makeCopy(const DomItem &self) const
{
return std::static_pointer_cast<AstComments>(doCopy(self));
}
- Path canonicalPath(DomItem &self) const override { return self.m_ownerPath; }
- static void collectComments(MutableDomItem &item);
- static void collectComments(std::shared_ptr<Engine> engine, AST::Node *n,
- std::shared_ptr<AstComments> collectComments,
- MutableDomItem rootItem, FileLocations::Tree rootItemLocations);
- AstComments(std::shared_ptr<Engine> e) : m_engine(e) { }
+ Path canonicalPath(const DomItem &self) const override { return self.m_ownerPath; }
+ AstComments(const std::shared_ptr<Engine> &e) : m_engine(e) { }
AstComments(const AstComments &o)
: OwningItem(o), m_engine(o.m_engine), m_commentedElements(o.m_commentedElements)
{
@@ -199,6 +228,12 @@ public:
{
return m_commentedElements;
}
+
+ QHash<AST::Node *, CommentedElement> &commentedElements()
+ {
+ return m_commentedElements;
+ }
+
CommentedElement *commentForNode(AST::Node *n)
{
if (m_commentedElements.contains(n))
@@ -212,6 +247,20 @@ private:
QHash<AST::Node *, CommentedElement> m_commentedElements;
};
+class CommentCollector
+{
+public:
+ CommentCollector() = default;
+ CommentCollector(MutableDomItem item);
+ void collectComments();
+ void collectComments(const std::shared_ptr<Engine> &engine, AST::Node *rootNode,
+ const std::shared_ptr<AstComments> &astComments);
+
+private:
+ MutableDomItem m_rootItem;
+ FileLocations::Tree m_fileLocations;
+};
+
class VisitAll : public AST::Visitor
{
public:
diff --git a/src/qmldom/qqmldomcompare.cpp b/src/qmldom/qqmldomcompare.cpp
index 92e18944c0..65b357cc75 100644
--- a/src/qmldom/qqmldomcompare.cpp
+++ b/src/qmldom/qqmldomcompare.cpp
@@ -8,8 +8,8 @@ QT_BEGIN_NAMESPACE
namespace QQmlJS {
namespace Dom {
-bool domCompare(DomItem &i1, DomItem &i2, function_ref<bool(Path, DomItem &, DomItem &)> change,
- function_ref<bool(DomItem &, const PathEls::PathComponent &, DomItem &)> filter,
+bool domCompare(const DomItem &i1, const DomItem &i2, function_ref<bool(Path, const DomItem &, const DomItem &)> change,
+ function_ref<bool(const DomItem &, const PathEls::PathComponent &, const DomItem &)> filter,
Path basePath)
{
DomKind k1 = i1.domKind();
@@ -144,21 +144,26 @@ bool domCompare(DomItem &i1, DomItem &i2, function_ref<bool(Path, DomItem &, Dom
if (v1 != v2)
return change(basePath, i1, i2);
} break;
+ case DomKind::ScriptElement: {
+ // TODO: implement me
+ return false;
+
+ } break;
}
}
return true;
}
QStringList
-domCompareStrList(DomItem &i1, DomItem &i2,
- function_ref<bool(DomItem &, const PathEls::PathComponent &, DomItem &)> filter,
+domCompareStrList(const DomItem &i1, const DomItem &i2,
+ function_ref<bool(const DomItem &, const PathEls::PathComponent &, const DomItem &) const> filter,
DomCompareStrList stopAtFirstDiff)
{
QStringList res;
bool hasDiff = false;
domCompare(
i1, i2,
- [&res, &hasDiff, stopAtFirstDiff](Path p, DomItem &j1, DomItem &j2) {
+ [&res, &hasDiff, stopAtFirstDiff](const Path &p, const DomItem &j1, const DomItem &j2) {
hasDiff = true;
if (!j1) {
res.append(QStringLiteral("- %1\n").arg(p.toString()));
@@ -206,6 +211,10 @@ domCompareStrList(DomItem &i1, DomItem &i2,
.arg(j2.toString()));
}
} break;
+ case DomKind::ScriptElement: {
+ // implement me
+ break;
+ }
}
}
}
diff --git a/src/qmldom/qqmldomcompare_p.h b/src/qmldom/qqmldomcompare_p.h
index b15fd562fe..651486d7a9 100644
--- a/src/qmldom/qqmldomcompare_p.h
+++ b/src/qmldom/qqmldomcompare_p.h
@@ -26,20 +26,20 @@ namespace QQmlJS {
namespace Dom {
bool domCompare(
- DomItem &i1, DomItem &i2, function_ref<bool(Path, DomItem &, DomItem &)> change,
- function_ref<bool(DomItem &, const PathEls::PathComponent &, DomItem &)> filter = noFilter,
+ const DomItem &i1, const DomItem &i2, function_ref<bool(Path, const DomItem &, const DomItem &)> change,
+ function_ref<bool(const DomItem &, const PathEls::PathComponent &, const DomItem &)> filter = noFilter,
Path p = Path());
enum DomCompareStrList { FirstDiff, AllDiffs };
QMLDOM_EXPORT QStringList domCompareStrList(
- DomItem &i1, DomItem &i2,
- function_ref<bool(DomItem &, const PathEls::PathComponent &, DomItem &)> filter = noFilter,
+ const DomItem &i1, const DomItem &i2,
+ function_ref<bool(const DomItem &, const PathEls::PathComponent &, const DomItem &) const> filter = noFilter,
DomCompareStrList stopAtFirstDiff = DomCompareStrList::FirstDiff);
inline QStringList domCompareStrList(
- MutableDomItem &i1, DomItem &i2,
- function_ref<bool(DomItem &, const PathEls::PathComponent &, DomItem &)> filter = noFilter,
+ MutableDomItem &i1, const DomItem &i2,
+ function_ref<bool(const DomItem &, const PathEls::PathComponent &, const DomItem &) const> filter = noFilter,
DomCompareStrList stopAtFirstDiff = DomCompareStrList::FirstDiff)
{
DomItem ii1 = i1.item();
@@ -47,8 +47,8 @@ inline QStringList domCompareStrList(
}
inline QStringList domCompareStrList(
- DomItem &i1, MutableDomItem &i2,
- function_ref<bool(DomItem &, const PathEls::PathComponent &, DomItem &)> filter = noFilter,
+ const DomItem &i1, MutableDomItem &i2,
+ function_ref<bool(const DomItem &, const PathEls::PathComponent &, const DomItem &) const> filter = noFilter,
DomCompareStrList stopAtFirstDiff = DomCompareStrList::FirstDiff)
{
DomItem ii2 = i2.item();
@@ -57,7 +57,7 @@ inline QStringList domCompareStrList(
inline QStringList domCompareStrList(
MutableDomItem &i1, MutableDomItem &i2,
- function_ref<bool(DomItem &, const PathEls::PathComponent &, DomItem &)> filter = noFilter,
+ function_ref<bool(const DomItem &, const PathEls::PathComponent &, const DomItem &) const> filter = noFilter,
DomCompareStrList stopAtFirstDiff = DomCompareStrList::FirstDiff)
{
DomItem ii1 = i1.item();
diff --git a/src/qmldom/qqmldomconstants_p.h b/src/qmldom/qqmldomconstants_p.h
index a648379551..ac5f8f67c4 100644
--- a/src/qmldom/qqmldomconstants_p.h
+++ b/src/qmldom/qqmldomconstants_p.h
@@ -101,13 +101,7 @@ Q_ENUM_NS(VisitPrototypesOption)
Q_DECLARE_FLAGS(VisitPrototypesOptions, VisitPrototypesOption)
Q_DECLARE_OPERATORS_FOR_FLAGS(VisitPrototypesOptions)
-enum class DomKind {
- Empty,
- Object,
- List,
- Map,
- Value
-};
+enum class DomKind { Empty, Object, List, Map, Value, ScriptElement };
Q_ENUM_NS(DomKind)
enum class DomType {
@@ -130,7 +124,8 @@ enum class DomType {
// types
EnumDecl, // A in above example
JsResource, // QML file contains QML object, JSFile contains JsResource
- QmltypesComponent, // Component inside a qmltypes fles; compared to component it has exported meta-object revisions; singleton flag; can export multiple names
+ QmltypesComponent, // Component inside a qmltypes fles; compared to component it has exported
+ // meta-object revisions; singleton flag; can export multiple names
QmlComponent, // "normal" QML file based Component; also can represent inline components
GlobalComponent, // component of global object ### REVISIT, try to replace with one of the above
@@ -150,23 +145,29 @@ enum class DomType {
ConstantData, // the 2 in "property int i: 2"; can be any generic data in a QML document
SimpleObjectWrap, // internal wrapping to give uniform DOMItem access; ### research more
ScriptExpression, // wraps an AST script expression as a DOMItem
- Reference, // reference to another DOMItem; e.g. asking for a type of an object returns a Reference
- PropertyDefinition, // _just_ the property definition; without the binding, even if it's one line
+ Reference, // reference to another DOMItem; e.g. asking for a type of an object returns a
+ // Reference
+ PropertyDefinition, // _just_ the property definition; without the binding, even if it's one
+ // line
Binding, // the part after the ":"
MethodParameter,
MethodInfo, // container of MethodParameter
Version, // wrapped
Comment,
CommentedElement, // attached to AST if they have pre-/post-comments?
- RegionComments, // DomItems have attached RegionComments; can attach comments to fine grained "regions" in a DomItem; like the default keyword of a property definition
+ RegionComments, // DomItems have attached RegionComments; can attach comments to fine grained
+ // "regions" in a DomItem; like the default keyword of a property definition
AstComments, // hash-table from AST node to commented element
- FileLocations, // mapping from DomItem to file location ### REVISIT: try to move out of hierarchy?
- UpdatedScriptExpression, // used in writeOut method when formatting changes ### Revisit: try to move out of DOM hierarchy
+ FileLocations, // mapping from DomItem to file location ### REVISIT: try to move out of
+ // hierarchy?
+ UpdatedScriptExpression, // used in writeOut method when formatting changes ### Revisit: try to
+ // move out of DOM hierarchy
// convenience collecting types
PropertyInfo, // not a DOM Item, just a convenience class
- // Moc objects, mainly for testing ### Try to remove them; replace their usage in tests with "real" instances
+ // Moc objects, mainly for testing ### Try to remove them; replace their usage in tests with
+ // "real" instances
MockObject,
MockOwner,
@@ -182,7 +183,54 @@ enum class DomType {
// Dom top level
DomEnvironment, // a consistent view of modules, types, files, etc.
- DomUniverse // a cache of what can be found in the DomEnvironment, contains the latest valid version for every file/type, etc. + latest overall
+ DomUniverse, // a cache of what can be found in the DomEnvironment, contains the latest valid
+ // version for every file/type, etc. + latest overall
+
+ // Dom Script elements
+ // TODO
+ ScriptElementWrap, // internal wrapping to give uniform access of script elements (e.g. for
+ // statement lists)
+ ScriptElementStart, // marker to check if a DomType is a scriptelement or not
+ ScriptBlockStatement = ScriptElementStart,
+ ScriptIdentifierExpression,
+ ScriptLiteral,
+ ScriptForStatement,
+ ScriptIfStatement,
+ ScriptPostExpression,
+ ScriptUnaryExpression,
+ ScriptBinaryExpression,
+ ScriptVariableDeclaration,
+ ScriptVariableDeclarationEntry,
+ ScriptReturnStatement,
+ ScriptGenericElement,
+ ScriptCallExpression,
+ ScriptFormalParameter,
+ ScriptArray,
+ ScriptObject,
+ ScriptProperty,
+ ScriptType,
+ ScriptElision,
+ ScriptArrayEntry,
+ ScriptPattern,
+ ScriptSwitchStatement,
+ ScriptCaseBlock,
+ ScriptCaseClause,
+ ScriptDefaultClause,
+ ScriptWhileStatement,
+ ScriptDoWhileStatement,
+ ScriptForEachStatement,
+ ScriptTryCatchStatement,
+ ScriptThrowStatement,
+ ScriptLabelledStatement,
+ ScriptBreakStatement,
+ ScriptContinueStatement,
+ ScriptConditionalExpression,
+ ScriptEmptyStatement,
+ ScriptParenthesizedExpression,
+ ScriptFunctionExpression,
+ ScriptYieldExpression,
+
+ ScriptElementStop, // marker to check if a DomType is a scriptelement or not
};
Q_ENUM_NS(DomType)
@@ -203,14 +251,6 @@ enum class ListOptions {
};
Q_ENUM_NS(ListOptions)
-enum class LoadOption {
- DefaultLoad = 0x0,
- ForceLoad = 0x1,
-};
-Q_ENUM_NS(LoadOption)
-Q_DECLARE_FLAGS(LoadOptions, LoadOption)
-Q_DECLARE_OPERATORS_FOR_FLAGS(LoadOptions)
-
enum class EscapeOptions{
OuterQuotes,
NoOuterQuotes
@@ -246,6 +286,14 @@ Q_ENUM_NS(GoTo)
enum class AddOption { KeepExisting, Overwrite };
Q_ENUM_NS(AddOption)
+/*!
+\internal
+FilterUpOptions decide in which direction the filtering is done.
+ReturnInner starts the search at top(), and work its way down to the current
+element.
+ReturnOuter and ReturnOuterNoSelf starts the search at the current element and
+works their way up to to top().
+*/
enum class FilterUpOptions { ReturnOuter, ReturnOuterNoSelf, ReturnInner };
Q_ENUM_NS(FilterUpOptions)
@@ -266,22 +314,101 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(WriteOutChecks)
enum class LocalSymbolsType {
None = 0x0,
- QmlTypes = 0x1,
- Types = 0x3,
- Signals = 0x4,
- Methods = 0xC,
- Attributes = 0x10,
- Ids = 0x20,
- Components = 0x40,
- Namespaces = 0x80,
- Globals = 0x100,
- MethodParameters = 0x200,
- All = 0x3FF
+ ObjectType = 0x1,
+ ValueType = 0x2,
+ Signal = 0x4,
+ Method = 0x8,
+ Attribute = 0x10,
+ Id = 0x20,
+ Namespace = 0x40,
+ Global = 0x80,
+ MethodParameter = 0x100,
+ Singleton = 0x200,
+ AttachedType = 0x400,
};
Q_ENUM_NS(LocalSymbolsType)
Q_DECLARE_FLAGS(LocalSymbolsTypes, LocalSymbolsType)
Q_DECLARE_OPERATORS_FOR_FLAGS(LocalSymbolsTypes)
+/*!
+\internal
+The FileLocationRegion allows to map the different FileLocation subregions to their position in
+the actual code. For example, \c{ColonTokenRegion} denotes the position of the ':' token in a
+binding like `myProperty: something()`, or the ':' token in a pragma like `pragma Hello: World`.
+
+These are used for formatting in qmlformat and autocompletion in qmlls.
+
+MainRegion denotes the entire FileLocation region.
+
+\sa{OutWriter::regionToString}, {FileLocations::regionName}
+*/
+enum FileLocationRegion : int {
+ AsTokenRegion,
+ BreakKeywordRegion,
+ DoKeywordRegion,
+ CaseKeywordRegion,
+ CatchKeywordRegion,
+ ColonTokenRegion,
+ CommaTokenRegion,
+ ComponentKeywordRegion,
+ ContinueKeywordRegion,
+ DefaultKeywordRegion,
+ EllipsisTokenRegion,
+ ElseKeywordRegion,
+ EnumKeywordRegion,
+ EnumValueRegion,
+ EqualTokenRegion,
+ ForKeywordRegion,
+ FinallyKeywordRegion,
+ FirstSemicolonTokenRegion,
+ FunctionKeywordRegion,
+ IdColonTokenRegion,
+ IdNameRegion,
+ IdTokenRegion,
+ IdentifierRegion,
+ IfKeywordRegion,
+ ImportTokenRegion,
+ ImportUriRegion,
+ InOfTokenRegion,
+ LeftBraceRegion,
+ LeftBracketRegion,
+ LeftParenthesisRegion,
+ MainRegion,
+ OperatorTokenRegion,
+ OnTargetRegion,
+ OnTokenRegion,
+ PragmaKeywordRegion,
+ PragmaValuesRegion,
+ PropertyKeywordRegion,
+ QuestionMarkTokenRegion,
+ ReadonlyKeywordRegion,
+ RequiredKeywordRegion,
+ ReturnKeywordRegion,
+ RightBraceRegion,
+ RightBracketRegion,
+ RightParenthesisRegion,
+ SecondSemicolonRegion,
+ SemicolonTokenRegion,
+ SignalKeywordRegion,
+ SwitchKeywordRegion,
+ ThrowKeywordRegion,
+ TryKeywordRegion,
+ TypeIdentifierRegion,
+ VersionRegion,
+ WhileKeywordRegion,
+ YieldKeywordRegion,
+};
+Q_ENUM_NS(FileLocationRegion);
+
+enum DomCreationOption : char {
+ None = 0,
+ WithSemanticAnalysis = 1,
+ WithScriptExpressions = 2,
+ WithRecovery = 4
+};
+
+Q_DECLARE_FLAGS(DomCreationOptions, DomCreationOption);
+
} // end namespace Dom
} // end namespace QQmlJS
diff --git a/src/qmldom/qqmldomelements.cpp b/src/qmldom/qqmldomelements.cpp
index 74963aef3b..348984172f 100644
--- a/src/qmldom/qqmldomelements.cpp
+++ b/src/qmldom/qqmldomelements.cpp
@@ -5,6 +5,8 @@
// but in this type of warning, it often isn't.
//#if defined(Q_CC_GNU) && Q_CC_GNU >= 1100
//QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized")
+#include "qqmldomconstants_p.h"
+#include "qqmldompath_p.h"
#if defined(__GNUC__) && __GNUC__ >= 11
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
@@ -43,7 +45,7 @@ namespace Dom {
namespace Paths {
-Path moduleIndexPath(QString uri, int majorVersion, ErrorHandler errorHandler)
+Path moduleIndexPath(const QString &uri, int majorVersion, const ErrorHandler &errorHandler)
{
QString version = QString::number(majorVersion);
if (majorVersion == Version::Latest)
@@ -59,7 +61,7 @@ Path moduleIndexPath(QString uri, int majorVersion, ErrorHandler errorHandler)
return Path::Root(PathRoot::Env).field(Fields::moduleIndexWithUri).key(uri).key(version);
}
-Path moduleScopePath(QString uri, Version version, ErrorHandler)
+Path moduleScopePath(const QString &uri, Version version, const ErrorHandler &)
{
return Path::Root(PathRoot::Env)
.field(Fields::moduleIndexWithUri)
@@ -69,7 +71,7 @@ Path moduleScopePath(QString uri, Version version, ErrorHandler)
.key(version.minorString());
}
-Path moduleScopePath(QString uri, QString version, ErrorHandler errorHandler)
+Path moduleScopePath(const QString &uri, const QString &version, const ErrorHandler &errorHandler)
{
Version v = Version::fromString(version);
if (!version.isEmpty() && !(v.isValid() || v.isLatest()))
@@ -85,25 +87,25 @@ static ErrorGroups domParsingErrors()
return res;
}
-bool CommentableDomElement::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool CommentableDomElement::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = true;
cont = cont && self.dvWrapField(visitor, Fields::comments, m_comments);
return cont;
}
-void Component::updatePathFromOwner(Path newPath)
+void Component::updatePathFromOwner(const Path &newPath)
{
DomElement::updatePathFromOwner(newPath);
updatePathFromOwnerMultiMap(m_enumerations, newPath.field(Fields::enumerations));
updatePathFromOwnerQList(m_objects, newPath.field(Fields::objects));
}
-Component::Component(QString name) : CommentableDomElement(Path()), m_name(name) { }
+Component::Component(const QString &name) : CommentableDomElement(Path()), m_name(name) { }
-Component::Component(Path pathFromOwner) : CommentableDomElement(pathFromOwner) { }
+Component::Component(const Path &pathFromOwner) : CommentableDomElement(pathFromOwner) { }
-bool Component::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool Component::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = CommentableDomElement::iterateDirectSubpaths(self, visitor);
cont = cont && self.dvValueField(visitor, Fields::name, name());
@@ -117,20 +119,13 @@ bool Component::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
return cont;
}
-DomItem Component::field(DomItem &self, QStringView name)
+DomItem Component::field(const DomItem &self, QStringView name) const
{
- switch (name.size()) {
- case 4:
- if (name == Fields::name)
- return self.wrapField(Fields::name, m_name);
- break;
- case 7:
- if (name == Fields::objects)
- return self.wrapField(Fields::objects, m_objects);
- break;
- default:
- break;
- }
+ if (name == Fields::name)
+ return self.wrapField(Fields::name, m_name);
+ if (name == Fields::objects)
+ return self.wrapField(Fields::objects, m_objects);
+
return DomBase::field(self, name);
}
@@ -140,45 +135,50 @@ Path Component::addObject(const QmlObject &object, QmlObject **oPtr)
oPtr);
}
-bool QmlComponent::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool QmlComponent::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = Component::iterateDirectSubpaths(self, visitor);
cont = cont && self.dvWrapField(visitor, Fields::ids, m_ids);
cont = cont && self.dvValueLazyField(visitor, Fields::subComponents, [this, &self]() {
return this->subComponents(self);
});
+ if (m_nameIdentifiers) {
+ cont = cont && self.dvItemField(visitor, Fields::nameIdentifiers, [this, &self]() {
+ return self.subScriptElementWrapperItem(m_nameIdentifiers);
+ });
+ }
return cont;
}
-void QmlComponent::updatePathFromOwner(Path newPath)
+void QmlComponent::updatePathFromOwner(const Path &newPath)
{
Component::updatePathFromOwner(newPath);
updatePathFromOwnerMultiMap(m_ids, newPath.field(Fields::annotations));
}
-void QmlComponent::writeOut(DomItem &self, OutWriter &lw) const
+void QmlComponent::writeOut(const DomItem &self, OutWriter &lw) const
{
if (name().contains(QLatin1Char('.'))) {
// inline component
lw.ensureNewline()
- .writeRegion(u"component")
+ .writeRegion(ComponentKeywordRegion)
.space()
- .writeRegion(u"componentName", name().split(QLatin1Char('.')).last())
- .writeRegion(u"colon", u":")
+ .writeRegion(IdentifierRegion, name().split(QLatin1Char('.')).last())
+ .writeRegion(ColonTokenRegion)
.space();
}
self.field(Fields::objects).index(0).writeOut(lw);
}
-QList<QString> QmlComponent::subComponentsNames(DomItem &self) const
+QList<QString> QmlComponent::subComponentsNames(const DomItem &self) const
{
DomItem components = self.owner().field(Fields::components);
- QSet<QString> cNames = components.keys();
+ const QSet<QString> cNames = components.keys();
QString myNameDot = self.pathFromOwner()[1].headName();
if (!myNameDot.isEmpty())
myNameDot += QLatin1Char('.');
QList<QString> subNames;
- for (QString cName : cNames)
+ for (const QString &cName : cNames)
if (cName.startsWith(myNameDot)
&& !QStringView(cName).mid(myNameDot.size()).contains(QLatin1Char('.'))
&& !cName.isEmpty())
@@ -187,12 +187,12 @@ QList<QString> QmlComponent::subComponentsNames(DomItem &self) const
return subNames;
}
-QList<DomItem> QmlComponent::subComponents(DomItem &self) const
+QList<DomItem> QmlComponent::subComponents(const DomItem &self) const
{
DomItem components = self.owner().field(Fields::components);
QList<DomItem> res;
- for (QString cName : subComponentsNames(self))
- for (DomItem comp : components.key(cName).values())
+ for (const QString &cName : subComponentsNames(self))
+ for (const DomItem &comp : components.key(cName).values())
res.append(comp);
return res;
}
@@ -244,7 +244,7 @@ QString Version::stringValue() const
return QString::number(majorVersion) + QChar::fromLatin1('.') + QString::number(minorVersion);
}
-bool Version::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool Version::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = true;
cont = cont && self.dvWrapField(visitor, Fields::majorVersion, majorVersion);
@@ -264,7 +264,8 @@ QRegularExpression Import::importRe()
return res;
}
-Import Import::fromUriString(QString importStr, Version v, QString importId, ErrorHandler handler)
+Import Import::fromUriString(
+ const QString &importStr, Version v, const QString &importId, const ErrorHandler &handler)
{
auto m = importRe().match(importStr);
if (m.hasMatch()) {
@@ -276,15 +277,21 @@ Import Import::fromUriString(QString importStr, Version v, QString importId, Err
"version %3")
.arg(m.captured(2), importStr, v.stringValue()))
.handle(handler);
- if (importId.isEmpty())
- importId = m.captured(u"importId");
- else if (!m.captured(u"importId").isEmpty())
- domParsingErrors()
- .warning(tr("namespace %1 in import string '%2' overridden by explicit "
- "importId %3")
- .arg(m.captured(u"importId"), importStr, importId))
- .handle(handler);
- return Import(QmlUri::fromUriString(m.captured(u"uri").trimmed()), v, importId);
+ QString resolvedImportId;
+ if (importId.isEmpty()) {
+ resolvedImportId = m.captured(u"importId");
+ } else {
+ if (!m.captured(u"importId").isEmpty()) {
+ domParsingErrors()
+ .warning(tr("namespace %1 in import string '%2' overridden by explicit "
+ "importId %3")
+ .arg(m.captured(u"importId"), importStr, importId))
+ .handle(handler);
+ }
+ resolvedImportId = importId;
+ }
+
+ return Import(QmlUri::fromUriString(m.captured(u"uri").trimmed()), v, resolvedImportId);
}
domParsingErrors()
.error(tr("Unexpected URI format in import '%1'").arg(importStr))
@@ -292,12 +299,13 @@ Import Import::fromUriString(QString importStr, Version v, QString importId, Err
return Import();
}
-Import Import::fromFileString(QString importStr, QString importId, ErrorHandler)
+Import Import::fromFileString(
+ const QString &importStr, const QString &importId, const ErrorHandler &)
{
return Import(QmlUri::fromDirectoryString(importStr), Version(), importId);
}
-bool Import::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool Import::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = true;
cont = cont && self.dvValueField(visitor, Fields::uri, uri.toString());
@@ -310,48 +318,74 @@ bool Import::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
return cont;
}
-void Import::writeOut(DomItem &, OutWriter &ow) const
+void Import::writeOut(const DomItem &self, OutWriter &ow) const
{
if (implicit)
return;
- ow.ensureNewline();
- ow.writeRegion(u"import").space();
- ow.writeRegion(u"uri", uri.toString());
+
+ QString code;
+ const DomItem owner = self.owner();
+ if (std::shared_ptr<QmlFile> qmlFilePtr = self.ownerAs<QmlFile>())
+ code = qmlFilePtr->code();
+
+ // check for an empty line before the import, and preserve it
+ int preNewlines = 0;
+
+ const FileLocations::Tree elLoc = FileLocations::findAttachedInfo(self).foundTree;
+
+ quint32 start = elLoc->info().fullRegion.offset;
+ if (size_t(code.size()) >= start) {
+ while (start != 0) {
+ QChar c = code.at(--start);
+ if (c == u'\n') {
+ if (++preNewlines == 2)
+ break;
+ } else if (!c.isSpace())
+ break;
+ }
+ }
+ if (preNewlines == 0)
+ ++preNewlines;
+
+ ow.ensureNewline(preNewlines);
+ ow.writeRegion(ImportTokenRegion).space();
+ ow.writeRegion(ImportUriRegion, uri.toString());
if (uri.isModule()) {
QString vString = version.stringValue();
if (!vString.isEmpty())
ow.space().write(vString);
}
if (!importId.isEmpty())
- ow.space().writeRegion(u"as").space().writeRegion(u"id", importId);
+ ow.space().writeRegion(AsTokenRegion).space().writeRegion(IdNameRegion, importId);
}
-Id::Id(QString idName, Path referredObject) : name(idName), referredObjectPath(referredObject) { }
+Id::Id(const QString &idName, const Path &referredObject) : name(idName), referredObjectPath(referredObject) { }
-bool Id::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool Id::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = true;
cont = cont && self.dvValueField(visitor, Fields::name, name);
cont = cont && self.dvReferenceField(visitor, Fields::referredObject, referredObjectPath);
cont = cont && self.dvWrapField(visitor, Fields::comments, comments);
cont = cont && self.dvWrapField(visitor, Fields::annotations, annotations);
+ cont = cont && self.dvWrapField(visitor, Fields::value, value);
return cont;
}
-void Id::updatePathFromOwner(Path newPath)
+void Id::updatePathFromOwner(const Path &newPath)
{
updatePathFromOwnerQList(annotations, newPath.field(Fields::annotations));
}
-Path Id::addAnnotation(Path selfPathFromOwner, const QmlObject &annotation, QmlObject **aPtr)
+Path Id::addAnnotation(const Path &selfPathFromOwner, const QmlObject &annotation, QmlObject **aPtr)
{
return appendUpdatableElementInQList(selfPathFromOwner.field(Fields::annotations), annotations,
annotation, aPtr);
}
-QmlObject::QmlObject(Path pathFromOwner) : CommentableDomElement(pathFromOwner) { }
+QmlObject::QmlObject(const Path &pathFromOwner) : CommentableDomElement(pathFromOwner) { }
-bool QmlObject::iterateBaseDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool QmlObject::iterateBaseDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = CommentableDomElement::iterateDirectSubpaths(self, visitor);
if (!idStr().isEmpty())
@@ -369,13 +403,18 @@ bool QmlObject::iterateBaseDirectSubpaths(DomItem &self, DirectVisitor visitor)
cont = cont && self.dvItemField(visitor, Fields::propertyInfos, [this, &self]() {
return self.subMapItem(Map(
pathFromOwner().field(Fields::propertyInfos),
- [&self](DomItem &map, QString k) {
+ [&self](const DomItem &map, const QString &k) {
auto pInfo = self.propertyInfoWithName(k);
return map.wrap(PathEls::Key(k), pInfo);
},
- [&self](DomItem &) { return self.propertyInfoNames(); },
+ [&self](const DomItem &) { return self.propertyInfoNames(); },
QLatin1String("PropertyInfo")));
});
+ if (m_nameIdentifiers) {
+ cont = cont && self.dvItemField(visitor, Fields::nameIdentifiers, [this, &self]() {
+ return self.subScriptElementWrapperItem(m_nameIdentifiers);
+ });
+ }
return cont;
}
@@ -391,7 +430,7 @@ QList<QString> QmlObject::fields() const
return myFields;
}
-bool QmlObject::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool QmlObject::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = iterateBaseDirectSubpaths(self, visitor);
cont = cont && self.dvValueLazyField(visitor, Fields::defaultPropertyName, [this, &self]() {
@@ -400,91 +439,65 @@ bool QmlObject::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
return cont;
}
-DomItem QmlObject::field(DomItem &self, QStringView name)
+DomItem QmlObject::field(const DomItem &self, QStringView name) const
{
- switch (name.size()) {
- case 4:
- if (name == Fields::name)
- return self.subDataItem(PathEls::Field(Fields::name), this->name());
- break;
- case 5:
- if (name == Fields::idStr) {
- if (idStr().isEmpty())
- return DomItem();
- return self.subDataItem(PathEls::Field(Fields::idStr), idStr());
- }
- break;
- case 7:
- if (name == Fields::methods)
- return self.wrapField(Fields::methods, m_methods);
- break;
- case 8:
- switch (name.at(1).unicode()) {
- case u'i':
- if (name == Fields::bindings)
- return self.wrapField(Fields::bindings, m_bindings);
- break;
- case u'o':
- if (name == Fields::comments)
- return CommentableDomElement::field(self, name);
- break;
- case u'h':
- if (name == Fields::children)
- return self.wrapField(Fields::children, m_children);
- break;
- default:
- break;
- }
- break;
- case 9:
- if (name == Fields::nextScope) {
- if (nextScopePath())
- return self.subReferenceItem(PathEls::Field(Fields::nextScope), nextScopePath());
- else
- return DomItem();
- }
- break;
- case 10:
- if (name == Fields::prototypes) {
- if (prototypePaths().isEmpty())
- return DomItem();
- return self.subReferencesItem(PathEls::Field(Fields::prototypes), m_prototypePaths);
- }
- break;
- case 11:
- if (name == Fields::annotations)
- return self.wrapField(Fields::annotations, m_annotations);
- break;
- case 12:
+ if (name == Fields::name)
+ return self.subDataItem(PathEls::Field(Fields::name), this->name());
+ if (name == Fields::idStr) {
+ if (idStr().isEmpty())
+ return DomItem();
+ return self.subDataItem(PathEls::Field(Fields::idStr), idStr());
+ }
+ if (name == Fields::methods)
+ return self.wrapField(Fields::methods, m_methods);
+ if (name == Fields::bindings)
+ return self.wrapField(Fields::bindings, m_bindings);
+ if (name == Fields::comments)
+ return CommentableDomElement::field(self, name);
+ if (name == Fields::children)
+ return self.wrapField(Fields::children, m_children);
+
+ if (name == Fields::nextScope) {
+ if (nextScopePath())
+ return self.subReferenceItem(PathEls::Field(Fields::nextScope), nextScopePath());
+ else
+ return DomItem();
+ }
+ if (name == Fields::prototypes) {
+ if (prototypePaths().isEmpty())
+ return DomItem();
+ return self.subReferencesItem(PathEls::Field(Fields::prototypes), m_prototypePaths);
+ }
+ if (name == Fields::annotations)
+ return self.wrapField(Fields::annotations, m_annotations);
+ if (name == Fields::propertyDefs)
return self.wrapField(Fields::propertyDefs, m_propertyDefs);
- break;
- case 13:
- if (name == Fields::propertyInfos)
- return self.subMapItem(Map(
- pathFromOwner().field(Fields::propertyInfos),
- [self](DomItem &map, QString k) mutable {
- auto pInfo = self.propertyInfoWithName(k);
- return map.wrap(PathEls::Key(k), pInfo);
- },
- [self](DomItem &) mutable { return self.propertyInfoNames(); },
- QLatin1String("PropertyInfo")));
- break;
- case 19:
- if (name == Fields::defaultPropertyName)
- return self.subDataItem(PathEls::Field(Fields::defaultPropertyName),
- defaultPropertyName(self));
- break;
- default:
- break;
+ if (name == Fields::propertyInfos) {
+ // Need to explicitly copy self here since we might store this and call it later.
+ return self.subMapItem(Map(
+ pathFromOwner().field(Fields::propertyInfos),
+ [copiedSelf = self](const DomItem &map, const QString &k) {
+ return map.wrap(PathEls::Key(k), copiedSelf.propertyInfoWithName(k));
+ },
+ [copiedSelf = self](const DomItem &) { return copiedSelf.propertyInfoNames(); },
+ QLatin1String("PropertyInfo")));
+ }
+ if (name == Fields::nameIdentifiers && m_nameIdentifiers) {
+ return self.subScriptElementWrapperItem(m_nameIdentifiers);
+ }
+ if (name == Fields::defaultPropertyName) {
+ return self.subDataItem(PathEls::Field(Fields::defaultPropertyName),
+ defaultPropertyName(self));
}
static QStringList knownLookups({ QString::fromUtf16(Fields::fileLocationsTree) });
- if (!knownLookups.contains(name))
+ if (!knownLookups.contains(name)) {
qCWarning(domLog()) << "Asked non existing field " << name << " in QmlObject "
<< pathFromOwner();
+ }
return DomItem();
}
-void QmlObject::updatePathFromOwner(Path newPath)
+void QmlObject::updatePathFromOwner(const Path &newPath)
{
DomElement::updatePathFromOwner(newPath);
updatePathFromOwnerMultiMap(m_propertyDefs, newPath.field(Fields::propertyDefs));
@@ -504,14 +517,14 @@ QString QmlObject::localDefaultPropertyName() const
return QString();
}
-QString QmlObject::defaultPropertyName(DomItem &self) const
+QString QmlObject::defaultPropertyName(const DomItem &self) const
{
QString dProp = localDefaultPropertyName();
if (!dProp.isEmpty())
return dProp;
QString res = QStringLiteral(u"data");
self.visitPrototypeChain(
- [&res](DomItem &obj) {
+ [&res](const DomItem &obj) {
if (const QmlObject *objPtr = obj.as<QmlObject>()) {
QString dProp = objPtr->localDefaultPropertyName();
if (!dProp.isEmpty()) {
@@ -525,10 +538,10 @@ QString QmlObject::defaultPropertyName(DomItem &self) const
return res;
}
-bool QmlObject::iterateSubOwners(DomItem &self, function_ref<bool(DomItem &)> visitor) const
+bool QmlObject::iterateSubOwners(const DomItem &self, function_ref<bool(const DomItem &)> visitor) const
{
- bool cont = self.field(Fields::bindings).visitKeys([visitor](QString, DomItem &bs) {
- return bs.visitIndexes([visitor](DomItem &b) {
+ bool cont = self.field(Fields::bindings).visitKeys([visitor](const QString &, const DomItem &bs) {
+ return bs.visitIndexes([visitor](const DomItem &b) {
DomItem v = b.field(Fields::value);
if (std::shared_ptr<ScriptExpression> vPtr = v.ownerAs<ScriptExpression>()) {
if (!visitor(v))
@@ -538,7 +551,7 @@ bool QmlObject::iterateSubOwners(DomItem &self, function_ref<bool(DomItem &)> vi
return true;
});
});
- cont = cont && self.field(Fields::children).visitIndexes([visitor](DomItem &qmlObj) {
+ cont = cont && self.field(Fields::children).visitIndexes([visitor](const DomItem &qmlObj) {
if (const QmlObject *qmlObjPtr = qmlObj.as<QmlObject>()) {
return qmlObjPtr->iterateSubOwners(qmlObj, visitor);
}
@@ -548,7 +561,7 @@ bool QmlObject::iterateSubOwners(DomItem &self, function_ref<bool(DomItem &)> vi
return cont;
}
-static QStringList dotExpressionToList(std::shared_ptr<ScriptExpression> expr)
+static QStringList dotExpressionToList(const std::shared_ptr<ScriptExpression> &expr)
{
QStringList res;
AST::Node *node = (expr ? expr->ast() : nullptr);
@@ -574,14 +587,14 @@ static QStringList dotExpressionToList(std::shared_ptr<ScriptExpression> expr)
return res;
}
-LocallyResolvedAlias QmlObject::resolveAlias(DomItem &self,
+LocallyResolvedAlias QmlObject::resolveAlias(const DomItem &self,
std::shared_ptr<ScriptExpression> accessSequence) const
{
QStringList accessSequenceList = dotExpressionToList(accessSequence);
return resolveAlias(self, accessSequenceList);
}
-LocallyResolvedAlias QmlObject::resolveAlias(DomItem &self, const QStringList &accessSequence) const
+LocallyResolvedAlias QmlObject::resolveAlias(const DomItem &self, const QStringList &accessSequence) const
{
LocallyResolvedAlias res;
QSet<QString> visitedAlias;
@@ -669,8 +682,8 @@ LocallyResolvedAlias QmlObject::resolveAlias(DomItem &self, const QStringList &a
return res;
}
-MutableDomItem QmlObject::addPropertyDef(MutableDomItem &self, PropertyDefinition propertyDef,
- AddOption option)
+MutableDomItem QmlObject::addPropertyDef(
+ MutableDomItem &self, const PropertyDefinition &propertyDef, AddOption option)
{
Path p = addPropertyDef(propertyDef, option);
if (p.last().headIndex(0) > 1)
@@ -688,7 +701,8 @@ MutableDomItem QmlObject::addBinding(MutableDomItem &self, Binding binding, AddO
return self.owner().path(p);
}
-MutableDomItem QmlObject::addMethod(MutableDomItem &self, MethodInfo functionDef, AddOption option)
+MutableDomItem QmlObject::addMethod(
+ MutableDomItem &self, const MethodInfo &functionDef, AddOption option)
{
Path p = addMethod(functionDef, option);
if (p.last().headIndex(0) > 1)
@@ -697,7 +711,7 @@ MutableDomItem QmlObject::addMethod(MutableDomItem &self, MethodInfo functionDef
return self.owner().path(p);
}
-void QmlObject::writeOut(DomItem &self, OutWriter &ow, QString onTarget) const
+void QmlObject::writeOut(const DomItem &self, OutWriter &ow, const QString &onTarget) const
{
const quint32 posOfNewElements = std::numeric_limits<quint32>::max();
bool isRootObject = pathFromOwner().length() == 5
@@ -707,10 +721,10 @@ void QmlObject::writeOut(DomItem &self, OutWriter &ow, QString onTarget) const
DomItem owner = self.owner();
if (std::shared_ptr<QmlFile> qmlFilePtr = self.ownerAs<QmlFile>())
code = qmlFilePtr->code();
- ow.writeRegion(u"name", name());
+ ow.writeRegion(IdentifierRegion, name());
if (!onTarget.isEmpty())
- ow.space().writeRegion(u"on", u"on").space().writeRegion(u"onTarget", onTarget).space();
- ow.writeRegion(u"leftBrace", u" {").newline();
+ ow.space().writeRegion(OnTokenRegion).space().writeRegion(OnTargetRegion, onTarget);
+ ow.writeRegion(LeftBraceRegion, u" {");
int baseIndent = ow.increaseIndent();
int spacerId = 0;
if (!idStr().isEmpty()) { // *always* put id first
@@ -718,22 +732,24 @@ void QmlObject::writeOut(DomItem &self, OutWriter &ow, QString onTarget) const
if (myId)
myId.writeOutPre(ow);
ow.ensureNewline()
- .writeRegion(u"idToken", u"id")
- .writeRegion(u"idColon", u":")
+ .writeRegion(IdTokenRegion)
+ .writeRegion(IdColonTokenRegion)
.space()
- .writeRegion(u"id", idStr());
+ .writeRegion(IdNameRegion, idStr());
if (ow.lineWriter.options().attributesSequence
== LineWriterOptions::AttributesSequence::Normalize) {
ow.ensureNewline(2);
}
- if (myId)
+ if (myId) {
myId.writeOutPost(ow);
+ ow.ensureNewline(1);
+ }
}
quint32 counter = ow.counter();
DomItem component;
if (isRootObject)
component = self.containingObject();
- auto startLoc = [&](FileLocations::Tree l) {
+ auto startLoc = [&](const FileLocations::Tree &l) {
if (l)
return l->info().fullRegion;
return SourceLocation(posOfNewElements, 0, 0, 0);
@@ -746,13 +762,16 @@ void QmlObject::writeOut(DomItem &self, OutWriter &ow, QString onTarget) const
FileLocations::Tree componentLoc;
if (isRootObject && objLoc.foundTree)
componentLoc = objLoc.foundTree->parent()->parent();
- auto addMMap = [&attribs, &startLoc](DomItem &base, FileLocations::Tree baseLoc) {
+ auto addMMap
+ = [&attribs, &startLoc](const DomItem &base, const FileLocations::Tree &baseLoc) {
if (!base)
return;
- for (auto els : base.values()) {
+ const auto values = base.values();
+ for (const auto &els : values) {
FileLocations::Tree elsLoc =
FileLocations::find(baseLoc, els.pathFromOwner().last());
- for (auto el : els.values()) {
+ const auto elsValues = els.values();
+ for (const auto &el : elsValues) {
FileLocations::Tree elLoc =
FileLocations::find(elsLoc, el.pathFromOwner().last());
attribs.append(std::make_pair(startLoc(elLoc), el));
@@ -763,10 +782,12 @@ void QmlObject::writeOut(DomItem &self, OutWriter &ow, QString onTarget) const
DomItem base = this->field(self, fieldName);
addMMap(base, FileLocations::find(objLoc.foundTree, base.pathFromOwner().last()));
};
- auto addSingleLevel = [&attribs, &startLoc](DomItem &base, FileLocations::Tree baseLoc) {
+ auto addSingleLevel
+ = [&attribs, &startLoc](const DomItem &base, const FileLocations::Tree &baseLoc) {
if (!base)
return;
- for (auto el : base.values()) {
+ const auto baseValues = base.values();
+ for (const auto &el : baseValues) {
FileLocations::Tree elLoc = FileLocations::find(baseLoc, el.pathFromOwner().last());
attribs.append(std::make_pair(startLoc(elLoc), el));
}
@@ -783,7 +804,7 @@ void QmlObject::writeOut(DomItem &self, OutWriter &ow, QString onTarget) const
FileLocations::find(objLoc.foundTree, children.pathFromOwner().last()));
if (isRootObject) {
DomItem subCs = component.field(Fields::subComponents);
- for (DomItem &c : subCs.values()) {
+ for (const DomItem &c : subCs.values()) {
AttachedInfoLookupResult<FileLocations::Tree> subLoc =
FileLocations::findAttachedInfo(c);
Q_ASSERT(subLoc.foundTree);
@@ -839,16 +860,17 @@ void QmlObject::writeOut(DomItem &self, OutWriter &ow, QString onTarget) const
else {
qWarning() << "Internal error casting binding to Binding in"
<< b.canonicalPath();
- ow.writeRegion(u"leftBrace", u"{").writeRegion(u"rightBrace", u"}");
+ ow.writeRegion(LeftBraceRegion).writeRegion(RightBraceRegion);
}
b.writeOutPost(ow);
}
} else {
el.second.writeOut(ow);
}
+ ow.ensureNewline();
}
ow.decreaseIndent(1, baseIndent);
- ow.ensureNewline().write(u"}");
+ ow.writeRegion(RightBraceRegion);
return;
}
@@ -856,8 +878,10 @@ void QmlObject::writeOut(DomItem &self, OutWriter &ow, QString onTarget) const
DomItem propertyDefs = field(self, Fields::propertyDefs);
if (isRootObject) {
- for (auto enumDescs : component.field(Fields::enumerations).values()) {
- for (auto enumDesc : enumDescs.values()) {
+ const auto descs = component.field(Fields::enumerations).values();
+ for (const auto &enumDescs : descs) {
+ const auto values = enumDescs.values();
+ for (const auto &enumDesc : values) {
ow.ensureNewline(1);
enumDesc.writeOut(ow);
ow.ensureNewline(1);
@@ -868,14 +892,14 @@ void QmlObject::writeOut(DomItem &self, OutWriter &ow, QString onTarget) const
spacerId = ow.addNewlinesAutospacerCallback(2);
QSet<QString> mergedDefBinding;
for (const QString &defName : propertyDefs.sortedKeys()) {
- auto pDefs = propertyDefs.key(defName).values();
- for (auto pDef : pDefs) {
+ const auto pDefs = propertyDefs.key(defName).values();
+ for (const auto &pDef : pDefs) {
const PropertyDefinition *pDefPtr = pDef.as<PropertyDefinition>();
Q_ASSERT(pDefPtr);
DomItem b;
bool uniqueDeclarationWithThisName = pDefs.size() == 1;
if (uniqueDeclarationWithThisName && !pDefPtr->isRequired)
- bindings.key(pDef.name()).visitIndexes([&b, pDefPtr](DomItem &el) {
+ bindings.key(pDef.name()).visitIndexes([&b, pDefPtr](const DomItem &el) {
const Binding *elPtr = el.as<Binding>();
if (elPtr && elPtr->bindingType() == BindingType::Normal) {
switch (elPtr->valueKind()) {
@@ -911,7 +935,7 @@ void QmlObject::writeOut(DomItem &self, OutWriter &ow, QString onTarget) const
else {
qWarning() << "Internal error casting binding to Binding in"
<< b.canonicalPath();
- ow.writeRegion(u"leftBrace", u"{").writeRegion(u"rightBrace", u"}");
+ ow.writeRegion(LeftBraceRegion).writeRegion(RightBraceRegion);
}
b.writeOutPost(ow);
}
@@ -919,8 +943,10 @@ void QmlObject::writeOut(DomItem &self, OutWriter &ow, QString onTarget) const
}
ow.removeTextAddCallback(spacerId);
QList<DomItem> signalList, methodList;
- for (auto ms : field(self, Fields::methods).values()) {
- for (auto m : ms.values()) {
+ const auto fields = field(self, Fields::methods).values();
+ for (const auto &ms : fields) {
+ const auto values = ms.values();
+ for (const auto &m : values) {
const MethodInfo *mPtr = m.as<MethodInfo>();
if (mPtr && mPtr->methodType == MethodInfo::MethodType::Signal)
signalList.append(m);
@@ -930,7 +956,7 @@ void QmlObject::writeOut(DomItem &self, OutWriter &ow, QString onTarget) const
}
if (counter != ow.counter())
spacerId = ow.addNewlinesAutospacerCallback(2);
- for (auto &sig : signalList) {
+ for (const auto &sig : std::as_const(signalList)) {
ow.ensureNewline();
sig.writeOut(ow);
ow.ensureNewline();
@@ -939,7 +965,7 @@ void QmlObject::writeOut(DomItem &self, OutWriter &ow, QString onTarget) const
if (counter != ow.counter())
spacerId = ow.addNewlinesAutospacerCallback(2);
bool first = true;
- for (auto &method : methodList) {
+ for (const auto &method : std::as_const(methodList)) {
if (!first && ow.lineWriter.options().functionsSpacing) {
ow.newline();
}
@@ -950,9 +976,10 @@ void QmlObject::writeOut(DomItem &self, OutWriter &ow, QString onTarget) const
}
ow.removeTextAddCallback(spacerId);
QList<DomItem> normalBindings, signalHandlers, delayedBindings;
- for (auto bName : bindings.sortedKeys()) {
+ for (const auto &bName : bindings.sortedKeys()) {
bool skipFirstNormal = mergedDefBinding.contains(bName);
- for (auto b : bindings.key(bName).values()) {
+ const auto values = bindings.key(bName).values();
+ for (const auto &b : values) {
const Binding *bPtr = b.as<Binding>();
if (skipFirstNormal) {
if (bPtr && bPtr->bindingType() == BindingType::Normal) {
@@ -971,23 +998,24 @@ void QmlObject::writeOut(DomItem &self, OutWriter &ow, QString onTarget) const
}
if (counter != ow.counter())
spacerId = ow.addNewlinesAutospacerCallback(2);
- for (auto &b : normalBindings)
+ for (const auto &b : std::as_const(normalBindings))
b.writeOut(ow);
ow.removeTextAddCallback(spacerId);
if (counter != ow.counter())
spacerId = ow.addNewlinesAutospacerCallback(2);
- for (auto &b : delayedBindings)
+ for (const auto &b : std::as_const(delayedBindings))
b.writeOut(ow);
ow.removeTextAddCallback(spacerId);
if (counter != ow.counter())
spacerId = ow.addNewlinesAutospacerCallback(2);
- for (auto &b : signalHandlers)
+ for (const auto &b : std::as_const(signalHandlers))
b.writeOut(ow);
ow.removeTextAddCallback(spacerId);
if (counter != ow.counter())
spacerId = ow.addNewlinesAutospacerCallback(2);
first = true;
- for (auto c : field(self, Fields::children).values()) {
+ const auto values = field(self, Fields::children).values();
+ for (const auto &c : values) {
if (!first && ow.lineWriter.options().objectsSpacing) {
ow.newline().newline();
}
@@ -1001,27 +1029,30 @@ void QmlObject::writeOut(DomItem &self, OutWriter &ow, QString onTarget) const
DomItem subComps = component.field(Fields::subComponents);
if (counter != ow.counter())
spacerId = ow.addNewlinesAutospacerCallback(2);
- for (auto subC : subComps.values()) {
+ const auto values = subComps.values();
+ for (const auto &subC : values) {
ow.ensureNewline();
subC.writeOut(ow);
}
ow.removeTextAddCallback(spacerId);
}
ow.decreaseIndent(1, baseIndent);
- ow.ensureNewline().write(u"}");
+ ow.ensureNewline().writeRegion(RightBraceRegion);
}
-Binding::Binding(QString name, std::unique_ptr<BindingValue> value, BindingType bindingType)
+Binding::Binding(const QString &name, std::unique_ptr<BindingValue> value, BindingType bindingType)
: m_bindingType(bindingType), m_name(name), m_value(std::move(value))
{
}
-Binding::Binding(QString name, std::shared_ptr<ScriptExpression> value, BindingType bindingType)
+Binding::Binding(
+ const QString &name, const std::shared_ptr<ScriptExpression> &value,
+ BindingType bindingType)
: Binding(name, std::make_unique<BindingValue>(value), bindingType)
{
}
-Binding::Binding(QString name, QString scriptCode, BindingType bindingType)
+Binding::Binding(const QString &name, const QString &scriptCode, BindingType bindingType)
: Binding(name,
std::make_unique<BindingValue>(std::make_shared<ScriptExpression>(
scriptCode, ScriptExpression::ExpressionType::BindingExpression, 0,
@@ -1030,12 +1061,12 @@ Binding::Binding(QString name, QString scriptCode, BindingType bindingType)
{
}
-Binding::Binding(QString name, QmlObject value, BindingType bindingType)
+Binding::Binding(const QString &name, const QmlObject &value, BindingType bindingType)
: Binding(name, std::make_unique<BindingValue>(value), bindingType)
{
}
-Binding::Binding(QString name, QList<QmlObject> value, BindingType bindingType)
+Binding::Binding(const QString &name, const QList<QmlObject> &value, BindingType bindingType)
: Binding(name, std::make_unique<BindingValue>(value), bindingType)
{
}
@@ -1044,7 +1075,8 @@ Binding::Binding(const Binding &o)
: m_bindingType(o.m_bindingType),
m_name(o.m_name),
m_annotations(o.m_annotations),
- m_comments(o.m_comments)
+ m_comments(o.m_comments),
+ m_bindingIdentifiers(o.m_bindingIdentifiers)
{
if (o.m_value) {
m_value = std::make_unique<BindingValue>(*o.m_value);
@@ -1059,6 +1091,7 @@ Binding &Binding::operator=(const Binding &o)
m_bindingType = o.m_bindingType;
m_annotations = o.m_annotations;
m_comments = o.m_comments;
+ m_bindingIdentifiers = o.m_bindingIdentifiers;
if (o.m_value) {
if (!m_value)
m_value = std::make_unique<BindingValue>(*o.m_value);
@@ -1070,7 +1103,7 @@ Binding &Binding::operator=(const Binding &o)
return *this;
}
-bool Binding::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool Binding::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = true;
cont = cont && self.dvValueField(visitor, Fields::name, m_name);
@@ -1089,11 +1122,16 @@ bool Binding::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
cont = cont && self.dvValueLazyField(visitor, Fields::postCode, [this]() {
return this->postCode();
});
+ if (m_bindingIdentifiers) {
+ cont = cont && self.dvItemField(visitor, Fields::bindingIdentifiers, [this, &self]() {
+ return self.subScriptElementWrapperItem(m_bindingIdentifiers);
+ });
+ }
cont = cont && self.dvWrapField(visitor, Fields::annotations, m_annotations);
return cont;
}
-DomItem Binding::valueItem(DomItem &self) const
+DomItem Binding::valueItem(const DomItem &self) const
{
if (!m_value)
return DomItem();
@@ -1149,13 +1187,13 @@ std::shared_ptr<ScriptExpression> Binding::scriptExpressionValue()
return nullptr;
}
-Path Binding::addAnnotation(Path selfPathFromOwner, const QmlObject &annotation, QmlObject **aPtr)
+Path Binding::addAnnotation(const Path &selfPathFromOwner, const QmlObject &annotation, QmlObject **aPtr)
{
return appendUpdatableElementInQList(selfPathFromOwner.field(Fields::annotations),
m_annotations, annotation, aPtr);
}
-void Binding::updatePathFromOwner(Path newPath)
+void Binding::updatePathFromOwner(const Path &newPath)
{
Path base = newPath.field(Fields::annotations);
if (m_value)
@@ -1163,12 +1201,12 @@ void Binding::updatePathFromOwner(Path newPath)
updatePathFromOwnerQList(m_annotations, newPath.field(Fields::annotations));
}
-void Binding::writeOut(DomItem &self, OutWriter &lw) const
+void Binding::writeOut(const DomItem &self, OutWriter &lw) const
{
lw.ensureNewline();
if (m_bindingType == BindingType::Normal) {
- lw.writeRegion(u"name", name());
- lw.writeRegion(u"colon", u":").space();
+ lw.writeRegion(IdentifierRegion, name());
+ lw.writeRegion(ColonTokenRegion).space();
writeOutValue(self, lw);
} else {
DomItem v = valueItem(self);
@@ -1183,7 +1221,7 @@ void Binding::writeOut(DomItem &self, OutWriter &lw) const
}
}
-void Binding::writeOutValue(DomItem &self, OutWriter &lw) const
+void Binding::writeOutValue(const DomItem &self, OutWriter &lw) const
{
DomItem v = valueItem(self);
switch (valueKind()) {
@@ -1205,7 +1243,7 @@ void Binding::writeOutValue(DomItem &self, OutWriter &lw) const
}
}
-bool QmltypesComponent::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool QmltypesComponent::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = Component::iterateDirectSubpaths(self, visitor);
cont = cont && self.dvWrapField(visitor, Fields::exports, m_exports);
@@ -1220,7 +1258,8 @@ bool QmltypesComponent::iterateDirectSubpaths(DomItem &self, DirectVisitor visit
return cont;
}
-Export Export::fromString(Path source, QStringView exp, Path typePath, ErrorHandler h)
+Export Export::fromString(
+ const Path &source, QStringView exp, const Path &typePath, const ErrorHandler &h)
{
Export res;
res.exportSourcePath = source;
@@ -1237,14 +1276,13 @@ Export Export::fromString(Path source, QStringView exp, Path typePath, ErrorHand
"or 'Name major.minor' not '%1'.")
.arg(exp))
.handle(h);
- QString package;
if (slashIdx != -1)
res.uri = exp.left(slashIdx).toString();
res.typeName = exp.mid(slashIdx + 1, spaceIdx - (slashIdx + 1)).toString();
return res;
}
-bool AttributeInfo::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool AttributeInfo::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = true;
cont = cont && self.dvValueField(visitor, Fields::name, name);
@@ -1257,20 +1295,20 @@ bool AttributeInfo::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
return cont;
}
-Path AttributeInfo::addAnnotation(Path selfPathFromOwner, const QmlObject &annotation,
+Path AttributeInfo::addAnnotation(const Path &selfPathFromOwner, const QmlObject &annotation,
QmlObject **aPtr)
{
return appendUpdatableElementInQList(selfPathFromOwner.field(Fields::annotations), annotations,
annotation, aPtr);
}
-void AttributeInfo::updatePathFromOwner(Path newPath)
+void AttributeInfo::updatePathFromOwner(const Path &newPath)
{
Path base = newPath.field(Fields::annotations);
updatePathFromOwnerQList(annotations, newPath.field(Fields::annotations));
}
-bool EnumDecl::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool EnumDecl::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = CommentableDomElement::iterateDirectSubpaths(self, visitor);
cont = cont && self.dvValueField(visitor, Fields::name, name());
@@ -1279,13 +1317,13 @@ bool EnumDecl::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
return cont;
}
-void EnumDecl::updatePathFromOwner(Path newPath)
+void EnumDecl::updatePathFromOwner(const Path &newPath)
{
DomElement::updatePathFromOwner(newPath);
updatePathFromOwnerQList(m_annotations, newPath.field(Fields::annotations));
}
-void EnumDecl::setAnnotations(QList<QmlObject> annotations)
+void EnumDecl::setAnnotations(const QList<QmlObject> &annotations)
{
m_annotations = annotations;
}
@@ -1296,23 +1334,24 @@ Path EnumDecl::addAnnotation(const QmlObject &annotation, QmlObject **aPtr)
annotation, aPtr);
}
-void EnumDecl::writeOut(DomItem &self, OutWriter &ow) const
+void EnumDecl::writeOut(const DomItem &self, OutWriter &ow) const
{
- ow.writeRegion(u"enum", u"enum")
+ ow.writeRegion(EnumKeywordRegion)
.space()
- .writeRegion(u"name", name())
+ .writeRegion(IdentifierRegion, name())
.space()
- .writeRegion(u"lbrace", u"{");
+ .writeRegion(LeftBraceRegion);
int iLevel = ow.increaseIndent(1);
- for (auto value : self.field(Fields::values).values()) {
+ const auto values = self.field(Fields::values).values();
+ for (const auto &value : values) {
ow.ensureNewline();
value.writeOut(ow);
}
ow.decreaseIndent(1, iLevel);
- ow.ensureNewline().writeRegion(u"rbrace", u"}");
+ ow.ensureNewline().writeRegion(RightBraceRegion);
}
-QList<Path> ImportScope::allSources(DomItem &self) const
+QList<Path> ImportScope::allSources(const DomItem &self) const
{
DomItem top = self.top();
DomItem env = top.environment();
@@ -1330,7 +1369,7 @@ QList<Path> ImportScope::allSources(DomItem &self) const
knownPaths.insert(pNow);
res.append(pNow);
DomItem sourceBase = top.path(pNow);
- for (DomItem autoExp : sourceBase.field(Fields::autoExports).values()) {
+ for (const DomItem &autoExp : sourceBase.field(Fields::autoExports).values()) {
if (const ModuleAutoExport *autoExpPtr = autoExp.as<ModuleAutoExport>()) {
Path newSource;
if (autoExpPtr->inheritVersion) {
@@ -1364,14 +1403,14 @@ QList<Path> ImportScope::allSources(DomItem &self) const
return res;
}
-bool ImportScope::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool ImportScope::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = true;
cont = cont && self.dvReferencesField(visitor, Fields::importSources, m_importSourcePaths);
cont = cont && self.dvItemField(visitor, Fields::allSources, [this, &self]() -> DomItem {
return self.subListItem(List::fromQList<Path>(
self.pathFromOwner().field(Fields::allSources), allSources(self),
- [](DomItem &list, const PathEls::PathComponent &p, const Path &el) {
+ [](const DomItem &list, const PathEls::PathComponent &p, const Path &el) {
return list.subDataItem(p, el.toString());
}));
});
@@ -1379,20 +1418,20 @@ bool ImportScope::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
cont = cont && self.dvItemField(visitor, Fields::imported, [this, &self]() -> DomItem {
return self.subMapItem(Map(
self.pathFromOwner().field(Fields::imported),
- [this, &self](DomItem &map, QString key) {
+ [this, &self](const DomItem &map, const QString &key) {
return map.subListItem(List::fromQList<DomItem>(
map.pathFromOwner().key(key), importedItemsWithName(self, key),
- [](DomItem &, const PathEls::PathComponent &, DomItem &el) {
+ [](const DomItem &, const PathEls::PathComponent &, const DomItem &el) {
return el;
}));
},
- [this, &self](DomItem &) { return this->importedNames(self); },
+ [this, &self](const DomItem &) { return this->importedNames(self); },
QLatin1String("List<Export>")));
});
return cont;
}
-bool PropertyInfo::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool PropertyInfo::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = true;
cont = cont && self.dvValueField(visitor, Fields::propertyDefs, propertyDefs);
@@ -1407,7 +1446,7 @@ BindingValue::BindingValue(const QmlObject &o) : kind(BindingValueKind::Object)
new (&object) QmlObject(o);
}
-BindingValue::BindingValue(std::shared_ptr<ScriptExpression> o)
+BindingValue::BindingValue(const std::shared_ptr<ScriptExpression> &o)
: kind(BindingValueKind::ScriptExpression)
{
new (&scriptExpression) std::shared_ptr<ScriptExpression>(o);
@@ -1458,7 +1497,7 @@ BindingValue &BindingValue::operator=(const BindingValue &o)
return *this;
}
-DomItem BindingValue::value(DomItem &binding)
+DomItem BindingValue::value(const DomItem &binding) const
{
switch (kind) {
case BindingValueKind::Empty:
@@ -1470,14 +1509,14 @@ DomItem BindingValue::value(DomItem &binding)
case BindingValueKind::Array:
return binding.subListItem(List::fromQListRef<QmlObject>(
binding.pathFromOwner().field(u"value"), array,
- [binding](DomItem &self, const PathEls::PathComponent &, QmlObject &obj) {
+ [](const DomItem &self, const PathEls::PathComponent &, const QmlObject &obj) {
return self.copy(&obj);
}));
}
return DomItem();
}
-void BindingValue::updatePathFromOwner(Path newPath)
+void BindingValue::updatePathFromOwner(const Path &newPath)
{
switch (kind) {
case BindingValueKind::Empty:
@@ -1511,10 +1550,10 @@ void BindingValue::clearValue()
kind = BindingValueKind::Empty;
}
-ScriptExpression::ScriptExpression(QStringView code, std::shared_ptr<QQmlJS::Engine> engine,
- AST::Node *ast, std::shared_ptr<AstComments> comments,
- ExpressionType expressionType, SourceLocation localOffset,
- int derivedFrom, QStringView preCode, QStringView postCode)
+ScriptExpression::ScriptExpression(
+ QStringView code, const std::shared_ptr<QQmlJS::Engine> &engine, AST::Node *ast,
+ const std::shared_ptr<AstComments> &comments, ExpressionType expressionType,
+ SourceLocation localOffset, int derivedFrom, QStringView preCode, QStringView postCode)
: OwningItem(derivedFrom),
m_expressionType(expressionType),
m_code(code),
@@ -1547,8 +1586,8 @@ ScriptExpression::ScriptExpression(const ScriptExpression &e) : OwningItem(e)
m_astComments = e.m_astComments;
}
-std::shared_ptr<ScriptExpression> ScriptExpression::copyWithUpdatedCode(DomItem &self,
- QString code) const
+std::shared_ptr<ScriptExpression> ScriptExpression::copyWithUpdatedCode(
+ const DomItem &self, const QString &code) const
{
std::shared_ptr<ScriptExpression> copy = makeCopy(self);
DomItem container = self.containingObject();
@@ -1558,7 +1597,7 @@ std::shared_ptr<ScriptExpression> ScriptExpression::copyWithUpdatedCode(DomItem
return copy;
}
-bool ScriptExpression::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool ScriptExpression::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = OwningItem::iterateDirectSubpaths(self, visitor);
cont = cont && self.dvValueField(visitor, Fields::code, code());
@@ -1573,12 +1612,17 @@ bool ScriptExpression::iterateDirectSubpaths(DomItem &self, DirectVisitor visito
cont = cont
&& self.dvValueLazyField(
visitor, Fields::localOffset,
- [this]() { return locationToData(localOffset()); },
+ [this]() { return sourceLocationToQCborValue(localOffset()); },
ConstantData::Options::MapIsMap);
cont = cont && self.dvValueLazyField(visitor, Fields::astRelocatableDump, [this]() {
return astRelocatableDump();
});
cont = cont && self.dvValueField(visitor, Fields::expressionType, int(expressionType()));
+ if (m_element) {
+ cont = cont && self.dvItemField(visitor, Fields::scriptElement, [this, &self]() {
+ return self.subScriptElementWrapperItem(m_element);
+ });
+ }
return cont;
}
@@ -1613,19 +1657,24 @@ AST::Node *firstNodeInRange(AST::Node *n, quint32 minStart = 0, quint32 maxEnd =
return visitor.firstNodeInRange;
}
-void ScriptExpression::setCode(QString code, QString preCode, QString postCode)
+void ScriptExpression::setCode(const QString &code, const QString &preCode, const QString &postCode)
{
+ // TODO QTBUG-121933
m_codeStr = code;
- const bool qmlMode = (m_expressionType == ExpressionType::BindingExpression);
- if (qmlMode && preCode.isEmpty()) {
- preCode = Binding::preCodeForName(u"binding");
- postCode = Binding::postCodeForName(u"binding");
- }
- if (!preCode.isEmpty() || !postCode.isEmpty())
- m_codeStr = preCode + code + postCode;
- m_code = QStringView(m_codeStr).mid(preCode.size(), code.size());
- m_preCode = QStringView(m_codeStr).mid(0, preCode.size());
- m_postCode = QStringView(m_codeStr).mid(preCode.size() + code.size(), postCode.size());
+ QString resolvedPreCode, resolvedPostCode;
+ if (m_expressionType == ExpressionType::BindingExpression && preCode.isEmpty()) {
+ resolvedPreCode = Binding::preCodeForName(u"binding");
+ resolvedPostCode = Binding::postCodeForName(u"binding");
+ } else {
+ resolvedPreCode = preCode;
+ resolvedPostCode = postCode;
+ }
+ if (!resolvedPreCode.isEmpty() || !resolvedPostCode.isEmpty())
+ m_codeStr = resolvedPreCode + code + resolvedPostCode;
+ m_code = QStringView(m_codeStr).mid(resolvedPreCode.size(), code.size());
+ m_preCode = QStringView(m_codeStr).mid(0, resolvedPreCode.size());
+ m_postCode = QStringView(m_codeStr).mid(
+ resolvedPreCode.size() + code.size(), resolvedPostCode.size());
m_engine = nullptr;
m_ast = nullptr;
m_localOffset = SourceLocation();
@@ -1637,26 +1686,17 @@ void ScriptExpression::setCode(QString code, QString preCode, QString postCode)
m_localOffset.startLine = preChange.nNewlines;
m_engine = std::make_shared<QQmlJS::Engine>();
m_astComments = std::make_shared<AstComments>(m_engine);
- QQmlJS::Lexer lexer(m_engine.get());
- lexer.setCode(m_codeStr, /*lineno = */ 1, /*qmlMode=*/true);
- QQmlJS::Parser parser(m_engine.get());
- if ((qmlMode && !parser.parse()) || (!qmlMode && !parser.parseScript()))
- addErrorLocal(domParsingErrors().error(tr("Parsing of code failed")));
- for (DiagnosticMessage msg : parser.diagnosticMessages()) {
- ErrorMessage err = domParsingErrors().errorMessage(msg);
- err.location.offset -= m_localOffset.offset;
- err.location.startLine -= m_localOffset.startLine;
- if (err.location.startLine == 1)
- err.location.startColumn -= m_localOffset.startColumn;
- addErrorLocal(err);
- }
- m_ast = parser.rootNode();
+ m_ast = parse(resolveParseMode());
+
if (AST::Program *programPtr = AST::cast<AST::Program *>(m_ast)) {
m_ast = programPtr->statements;
}
if (!m_preCode.isEmpty())
m_ast = firstNodeInRange(m_ast, m_preCode.size(),
m_preCode.size() + m_code.size());
+ if (auto *sList = AST::cast<AST::FormalParameterList *>(m_ast)) {
+ m_ast = sList->element;
+ }
if (m_expressionType != ExpressionType::FunctionBody) {
if (AST::StatementList *sList = AST::cast<AST::StatementList *>(m_ast)) {
if (!sList->next)
@@ -1666,11 +1706,45 @@ void ScriptExpression::setCode(QString code, QString preCode, QString postCode)
if (m_expressionType == ExpressionType::BindingExpression)
if (AST::ExpressionStatement *exp = AST::cast<AST::ExpressionStatement *>(m_ast))
m_ast = exp->expression;
- AstComments::collectComments(m_engine, m_ast, m_astComments, MutableDomItem(), nullptr);
+
+ CommentCollector collector;
+ collector.collectComments(m_engine, m_ast, m_astComments);
+ }
+}
+
+AST::Node *ScriptExpression::parse(const ParseMode mode)
+{
+ QQmlJS::Lexer lexer(m_engine.get());
+ lexer.setCode(m_codeStr, /*lineno = */ 1, /*qmlMode=*/mode == ParseMode::QML);
+ QQmlJS::Parser parser(m_engine.get());
+ const bool parserSucceeded = [mode, &parser]() {
+ switch (mode) {
+ case ParseMode::QML:
+ return parser.parse();
+ case ParseMode::JS:
+ return parser.parseScript();
+ case ParseMode::ESM:
+ return parser.parseModule();
+ default:
+ Q_UNREACHABLE_RETURN(false);
+ }
+ }();
+ if (!parserSucceeded) {
+ addErrorLocal(domParsingErrors().error(tr("Parsing of code failed")));
+ }
+ const auto messages = parser.diagnosticMessages();
+ for (const DiagnosticMessage &msg : messages) {
+ ErrorMessage err = domParsingErrors().errorMessage(msg);
+ err.location.offset -= m_localOffset.offset;
+ err.location.startLine -= m_localOffset.startLine;
+ if (err.location.startLine == 1)
+ err.location.startColumn -= m_localOffset.startColumn;
+ addErrorLocal(std::move(err));
}
+ return parser.rootNode();
}
-void ScriptExpression::astDumper(Sink s, AstDumperOptions options) const
+void ScriptExpression::astDumper(const Sink &s, AstDumperOptions options) const
{
astNodeDumper(s, ast(), options, 1, 0, [this](SourceLocation astL) {
SourceLocation l = this->locationToLocal(astL);
@@ -1680,12 +1754,12 @@ void ScriptExpression::astDumper(Sink s, AstDumperOptions options) const
QString ScriptExpression::astRelocatableDump() const
{
- return dumperToString([this](Sink s) {
+ return dumperToString([this](const Sink &s) {
this->astDumper(s, AstDumperOption::NoLocations | AstDumperOption::SloppyCompare);
});
}
-void ScriptExpression::writeOut(DomItem &self, OutWriter &lw) const
+void ScriptExpression::writeOut(const DomItem &self, OutWriter &lw) const
{
OutWriter *ow = &lw;
@@ -1695,6 +1769,14 @@ void ScriptExpression::writeOut(DomItem &self, OutWriter &lw) const
QStringView reformattedCode =
QStringView(ow->writtenStr).mid(myLoc.offset, myLoc.length);
if (reformattedCode != code()) {
+ // If some reformatting of the expression took place,
+ // it will be saved as an intermediate step.
+ // then it will be used to restore writtenOut fileItem
+ // in the OutWriter::restoreWrittenFile
+
+ //Interestingly enough, this copyWithUpdatedCode will
+ //instantiate Engine and Parser and will parse "reformattedCode"
+ //because it calls ScriptExpression::setCode function
std::shared_ptr<ScriptExpression> copy =
copyWithUpdatedCode(self, reformattedCode.toString());
ow->addReformattedScriptExpression(self.canonicalPath(), copy);
@@ -1711,10 +1793,10 @@ void ScriptExpression::writeOut(DomItem &self, OutWriter &lw) const
lw.lineWriter.endSourceLocation(*codeLoc);
}
-SourceLocation ScriptExpression::globalLocation(DomItem &self) const
+SourceLocation ScriptExpression::globalLocation(const DomItem &self) const
{
- if (const FileLocations *fLocPtr = FileLocations::fileLocationsPtr(self)) {
- return fLocPtr->regions.value(QString(), fLocPtr->fullRegion);
+ if (const FileLocations::Tree tree = FileLocations::treeOf(self)) {
+ return FileLocations::region(tree, MainRegion);
}
return SourceLocation();
}
@@ -1724,23 +1806,23 @@ bool PropertyDefinition::isParametricType() const
return typeName.contains(QChar(u'<'));
}
-void PropertyDefinition::writeOut(DomItem &, OutWriter &lw) const
+void PropertyDefinition::writeOut(const DomItem &, OutWriter &lw) const
{
lw.ensureNewline();
if (isDefaultMember)
- lw.writeRegion(u"default").space();
+ lw.writeRegion(DefaultKeywordRegion).space();
if (isRequired)
- lw.writeRegion(u"required").space();
+ lw.writeRegion(RequiredKeywordRegion).space();
if (isReadonly)
- lw.writeRegion(u"readonly").space();
+ lw.writeRegion(ReadonlyKeywordRegion).space();
if (!typeName.isEmpty()) {
- lw.writeRegion(u"property").space();
- lw.writeRegion(u"type", typeName).space();
+ lw.writeRegion(PropertyKeywordRegion).space();
+ lw.writeRegion(TypeIdentifierRegion, typeName).space();
}
- lw.writeRegion(u"name", name);
+ lw.writeRegion(IdentifierRegion, name);
}
-bool MethodInfo::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool MethodInfo::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = AttributeInfo::iterateDirectSubpaths(self, visitor);
cont = cont && self.dvWrapField(visitor, Fields::parameters, parameters);
@@ -1752,12 +1834,18 @@ bool MethodInfo::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
cont = cont && self.dvValueField(visitor, Fields::postCode, postCode(self));
cont = cont && self.dvValueField(visitor, Fields::isConstructor, isConstructor);
}
+ if (returnType)
+ cont = cont && self.dvItemField(visitor, Fields::returnType, [this, &self]() {
+ return self.subOwnerItem(PathEls::Field(Fields::returnType), returnType);
+ });
if (body)
- cont = cont && self.dvWrapField(visitor, Fields::body, body);
+ cont = cont && self.dvItemField(visitor, Fields::body, [this, &self]() {
+ return self.subOwnerItem(PathEls::Field(Fields::body), body);
+ });
return cont;
}
-QString MethodInfo::preCode(DomItem &self) const
+QString MethodInfo::preCode(const DomItem &self) const
{
QString res;
LineWriter lw([&res](QStringView s) { res.append(s); }, QLatin1String("*preCode*"));
@@ -1767,41 +1855,41 @@ QString MethodInfo::preCode(DomItem &self) const
MockObject standinObj(self.pathFromOwner());
DomItem standin = self.copy(&standinObj);
ow.itemStart(standin);
- ow.writeRegion(u"function").space().writeRegion(u"name", name);
+ ow.writeRegion(FunctionKeywordRegion).space().writeRegion(IdentifierRegion, name);
bool first = true;
- ow.writeRegion(u"leftParen", u"(");
+ ow.writeRegion(LeftParenthesisRegion);
for (const MethodParameter &mp : parameters) {
if (first)
first = false;
else
ow.write(u", ");
- ow.write(mp.name);
+ ow.write(mp.value->code());
}
- ow.writeRegion(u"rightParen", u")");
- ow.ensureSpace().writeRegion(u"leftBrace", u"{");
+ ow.writeRegion(RightParenthesisRegion);
+ ow.ensureSpace().writeRegion(LeftBraceRegion);
ow.itemEnd(standin);
ow.eof();
return res;
}
-QString MethodInfo::postCode(DomItem &) const
+QString MethodInfo::postCode(const DomItem &) const
{
return QLatin1String("\n}\n");
}
-void MethodInfo::writeOut(DomItem &self, OutWriter &ow) const
+void MethodInfo::writeOut(const DomItem &self, OutWriter &ow) const
{
switch (methodType) {
case MethodType::Signal: {
if (body)
qCWarning(domLog) << "signal should not have a body in" << self.canonicalPath();
- ow.writeRegion(u"signal").space().writeRegion(u"name", name);
+ ow.writeRegion(SignalKeywordRegion).space().writeRegion(IdentifierRegion, name);
if (parameters.isEmpty())
return;
bool first = true;
- ow.writeRegion(u"leftParen", u"(");
+ ow.writeRegion(LeftParenthesisRegion);
int baseIndent = ow.increaseIndent();
- for (DomItem arg : self.field(Fields::parameters).values()) {
+ for (const DomItem &arg : self.field(Fields::parameters).values()) {
if (first)
first = false;
else
@@ -1811,86 +1899,112 @@ void MethodInfo::writeOut(DomItem &self, OutWriter &ow) const
else
qCWarning(domLog) << "failed to cast to MethodParameter";
}
- ow.writeRegion(u"rightParen", u")");
+ ow.writeRegion(RightParenthesisRegion);
ow.decreaseIndent(1, baseIndent);
return;
} break;
case MethodType::Method: {
- ow.writeRegion(u"function").space().writeRegion(u"name", name);
+ ow.writeRegion(FunctionKeywordRegion).space().writeRegion(IdentifierRegion, name);
bool first = true;
- ow.writeRegion(u"leftParen", u"(");
- for (DomItem arg : self.field(Fields::parameters).values()) {
+ ow.writeRegion(LeftParenthesisRegion);
+ for (const DomItem &arg : self.field(Fields::parameters).values()) {
if (first)
first = false;
else
ow.write(u", ");
arg.writeOut(ow);
}
- ow.writeRegion(u"rightParen", u")");
+ ow.writeRegion(RightParenthesisRegion);
if (!typeName.isEmpty()) {
- ow.writeRegion(u"colon", u":");
+ ow.writeRegion(ColonTokenRegion);
ow.space();
- ow.writeRegion(u"returnType", typeName);
+ ow.writeRegion(TypeIdentifierRegion, typeName);
}
- ow.ensureSpace().writeRegion(u"leftBrace", u"{");
+ ow.ensureSpace().writeRegion(LeftBraceRegion);
int baseIndent = ow.increaseIndent();
if (DomItem b = self.field(Fields::body)) {
ow.ensureNewline();
b.writeOut(ow);
}
ow.decreaseIndent(1, baseIndent);
- ow.ensureNewline().writeRegion(u"rightBrace", u"}");
+ ow.ensureNewline().writeRegion(RightBraceRegion);
} break;
}
}
-bool MethodParameter::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool MethodParameter::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = true;
cont = cont && self.dvValueField(visitor, Fields::name, name);
if (!typeName.isEmpty()) {
cont = cont
- && self.dvReferenceField(visitor, Fields::type, Paths::lookupCppTypePath(typeName));
+ && self.dvReferenceField(visitor, Fields::type, Paths::lookupTypePath(typeName));
cont = cont && self.dvValueField(visitor, Fields::typeName, typeName);
}
cont = cont && self.dvValueField(visitor, Fields::isPointer, isPointer);
cont = cont && self.dvValueField(visitor, Fields::isReadonly, isReadonly);
cont = cont && self.dvValueField(visitor, Fields::isList, isList);
cont = cont && self.dvWrapField(visitor, Fields::defaultValue, defaultValue);
+ cont = cont && self.dvWrapField(visitor, Fields::value, value);
+
+ cont = cont && self.dvValueField(visitor, Fields::preCode, u"function f("_s);
+ cont = cont && self.dvValueField(visitor, Fields::postCode, u") {}"_s);
+
if (!annotations.isEmpty())
cont = cont && self.dvWrapField(visitor, Fields::annotations, annotations);
cont = cont && self.dvWrapField(visitor, Fields::comments, comments);
return cont;
}
-void MethodParameter::writeOut(DomItem &self, OutWriter &ow) const
+void MethodParameter::writeOut(const DomItem &self, OutWriter &ow) const
{
- ow.writeRegion(u"name", name);
- if (!typeName.isEmpty())
- ow.writeRegion(u"colon", u":").space().writeRegion(u"type", typeName);
- if (defaultValue) {
- ow.space().writeRegion(u"equal", u"=").space();
- self.subOwnerItem(PathEls::Field(Fields::defaultValue), defaultValue).writeOut(ow);
+ if (!name.isEmpty()) {
+ if (isRestElement)
+ ow.writeRegion(EllipsisTokenRegion);
+ ow.writeRegion(IdentifierRegion, name);
+ if (!typeName.isEmpty())
+ ow.writeRegion(ColonTokenRegion).space().writeRegion(TypeIdentifierRegion, typeName);
+ if (defaultValue) {
+ ow.space().writeRegion(EqualTokenRegion).space();
+ self.subOwnerItem(PathEls::Field(Fields::defaultValue), defaultValue).writeOut(ow);
+ }
+ } else {
+ if (value) {
+ self.subOwnerItem(PathEls::Field(Fields::value), value).writeOut(ow);
+ }
}
}
-void MethodParameter::writeOutSignal(DomItem &self, OutWriter &ow) const
+void MethodParameter::writeOutSignal(const DomItem &self, OutWriter &ow) const
{
self.writeOutPre(ow);
if (!typeName.isEmpty())
- ow.writeRegion(u"type", typeName).space();
- ow.writeRegion(u"name", name);
+ ow.writeRegion(TypeIdentifierRegion, typeName).space();
+ ow.writeRegion(IdentifierRegion, name);
self.writeOutPost(ow);
}
-void Pragma::writeOut(DomItem &, OutWriter &ow) const
+void Pragma::writeOut(const DomItem &, OutWriter &ow) const
{
ow.ensureNewline();
- ow.writeRegion(u"pragma").space().writeRegion(u"name", name);
+ ow.writeRegion(PragmaKeywordRegion).space().writeRegion(IdentifierRegion, name);
+
+ bool isFirst = true;
+ for (const auto &value : values) {
+ if (isFirst) {
+ isFirst = false;
+ ow.writeRegion(ColonTokenRegion).space();
+ ow.writeRegion(PragmaValuesRegion, value);
+ continue;
+ }
+
+ ow.writeRegion(CommaTokenRegion).space();
+ ow.writeRegion(PragmaValuesRegion, value);
+ }
ow.ensureNewline();
}
-bool EnumItem::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool EnumItem::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = true;
cont = cont && self.dvValueField(visitor, Fields::name, name());
@@ -1899,30 +2013,19 @@ bool EnumItem::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
return cont;
}
-void EnumItem::writeOut(DomItem &self, OutWriter &ow) const
+void EnumItem::writeOut(const DomItem &self, OutWriter &ow) const
{
ow.ensureNewline();
- ow.writeRegion(u"name", name());
- bool hasDefaultValue = false;
+ ow.writeRegion(IdentifierRegion, name());
index_type myIndex = self.pathFromOwner().last().headIndex();
- if (myIndex == 0)
- hasDefaultValue = value() == 0;
- else if (myIndex > 0)
- hasDefaultValue = value()
- == self.container()
- .index(myIndex - 1)
- .field(Fields::value)
- .value()
- .toDouble(value())
- + 1;
- if (!hasDefaultValue) {
+ if (m_valueKind == ValueKind::ExplicitValue) {
QString v = QString::number(value(), 'f', 0);
if (abs(value() - v.toDouble()) > 1.e-10)
v = QString::number(value());
- ow.space().writeRegion(u"equal", u"=").space().writeRegion(u"value", v);
+ ow.space().writeRegion(EqualTokenRegion).space().writeRegion(EnumValueRegion, v);
}
if (myIndex >= 0 && self.container().indexes() != myIndex + 1)
- ow.writeRegion(u"comma", u",");
+ ow.writeRegion(CommaTokenRegion);
}
QmlUri QmlUri::fromString(const QString &str)
@@ -2069,6 +2172,11 @@ QmlUri::Kind QmlUri::kind() const
return m_kind;
}
+void ScriptExpression::setScriptElement(const ScriptElementVariant &p)
+{
+ m_element = p;
+}
+
} // end namespace Dom
} // end namespace QQmlJS
diff --git a/src/qmldom/qqmldomelements_p.h b/src/qmldom/qqmldomelements_p.h
index cbf22a0018..95cddbbc32 100644
--- a/src/qmldom/qqmldomelements_p.h
+++ b/src/qmldom/qqmldomelements_p.h
@@ -22,17 +22,15 @@
#include <QtQml/private/qqmljsast_p.h>
#include <QtQml/private/qqmljsengine_p.h>
+#include <QtQml/private/qqmlsignalnames_p.h>
#include <QtCore/QCborValue>
#include <QtCore/QCborMap>
#include <QtCore/QMutexLocker>
#include <QtCore/QPair>
-#ifdef QMLDOM_STANDALONE
-# include "qmlcompiler/qqmljsscope_p.h"
-#else
-# include <private/qqmljsscope_p.h>
-#endif
+#include <memory>
+#include <private/qqmljsscope_p.h>
#include <functional>
#include <limits>
@@ -45,38 +43,42 @@ namespace Dom {
// namespace for utility methods building specific paths
// using a namespace one can reopen it and add more methods in other places
namespace Paths {
-Path moduleIndexPath(QString uri, int majorVersion, ErrorHandler errorHandler = nullptr);
-Path moduleScopePath(QString uri, Version version, ErrorHandler errorHandler = nullptr);
-Path moduleScopePath(QString uri, QString version, ErrorHandler errorHandler = nullptr);
-inline Path moduleScopePath(QString uri, ErrorHandler errorHandler = nullptr)
+Path moduleIndexPath(
+ const QString &uri, int majorVersion, const ErrorHandler &errorHandler = nullptr);
+Path moduleScopePath(
+ const QString &uri, Version version, const ErrorHandler &errorHandler = nullptr);
+Path moduleScopePath(
+ const QString &uri, const QString &version, const ErrorHandler &errorHandler = nullptr);
+inline Path moduleScopePath(
+ const QString &uri, const ErrorHandler &errorHandler = nullptr)
{
return moduleScopePath(uri, QString(), errorHandler);
}
-inline Path qmlDirInfoPath(QString path)
+inline Path qmlDirInfoPath(const QString &path)
{
return Path::Root(PathRoot::Top).field(Fields::qmldirWithPath).key(path);
}
-inline Path qmlDirPath(QString path)
+inline Path qmlDirPath(const QString &path)
{
return qmlDirInfoPath(path).field(Fields::currentItem);
}
-inline Path qmldirFileInfoPath(QString path)
+inline Path qmldirFileInfoPath(const QString &path)
{
return Path::Root(PathRoot::Top).field(Fields::qmldirFileWithPath).key(path);
}
-inline Path qmldirFilePath(QString path)
+inline Path qmldirFilePath(const QString &path)
{
return qmldirFileInfoPath(path).field(Fields::currentItem);
}
-inline Path qmlFileInfoPath(QString canonicalFilePath)
+inline Path qmlFileInfoPath(const QString &canonicalFilePath)
{
return Path::Root(PathRoot::Top).field(Fields::qmlFileWithPath).key(canonicalFilePath);
}
-inline Path qmlFilePath(QString canonicalFilePath)
+inline Path qmlFilePath(const QString &canonicalFilePath)
{
return qmlFileInfoPath(canonicalFilePath).field(Fields::currentItem);
}
-inline Path qmlFileObjectPath(QString canonicalFilePath)
+inline Path qmlFileObjectPath(const QString &canonicalFilePath)
{
return qmlFilePath(canonicalFilePath)
.field(Fields::components)
@@ -85,55 +87,55 @@ inline Path qmlFileObjectPath(QString canonicalFilePath)
.field(Fields::objects)
.index(0);
}
-inline Path qmltypesFileInfoPath(QString path)
+inline Path qmltypesFileInfoPath(const QString &path)
{
return Path::Root(PathRoot::Top).field(Fields::qmltypesFileWithPath).key(path);
}
-inline Path qmltypesFilePath(QString path)
+inline Path qmltypesFilePath(const QString &path)
{
return qmltypesFileInfoPath(path).field(Fields::currentItem);
}
-inline Path jsFileInfoPath(QString path)
+inline Path jsFileInfoPath(const QString &path)
{
return Path::Root(PathRoot::Top).field(Fields::jsFileWithPath).key(path);
}
-inline Path jsFilePath(QString path)
+inline Path jsFilePath(const QString &path)
{
return jsFileInfoPath(path).field(Fields::currentItem);
}
-inline Path qmlDirectoryInfoPath(QString path)
+inline Path qmlDirectoryInfoPath(const QString &path)
{
return Path::Root(PathRoot::Top).field(Fields::qmlDirectoryWithPath).key(path);
}
-inline Path qmlDirectoryPath(QString path)
+inline Path qmlDirectoryPath(const QString &path)
{
return qmlDirectoryInfoPath(path).field(Fields::currentItem);
}
-inline Path globalScopeInfoPath(QString name)
+inline Path globalScopeInfoPath(const QString &name)
{
return Path::Root(PathRoot::Top).field(Fields::globalScopeWithName).key(name);
}
-inline Path globalScopePath(QString name)
+inline Path globalScopePath(const QString &name)
{
return globalScopeInfoPath(name).field(Fields::currentItem);
}
-inline Path lookupCppTypePath(QString name)
+inline Path lookupCppTypePath(const QString &name)
{
return Path::Current(PathCurrent::Lookup).field(Fields::cppType).key(name);
}
-inline Path lookupPropertyPath(QString name)
+inline Path lookupPropertyPath(const QString &name)
{
return Path::Current(PathCurrent::Lookup).field(Fields::propertyDef).key(name);
}
-inline Path lookupSymbolPath(QString name)
+inline Path lookupSymbolPath(const QString &name)
{
return Path::Current(PathCurrent::Lookup).field(Fields::symbol).key(name);
}
-inline Path lookupTypePath(QString name)
+inline Path lookupTypePath(const QString &name)
{
return Path::Current(PathCurrent::Lookup).field(Fields::type).key(name);
}
-inline Path loadInfoPath(Path el)
+inline Path loadInfoPath(const Path &el)
{
return Path::Root(PathRoot::Env).field(Fields::loadInfo).key(el.toString());
}
@@ -142,12 +144,12 @@ inline Path loadInfoPath(Path el)
class QMLDOM_EXPORT CommentableDomElement : public DomElement
{
public:
- CommentableDomElement(Path pathFromOwner = Path()) : DomElement(pathFromOwner) { }
+ CommentableDomElement(const Path &pathFromOwner = Path()) : DomElement(pathFromOwner) { }
CommentableDomElement(const CommentableDomElement &o) : DomElement(o), m_comments(o.m_comments)
{
}
CommentableDomElement &operator=(const CommentableDomElement &o) = default;
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override;
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override;
RegionComments &comments() { return m_comments; }
const RegionComments &comments() const { return m_comments; }
@@ -165,7 +167,7 @@ public:
Version(qint32 majorVersion = Undefined, qint32 minorVersion = Undefined);
static Version fromString(QStringView v);
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor);
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const;
bool isLatest() const;
bool isValid() const;
@@ -264,17 +266,20 @@ class QMLDOM_EXPORT Import
public:
constexpr static DomType kindValue = DomType::Import;
- static Import fromUriString(QString importStr, Version v = Version(),
- QString importId = QString(), ErrorHandler handler = nullptr);
- static Import fromFileString(QString importStr, QString importId = QString(),
- ErrorHandler handler = nullptr);
+ static Import fromUriString(
+ const QString &importStr, Version v = Version(), const QString &importId = QString(),
+ const ErrorHandler &handler = nullptr);
+ static Import fromFileString(
+ const QString &importStr, const QString &importId = QString(),
+ const ErrorHandler &handler = nullptr);
- Import(QmlUri uri = QmlUri(), Version version = Version(), QString importId = QString())
+ Import(const QmlUri &uri = QmlUri(), Version version = Version(),
+ const QString &importId = QString())
: uri(uri), version(version), importId(importId)
{
}
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor);
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const;
Path importedPath() const
{
if (uri.isDirectory()) {
@@ -298,7 +303,7 @@ public:
}
friend bool operator!=(const Import &i1, const Import &i2) { return !(i1 == i2); }
- void writeOut(DomItem &self, OutWriter &ow) const;
+ void writeOut(const DomItem &self, OutWriter &ow) const;
static QRegularExpression importRe();
@@ -314,7 +319,7 @@ class QMLDOM_EXPORT ModuleAutoExport
public:
constexpr static DomType kindValue = DomType::ModuleAutoExport;
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = true;
cont = cont && self.dvWrapField(visitor, Fields::import, import);
@@ -340,18 +345,23 @@ class QMLDOM_EXPORT Pragma
public:
constexpr static DomType kindValue = DomType::Pragma;
- Pragma(QString pragmaName = QString()) : name(pragmaName) { }
+ Pragma(const QString &pragmaName = QString(), const QStringList &pragmaValues = {})
+ : name(pragmaName), values{ pragmaValues }
+ {
+ }
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = self.dvValueField(visitor, Fields::name, name);
+ cont = cont && self.dvValueField(visitor, Fields::values, values);
cont = cont && self.dvWrapField(visitor, Fields::comments, comments);
return cont;
}
- void writeOut(DomItem &self, OutWriter &ow) const;
+ void writeOut(const DomItem &self, OutWriter &ow) const;
QString name;
+ QStringList values;
RegionComments comments;
};
@@ -360,34 +370,45 @@ class QMLDOM_EXPORT Id
public:
constexpr static DomType kindValue = DomType::Id;
- Id(QString idName = QString(), Path referredObject = Path());
+ Id(const QString &idName = QString(), const Path &referredObject = Path());
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor);
- void updatePathFromOwner(Path pathFromOwner);
- Path addAnnotation(Path selfPathFromOwner, const QmlObject &ann, QmlObject **aPtr = nullptr);
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const;
+ void updatePathFromOwner(const Path &pathFromOwner);
+ Path addAnnotation(const Path &selfPathFromOwner, const QmlObject &ann, QmlObject **aPtr = nullptr);
QString name;
Path referredObjectPath;
RegionComments comments;
QList<QmlObject> annotations;
+ std::shared_ptr<ScriptExpression> value;
};
+// TODO: rename? it may contain statements and stuff, not only expressions
+// TODO QTBUG-121933
class QMLDOM_EXPORT ScriptExpression final : public OwningItem
{
Q_GADGET
Q_DECLARE_TR_FUNCTIONS(ScriptExpression)
public:
- enum class ExpressionType { BindingExpression, FunctionBody, ArgInitializer };
+ enum class ExpressionType {
+ BindingExpression,
+ FunctionBody,
+ ArgInitializer,
+ ArgumentStructure,
+ ReturnType,
+ JSCode, // Used for storing the content of the whole .js file as "one" Expression
+ ESMCode, // Used for storing the content of the whole ECMAScript module (.mjs) as "one"
+ // Expression
+ };
Q_ENUM(ExpressionType);
constexpr static DomType kindValue = DomType::ScriptExpression;
DomType kind() const override { return kindValue; }
- explicit ScriptExpression(QStringView code, std::shared_ptr<QQmlJS::Engine> engine,
- AST::Node *ast, std::shared_ptr<AstComments> comments,
- ExpressionType expressionType,
- SourceLocation localOffset = SourceLocation(), int derivedFrom = 0,
- QStringView preCode = QStringView(),
- QStringView postCode = QStringView());
+ explicit ScriptExpression(
+ QStringView code, const std::shared_ptr<QQmlJS::Engine> &engine, AST::Node *ast,
+ const std::shared_ptr<AstComments> &comments, ExpressionType expressionType,
+ SourceLocation localOffset = SourceLocation(), int derivedFrom = 0,
+ QStringView preCode = QStringView(), QStringView postCode = QStringView());
ScriptExpression()
: ScriptExpression(QStringView(), std::shared_ptr<QQmlJS::Engine>(), nullptr,
@@ -396,8 +417,9 @@ public:
{
}
- explicit ScriptExpression(QString code, ExpressionType expressionType, int derivedFrom = 0,
- QString preCode = QString(), QString postCode = QString())
+ explicit ScriptExpression(
+ const QString &code, ExpressionType expressionType, int derivedFrom = 0,
+ const QString &preCode = QString(), const QString &postCode = QString())
: OwningItem(derivedFrom), m_expressionType(expressionType)
{
setCode(code, preCode, postCode);
@@ -405,20 +427,20 @@ public:
ScriptExpression(const ScriptExpression &e);
- std::shared_ptr<ScriptExpression> makeCopy(DomItem &self) const
+ std::shared_ptr<ScriptExpression> makeCopy(const DomItem &self) const
{
return std::static_pointer_cast<ScriptExpression>(doCopy(self));
}
- std::shared_ptr<ScriptExpression> copyWithUpdatedCode(DomItem &self, QString code) const;
+ std::shared_ptr<ScriptExpression> copyWithUpdatedCode(const DomItem &self, const QString &code) const;
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) override;
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override;
- Path canonicalPath(DomItem &self) const override { return self.m_ownerPath; }
+ Path canonicalPath(const DomItem &self) const override { return self.m_ownerPath; }
// parsed and created if not available
AST::Node *ast() const { return m_ast; }
// dump of the ast (without locations)
- void astDumper(Sink s, AstDumperOptions options) const;
+ void astDumper(const Sink &s, AstDumperOptions options) const;
QString astRelocatableDump() const;
// definedSymbols name, value, from
@@ -446,19 +468,21 @@ public:
return m_engine;
}
std::shared_ptr<AstComments> astComments() const { return m_astComments; }
- void writeOut(DomItem &self, OutWriter &lw) const override;
- SourceLocation globalLocation(DomItem &self) const;
+ void writeOut(const DomItem &self, OutWriter &lw) const override;
+ SourceLocation globalLocation(const DomItem &self) const;
SourceLocation localOffset() const { return m_localOffset; }
QStringView preCode() const { return m_preCode; }
QStringView postCode() const { return m_postCode; }
+ void setScriptElement(const ScriptElementVariant &p);
+ ScriptElementVariant scriptElement() { return m_element; }
protected:
- std::shared_ptr<OwningItem> doCopy(DomItem &) const override
+ std::shared_ptr<OwningItem> doCopy(const DomItem &) const override
{
return std::make_shared<ScriptExpression>(*this);
}
- std::function<SourceLocation(SourceLocation)> locationToGlobalF(DomItem &self) const
+ std::function<SourceLocation(SourceLocation)> locationToGlobalF(const DomItem &self) const
{
SourceLocation loc = globalLocation(self);
return [loc, this](SourceLocation x) {
@@ -479,13 +503,34 @@ protected:
: x.startColumn)); // are line and column 1 based? then we should + 1
}
- std::function<SourceLocation(SourceLocation)> locationToLocalF(DomItem &) const
+ std::function<SourceLocation(SourceLocation)> locationToLocalF(const DomItem &) const
{
return [this](SourceLocation x) { return locationToLocal(x); };
}
private:
- void setCode(QString code, QString preCode, QString postCode);
+ enum class ParseMode {
+ QML,
+ JS,
+ ESM, // ECMAScript module
+ };
+
+ inline ParseMode resolveParseMode()
+ {
+ switch (m_expressionType) {
+ case ExpressionType::BindingExpression:
+ // unfortunately there are no documentation explaining this resolution
+ // this was just moved from the original implementation
+ return ParseMode::QML;
+ case ExpressionType::ESMCode:
+ return ParseMode::ESM;
+ default:
+ return ParseMode::JS;
+ }
+ }
+ void setCode(const QString &code, const QString &preCode, const QString &postCode);
+ [[nodiscard]] AST::Node *parse(ParseMode mode);
+
ExpressionType m_expressionType;
QString m_codeStr;
QStringView m_code;
@@ -495,6 +540,7 @@ private:
mutable AST::Node *m_ast;
std::shared_ptr<AstComments> m_astComments;
SourceLocation m_localOffset;
+ ScriptElementVariant m_element;
};
class BindingValue;
@@ -504,22 +550,25 @@ class QMLDOM_EXPORT Binding
public:
constexpr static DomType kindValue = DomType::Binding;
- Binding(QString m_name = QString(),
+ Binding(const QString &m_name = QString(),
std::unique_ptr<BindingValue> value = std::unique_ptr<BindingValue>(),
BindingType bindingType = BindingType::Normal);
- Binding(QString m_name, std::shared_ptr<ScriptExpression> value,
+ Binding(const QString &m_name, const std::shared_ptr<ScriptExpression> &value,
+ BindingType bindingType = BindingType::Normal);
+ Binding(const QString &m_name, const QString &scriptCode,
+ BindingType bindingType = BindingType::Normal);
+ Binding(const QString &m_name, const QmlObject &value,
+ BindingType bindingType = BindingType::Normal);
+ Binding(const QString &m_name, const QList<QmlObject> &value,
BindingType bindingType = BindingType::Normal);
- Binding(QString m_name, QString scriptCode, BindingType bindingType = BindingType::Normal);
- Binding(QString m_name, QmlObject value, BindingType bindingType = BindingType::Normal);
- Binding(QString m_name, QList<QmlObject> value, BindingType bindingType = BindingType::Normal);
Binding(const Binding &o);
Binding(Binding &&o) = default;
~Binding();
Binding &operator=(const Binding &);
Binding &operator=(Binding &&) = default;
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor);
- DomItem valueItem(DomItem &self) const; // ### REVISIT: consider replacing return value with variant
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const;
+ DomItem valueItem(const DomItem &self) const; // ### REVISIT: consider replacing return value with variant
BindingValueKind valueKind() const;
QString name() const { return m_name; }
BindingType bindingType() const { return m_bindingType; }
@@ -530,20 +579,18 @@ public:
QList<QmlObject> *arrayValue();
std::shared_ptr<ScriptExpression> scriptExpressionValue();
QList<QmlObject> annotations() const { return m_annotations; }
- void setAnnotations(QList<QmlObject> annotations) { m_annotations = annotations; }
+ void setAnnotations(const QList<QmlObject> &annotations) { m_annotations = annotations; }
void setValue(std::unique_ptr<BindingValue> &&value) { m_value = std::move(value); }
- Path addAnnotation(Path selfPathFromOwner, const QmlObject &a, QmlObject **aPtr = nullptr);
+ Path addAnnotation(const Path &selfPathFromOwner, const QmlObject &a, QmlObject **aPtr = nullptr);
const RegionComments &comments() const { return m_comments; }
RegionComments &comments() { return m_comments; }
- void updatePathFromOwner(Path newPath);
- void writeOut(DomItem &self, OutWriter &lw) const;
- void writeOutValue(DomItem &self, OutWriter &lw) const;
+ void updatePathFromOwner(const Path &newPath);
+ void writeOut(const DomItem &self, OutWriter &lw) const;
+ void writeOutValue(const DomItem &self, OutWriter &lw) const;
bool isSignalHandler() const
{
QString baseName = m_name.split(QLatin1Char('.')).last();
- if (baseName.startsWith(u"on") && baseName.size() > 2 && baseName.at(2).isUpper())
- return true;
- return false;
+ return QQmlSignalNames::isHandlerName(baseName);
}
static QString preCodeForName(QStringView n)
{
@@ -553,13 +600,17 @@ public:
QString preCode() const { return preCodeForName(m_name); }
QString postCode() const { return postCodeForName(m_name); }
+ ScriptElementVariant bindingIdentifiers() const { return m_bindingIdentifiers; }
+ void setBindingIdentifiers(const ScriptElementVariant &bindingIdentifiers) { m_bindingIdentifiers = bindingIdentifiers; }
+
private:
- friend class QmlDomAstCreator;
+ friend class QQmlDomAstCreator;
BindingType m_bindingType;
QString m_name;
std::unique_ptr<BindingValue> m_value;
QList<QmlObject> m_annotations;
RegionComments m_comments;
+ ScriptElementVariant m_bindingIdentifiers;
};
class QMLDOM_EXPORT AttributeInfo
@@ -567,11 +618,14 @@ class QMLDOM_EXPORT AttributeInfo
public:
enum Access { Private, Protected, Public };
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor);
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const;
- Path addAnnotation(Path selfPathFromOwner, const QmlObject &annotation,
+ Path addAnnotation(const Path &selfPathFromOwner, const QmlObject &annotation,
QmlObject **aPtr = nullptr);
- void updatePathFromOwner(Path newPath);
+ void updatePathFromOwner(const Path &newPath);
+
+ QQmlJSScope::ConstPtr semanticScope() const { return m_semanticScope; }
+ void setSemanticScope(const QQmlJSScope::ConstPtr &scope) { m_semanticScope = scope; }
QString name;
Access access = Access::Public;
@@ -580,6 +634,7 @@ public:
bool isList = false;
QList<QmlObject> annotations;
RegionComments comments;
+ QQmlJSScope::ConstPtr m_semanticScope;
};
struct QMLDOM_EXPORT LocallyResolvedAlias
@@ -608,7 +663,7 @@ class QMLDOM_EXPORT PropertyDefinition : public AttributeInfo
public:
constexpr static DomType kindValue = DomType::PropertyDefinition;
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = AttributeInfo::iterateDirectSubpaths(self, visitor);
cont = cont && self.dvValueField(visitor, Fields::isPointer, isPointer);
@@ -621,6 +676,11 @@ public:
cont = cont && self.dvValueField(visitor, Fields::bindable, bindable);
cont = cont && self.dvValueField(visitor, Fields::notify, notify);
cont = cont && self.dvReferenceField(visitor, Fields::type, typePath());
+ if (m_nameIdentifiers) {
+ cont = cont && self.dvItemField(visitor, Fields::nameIdentifiers, [this, &self]() {
+ return self.subScriptElementWrapperItem(m_nameIdentifiers);
+ });
+ }
return cont;
}
@@ -628,7 +688,9 @@ public:
bool isAlias() const { return typeName == u"alias"; }
bool isParametricType() const;
- void writeOut(DomItem &self, OutWriter &lw) const;
+ void writeOut(const DomItem &self, OutWriter &lw) const;
+ ScriptElementVariant nameIdentifiers() const { return m_nameIdentifiers; }
+ void setNameIdentifiers(const ScriptElementVariant &name) { m_nameIdentifiers = name; }
QString read;
QString write;
@@ -638,6 +700,7 @@ public:
bool isPointer = false;
bool isDefaultMember = false;
bool isRequired = false;
+ ScriptElementVariant m_nameIdentifiers;
};
class QMLDOM_EXPORT PropertyInfo
@@ -645,7 +708,7 @@ class QMLDOM_EXPORT PropertyInfo
public:
constexpr static DomType kindValue = DomType::PropertyInfo; // used to get the correct kind in ObjectWrapper
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor);
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const;
QList<DomItem> propertyDefs;
QList<DomItem> bindings;
@@ -656,17 +719,24 @@ class QMLDOM_EXPORT MethodParameter
public:
constexpr static DomType kindValue = DomType::MethodParameter;
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor);
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const;
- void writeOut(DomItem &self, OutWriter &ow) const;
- void writeOutSignal(DomItem &self, OutWriter &ow) const;
+ void writeOut(const DomItem &self, OutWriter &ow) const;
+ void writeOutSignal(const DomItem &self, OutWriter &ow) const;
QString name;
QString typeName;
bool isPointer = false;
bool isReadonly = false;
bool isList = false;
+ bool isRestElement = false;
std::shared_ptr<ScriptExpression> defaultValue;
+ /*!
+ \internal
+ Contains the scriptElement representing this argument, inclusive default value,
+ deconstruction, etc.
+ */
+ std::shared_ptr<ScriptExpression> value;
QList<QmlObject> annotations;
RegionComments comments;
};
@@ -680,28 +750,29 @@ public:
constexpr static DomType kindValue = DomType::MethodInfo;
- Path typePath(DomItem &) const
+ Path typePath(const DomItem &) const
{
return (typeName.isEmpty() ? Path() : Paths::lookupTypePath(typeName));
}
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor);
- QString preCode(DomItem &) const; // ### REVISIT, might be simplified by using different toplevel production rules at usage site
- QString postCode(DomItem &) const;
- void writePre(DomItem &self, OutWriter &ow) const;
- void writeOut(DomItem &self, OutWriter &ow) const;
- void setCode(QString code)
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const;
+ QString preCode(const DomItem &) const; // ### REVISIT, might be simplified by using different toplevel production rules at usage site
+ QString postCode(const DomItem &) const;
+ void writePre(const DomItem &self, OutWriter &ow) const;
+ void writeOut(const DomItem &self, OutWriter &ow) const;
+ void setCode(const QString &code)
{
body = std::make_shared<ScriptExpression>(
code, ScriptExpression::ExpressionType::FunctionBody, 0,
QLatin1String("function foo(){\n"), QLatin1String("\n}\n"));
}
-
MethodInfo() = default;
+ // TODO: make private + add getters/setters
QList<MethodParameter> parameters;
MethodType methodType = Method;
std::shared_ptr<ScriptExpression> body;
+ std::shared_ptr<ScriptExpression> returnType;
bool isConstructor = false;
};
@@ -709,20 +780,27 @@ class QMLDOM_EXPORT EnumItem
{
public:
constexpr static DomType kindValue = DomType::EnumItem;
+ enum class ValueKind : quint8 {
+ ImplicitValue,
+ ExplicitValue
+ };
+ EnumItem(const QString &name = QString(), int value = 0, ValueKind valueKind = ValueKind::ImplicitValue)
+ : m_name(name), m_value(value), m_valueKind(valueKind)
+ {
+ }
- EnumItem(QString name = QString(), int value = 0) : m_name(name), m_value(value) { }
-
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor);
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const;
QString name() const { return m_name; }
double value() const { return m_value; }
RegionComments &comments() { return m_comments; }
const RegionComments &comments() const { return m_comments; }
- void writeOut(DomItem &self, OutWriter &lw) const;
+ void writeOut(const DomItem &self, OutWriter &lw) const;
private:
QString m_name;
double m_value;
+ ValueKind m_valueKind;
RegionComments m_comments;
};
@@ -732,33 +810,33 @@ public:
constexpr static DomType kindValue = DomType::EnumDecl;
DomType kind() const override { return kindValue; }
- EnumDecl(QString name = QString(), QList<EnumItem> values = QList<EnumItem>(),
+ EnumDecl(const QString &name = QString(), QList<EnumItem> values = QList<EnumItem>(),
Path pathFromOwner = Path())
: CommentableDomElement(pathFromOwner), m_name(name), m_values(values)
{
}
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) override;
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override;
QString name() const { return m_name; }
- void setName(QString name) { m_name = name; }
+ void setName(const QString &name) { m_name = name; }
const QList<EnumItem> &values() const & { return m_values; }
bool isFlag() const { return m_isFlag; }
void setIsFlag(bool flag) { m_isFlag = flag; }
QString alias() const { return m_alias; }
- void setAlias(QString aliasName) { m_alias = aliasName; }
+ void setAlias(const QString &aliasName) { m_alias = aliasName; }
void setValues(QList<EnumItem> values) { m_values = values; }
Path addValue(EnumItem value)
{
m_values.append(value);
return Path::Field(Fields::values).index(index_type(m_values.size() - 1));
}
- void updatePathFromOwner(Path newP) override;
+ void updatePathFromOwner(const Path &newP) override;
const QList<QmlObject> &annotations() const & { return m_annotations; }
- void setAnnotations(QList<QmlObject> annotations);
+ void setAnnotations(const QList<QmlObject> &annotations);
Path addAnnotation(const QmlObject &child, QmlObject **cPtr = nullptr);
- void writeOut(DomItem &self, OutWriter &lw) const override;
+ void writeOut(const DomItem &self, OutWriter &lw) const override;
private:
QString m_name;
@@ -775,20 +853,16 @@ public:
constexpr static DomType kindValue = DomType::QmlObject;
DomType kind() const override { return kindValue; }
- QmlObject(Path pathFromOwner = Path());
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override;
- bool iterateBaseDirectSubpaths(DomItem &self, DirectVisitor);
+ QmlObject(const Path &pathFromOwner = Path());
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override;
+ bool iterateBaseDirectSubpaths(const DomItem &self, DirectVisitor) const;
QList<QString> fields() const;
- QList<QString> fields(DomItem &) const override { return fields(); }
- DomItem field(DomItem &self, QStringView name);
- DomItem field(DomItem &self, QStringView name) const override
- {
- return const_cast<QmlObject *>(this)->field(self, name);
- }
- void updatePathFromOwner(Path newPath) override;
+ QList<QString> fields(const DomItem &) const override { return fields(); }
+ DomItem field(const DomItem &self, QStringView name) const override;
+ void updatePathFromOwner(const Path &newPath) override;
QString localDefaultPropertyName() const;
- QString defaultPropertyName(DomItem &self) const;
- virtual bool iterateSubOwners(DomItem &self, function_ref<bool(DomItem &owner)> visitor) const;
+ QString defaultPropertyName(const DomItem &self) const;
+ virtual bool iterateSubOwners(const DomItem &self, function_ref<bool(const DomItem &owner)> visitor) const;
QString idStr() const { return m_idStr; }
QString name() const { return m_name; }
@@ -800,11 +874,11 @@ public:
QList<QmlObject> children() const { return m_children; }
QList<QmlObject> annotations() const { return m_annotations; }
- void setIdStr(QString id) { m_idStr = id; }
- void setName(QString name) { m_name = name; }
- void setDefaultPropertyName(QString name) { m_defaultPropertyName = name; }
+ void setIdStr(const QString &id) { m_idStr = id; }
+ void setName(const QString &name) { m_name = name; }
+ void setDefaultPropertyName(const QString &name) { m_defaultPropertyName = name; }
void setPrototypePaths(QList<Path> prototypePaths) { m_prototypePaths = prototypePaths; }
- Path addPrototypePath(Path prototypePath)
+ Path addPrototypePath(const Path &prototypePath)
{
index_type idx = index_type(m_prototypePaths.indexOf(prototypePath));
if (idx == -1) {
@@ -813,33 +887,33 @@ public:
}
return Path::Field(Fields::prototypes).index(idx);
}
- void setNextScopePath(Path nextScopePath) { m_nextScopePath = nextScopePath; }
+ void setNextScopePath(const Path &nextScopePath) { m_nextScopePath = nextScopePath; }
void setPropertyDefs(QMultiMap<QString, PropertyDefinition> propertyDefs)
{
m_propertyDefs = propertyDefs;
}
void setBindings(QMultiMap<QString, Binding> bindings) { m_bindings = bindings; }
void setMethods(QMultiMap<QString, MethodInfo> functionDefs) { m_methods = functionDefs; }
- void setChildren(QList<QmlObject> children)
+ void setChildren(const QList<QmlObject> &children)
{
m_children = children;
if (pathFromOwner())
updatePathFromOwner(pathFromOwner());
}
- void setAnnotations(QList<QmlObject> annotations)
+ void setAnnotations(const QList<QmlObject> &annotations)
{
m_annotations = annotations;
if (pathFromOwner())
updatePathFromOwner(pathFromOwner());
}
- Path addPropertyDef(PropertyDefinition propertyDef, AddOption option,
+ Path addPropertyDef(const PropertyDefinition &propertyDef, AddOption option,
PropertyDefinition **pDef = nullptr)
{
return insertUpdatableElementInMultiMap(pathFromOwner().field(Fields::propertyDefs),
m_propertyDefs, propertyDef.name, propertyDef,
option, pDef);
}
- MutableDomItem addPropertyDef(MutableDomItem &self, PropertyDefinition propertyDef,
+ MutableDomItem addPropertyDef(MutableDomItem &self, const PropertyDefinition &propertyDef,
AddOption option);
Path addBinding(Binding binding, AddOption option, Binding **bPtr = nullptr)
@@ -848,12 +922,12 @@ public:
binding.name(), binding, option, bPtr);
}
MutableDomItem addBinding(MutableDomItem &self, Binding binding, AddOption option);
- Path addMethod(MethodInfo functionDef, AddOption option, MethodInfo **mPtr = nullptr)
+ Path addMethod(const MethodInfo &functionDef, AddOption option, MethodInfo **mPtr = nullptr)
{
return insertUpdatableElementInMultiMap(pathFromOwner().field(Fields::methods), m_methods,
functionDef.name, functionDef, option, mPtr);
}
- MutableDomItem addMethod(MutableDomItem &self, MethodInfo functionDef, AddOption option);
+ MutableDomItem addMethod(MutableDomItem &self, const MethodInfo &functionDef, AddOption option);
Path addChild(QmlObject child, QmlObject **cPtr = nullptr)
{
return appendUpdatableElementInQList(pathFromOwner().field(Fields::children), m_children,
@@ -869,15 +943,21 @@ public:
return appendUpdatableElementInQList(pathFromOwner().field(Fields::annotations),
m_annotations, annotation, aPtr);
}
- void writeOut(DomItem &self, OutWriter &ow, QString onTarget) const;
- void writeOut(DomItem &self, OutWriter &lw) const override { writeOut(self, lw, QString()); }
+ void writeOut(const DomItem &self, OutWriter &ow, const QString &onTarget) const;
+ void writeOut(const DomItem &self, OutWriter &lw) const override { writeOut(self, lw, QString()); }
- LocallyResolvedAlias resolveAlias(DomItem &self,
+ LocallyResolvedAlias resolveAlias(const DomItem &self,
std::shared_ptr<ScriptExpression> accessSequence) const;
- LocallyResolvedAlias resolveAlias(DomItem &self, const QStringList &accessSequence) const;
+ LocallyResolvedAlias resolveAlias(const DomItem &self, const QStringList &accessSequence) const;
+
+ QQmlJSScope::ConstPtr semanticScope() const { return m_scope; }
+ void setSemanticScope(const QQmlJSScope::ConstPtr &scope) { m_scope = scope; }
+
+ ScriptElementVariant nameIdentifiers() const { return m_nameIdentifiers; }
+ void setNameIdentifiers(const ScriptElementVariant &name) { m_nameIdentifiers = name; }
private:
- friend class QmlDomAstCreator;
+ friend class QQmlDomAstCreator;
QString m_idStr;
QString m_name;
QList<Path> m_prototypePaths;
@@ -888,6 +968,8 @@ private:
QMultiMap<QString, MethodInfo> m_methods;
QList<QmlObject> m_children;
QList<QmlObject> m_annotations;
+ QQmlJSScope::ConstPtr m_scope;
+ ScriptElementVariant m_nameIdentifiers;
};
class Export
@@ -895,8 +977,9 @@ class Export
Q_DECLARE_TR_FUNCTIONS(Export)
public:
constexpr static DomType kindValue = DomType::Export;
- static Export fromString(Path source, QStringView exp, Path typePath, ErrorHandler h);
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+ static Export fromString(
+ const Path &source, QStringView exp, const Path &typePath, const ErrorHandler &h);
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = true;
cont = cont && self.dvValueField(visitor, Fields::uri, uri);
@@ -923,18 +1006,14 @@ public:
class QMLDOM_EXPORT Component : public CommentableDomElement
{
public:
- Component(QString name);
- Component(Path pathFromOwner = Path());
+ Component(const QString &name);
+ Component(const Path &pathFromOwner = Path());
Component(const Component &o) = default;
Component &operator=(const Component &) = default;
- bool iterateDirectSubpaths(DomItem &, DirectVisitor) override;
- void updatePathFromOwner(Path newPath) override;
- DomItem field(DomItem &self, QStringView name) const override
- {
- return const_cast<Component *>(this)->field(self, name);
- }
- DomItem field(DomItem &self, QStringView name);
+ bool iterateDirectSubpaths(const DomItem &, DirectVisitor) const override;
+ void updatePathFromOwner(const Path &newPath) override;
+ DomItem field(const DomItem &self, QStringView name) const override;
QString name() const { return m_name; }
const QMultiMap<QString, EnumDecl> &enumerations() const & { return m_enumerations; }
@@ -943,9 +1022,9 @@ public:
bool isCreatable() const { return m_isCreatable; }
bool isComposite() const { return m_isComposite; }
QString attachedTypeName() const { return m_attachedTypeName; }
- Path attachedTypePath(DomItem &) const { return m_attachedTypePath; }
+ Path attachedTypePath(const DomItem &) const { return m_attachedTypePath; }
- void setName(QString name) { m_name = name; }
+ void setName(const QString &name) { m_name = name; }
void setEnumerations(QMultiMap<QString, EnumDecl> enumerations)
{
m_enumerations = enumerations;
@@ -957,16 +1036,16 @@ public:
m_enumerations, enumeration.name(), enumeration,
option, ePtr);
}
- void setObjects(QList<QmlObject> objects) { m_objects = objects; }
+ void setObjects(const QList<QmlObject> &objects) { m_objects = objects; }
Path addObject(const QmlObject &object, QmlObject **oPtr = nullptr);
void setIsSingleton(bool isSingleton) { m_isSingleton = isSingleton; }
void setIsCreatable(bool isCreatable) { m_isCreatable = isCreatable; }
void setIsComposite(bool isComposite) { m_isComposite = isComposite; }
- void setAttachedTypeName(QString name) { m_attachedTypeName = name; }
- void setAttachedTypePath(Path p) { m_attachedTypePath = p; }
+ void setAttachedTypeName(const QString &name) { m_attachedTypeName = name; }
+ void setAttachedTypePath(const Path &p) { m_attachedTypePath = p; }
private:
- friend class QmlDomAstCreator;
+ friend class QQmlDomAstCreator;
QString m_name;
QMultiMap<QString, EnumDecl> m_enumerations;
QList<QmlObject> m_objects;
@@ -983,8 +1062,8 @@ public:
constexpr static DomType kindValue = DomType::JsResource;
DomType kind() const override { return kindValue; }
- JsResource(Path pathFromOwner = Path()) : Component(pathFromOwner) { }
- bool iterateDirectSubpaths(DomItem &, DirectVisitor) override
+ JsResource(const Path &pathFromOwner = Path()) : Component(pathFromOwner) { }
+ bool iterateDirectSubpaths(const DomItem &, DirectVisitor) const override
{ // to do: complete
return true;
}
@@ -997,13 +1076,13 @@ public:
constexpr static DomType kindValue = DomType::QmltypesComponent;
DomType kind() const override { return kindValue; }
- QmltypesComponent(Path pathFromOwner = Path()) : Component(pathFromOwner) { }
- bool iterateDirectSubpaths(DomItem &, DirectVisitor) override;
+ QmltypesComponent(const Path &pathFromOwner = Path()) : Component(pathFromOwner) { }
+ bool iterateDirectSubpaths(const DomItem &, DirectVisitor) const override;
const QList<Export> &exports() const & { return m_exports; }
QString fileName() const { return m_fileName; }
void setExports(QList<Export> exports) { m_exports = exports; }
void addExport(const Export &exportedEntry) { m_exports.append(exportedEntry); }
- void setFileName(QString fileName) { m_fileName = fileName; }
+ void setFileName(const QString &fileName) { m_fileName = fileName; }
const QList<int> &metaRevisions() const & { return m_metaRevisions; }
void setMetaRevisions(QList<int> metaRevisions) { m_metaRevisions = metaRevisions; }
void setInterfaceNames(const QStringList& interfaces) { m_interfaceNames = interfaces; }
@@ -1014,20 +1093,28 @@ public:
void setValueTypeName(const QString &name) { m_valueTypeName = name; }
bool hasCustomParser() const { return m_hasCustomParser; }
void setHasCustomParser(bool v) { m_hasCustomParser = v; }
+ bool extensionIsJavaScript() const { return m_extensionIsJavaScript; }
+ void setExtensionIsJavaScript(bool v) { m_extensionIsJavaScript = v; }
bool extensionIsNamespace() const { return m_extensionIsNamespace; }
void setExtensionIsNamespace(bool v) { m_extensionIsNamespace = v; }
QQmlJSScope::AccessSemantics accessSemantics() const { return m_accessSemantics; }
void setAccessSemantics(QQmlJSScope::AccessSemantics v) { m_accessSemantics = v; }
+
+ void setSemanticScope(const QQmlJSScope::ConstPtr &scope) { m_semanticScope = scope; }
+ QQmlJSScope::ConstPtr semanticScope() const { return m_semanticScope; }
+
private:
QList<Export> m_exports;
QList<int> m_metaRevisions;
QString m_fileName; // remove?
QStringList m_interfaceNames;
bool m_hasCustomParser = false;
+ bool m_extensionIsJavaScript = false;
bool m_extensionIsNamespace = false;
QString m_valueTypeName;
QString m_extensionTypeName;
- QQmlJSScope::AccessSemantics m_accessSemantics;
+ QQmlJSScope::AccessSemantics m_accessSemantics = QQmlJSScope::AccessSemantics::None;
+ QQmlJSScope::ConstPtr m_semanticScope;
};
class QMLDOM_EXPORT QmlComponent final : public Component
@@ -1036,39 +1123,42 @@ public:
constexpr static DomType kindValue = DomType::QmlComponent;
DomType kind() const override { return kindValue; }
- QmlComponent(QString name = QString()) : Component(name)
+ QmlComponent(const QString &name = QString()) : Component(name)
{
setIsComposite(true);
setIsCreatable(true);
}
- QmlComponent(const QmlComponent &o)
- : Component(o), m_nextComponentPath(o.m_nextComponentPath), m_ids(o.m_ids)
- {
- }
- QmlComponent &operator=(const QmlComponent &) = default;
-
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override;
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override;
const QMultiMap<QString, Id> &ids() const & { return m_ids; }
Path nextComponentPath() const { return m_nextComponentPath; }
void setIds(QMultiMap<QString, Id> ids) { m_ids = ids; }
- void setNextComponentPath(Path p) { m_nextComponentPath = p; }
- void updatePathFromOwner(Path newPath) override;
+ void setNextComponentPath(const Path &p) { m_nextComponentPath = p; }
+ void updatePathFromOwner(const Path &newPath) override;
Path addId(const Id &id, AddOption option = AddOption::Overwrite, Id **idPtr = nullptr)
{
// warning does nor remove old idStr when overwriting...
return insertUpdatableElementInMultiMap(pathFromOwner().field(Fields::ids), m_ids, id.name,
id, option, idPtr);
}
- void writeOut(DomItem &self, OutWriter &) const override;
- QList<QString> subComponentsNames(DomItem &self) const;
- QList<DomItem> subComponents(DomItem &self) const;
+ void writeOut(const DomItem &self, OutWriter &) const override;
+ QList<QString> subComponentsNames(const DomItem &self) const;
+ QList<DomItem> subComponents(const DomItem &self) const;
+
+ void setSemanticScope(const QQmlJSScope::ConstPtr &scope) { m_semanticScope = scope; }
+ QQmlJSScope::ConstPtr semanticScope() const { return m_semanticScope; }
+ ScriptElementVariant nameIdentifiers() const { return m_nameIdentifiers; }
+ void setNameIdentifiers(const ScriptElementVariant &name) { m_nameIdentifiers = name; }
private:
- friend class QmlDomAstCreator;
+ friend class QQmlDomAstCreator;
Path m_nextComponentPath;
QMultiMap<QString, Id> m_ids;
+ QQmlJSScope::ConstPtr m_semanticScope;
+ // m_nameIdentifiers contains the name of the component as FieldMemberExpression, and therefore
+ // only exists in inline components!
+ ScriptElementVariant m_nameIdentifiers;
};
class QMLDOM_EXPORT GlobalComponent final : public Component
@@ -1077,7 +1167,7 @@ public:
constexpr static DomType kindValue = DomType::GlobalComponent;
DomType kind() const override { return kindValue; }
- GlobalComponent(Path pathFromOwner = Path()) : Component(pathFromOwner) { }
+ GlobalComponent(const Path &pathFromOwner = Path()) : Component(pathFromOwner) { }
};
static ErrorGroups importErrors = { { DomItem::domErrorGroup, NewErrorGroup("importError") } };
@@ -1095,22 +1185,24 @@ public:
const QMap<QString, ImportScope> &subImports() const & { return m_subImports; }
- QList<Path> allSources(DomItem &self) const;
+ QList<Path> allSources(const DomItem &self) const;
- QSet<QString> importedNames(DomItem &self) const
+ QSet<QString> importedNames(const DomItem &self) const
{
QSet<QString> res;
- for (Path p : allSources(self)) {
+ const auto sources = allSources(self);
+ for (const Path &p : sources) {
QSet<QString> ks = self.path(p.field(Fields::exports), self.errorHandler()).keys();
res += ks;
}
return res;
}
- QList<DomItem> importedItemsWithName(DomItem &self, QString name) const
+ QList<DomItem> importedItemsWithName(const DomItem &self, const QString &name) const
{
QList<DomItem> res;
- for (Path p : allSources(self)) {
+ const auto sources = allSources(self);
+ for (const Path &p : sources) {
DomItem source = self.path(p.field(Fields::exports), self.errorHandler());
DomItem els = source.key(name);
int nEls = els.indexes();
@@ -1125,10 +1217,10 @@ public:
return res;
}
- QList<Export> importedExportsWithName(DomItem &self, QString name) const
+ QList<Export> importedExportsWithName(const DomItem &self, const QString &name) const
{
QList<Export> res;
- for (DomItem &i : importedItemsWithName(self, name))
+ for (const DomItem &i : importedItemsWithName(self, name))
if (const Export *e = i.as<Export>())
res.append(*e);
else
@@ -1137,13 +1229,13 @@ public:
return res;
}
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor);
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const;
- void addImport(QStringList p, Path targetExports)
+ void addImport(QStringList p, const Path &targetExports)
{
if (!p.isEmpty()) {
- QString current = p.takeFirst();
- m_subImports[current].addImport(p, targetExports);
+ const QString current = p.takeFirst();
+ m_subImports[current].addImport(std::move(p), targetExports);
} else if (!m_importSourcePaths.contains(targetExports)) {
m_importSourcePaths.append(targetExports);
}
@@ -1159,14 +1251,14 @@ class BindingValue
public:
BindingValue();
BindingValue(const QmlObject &o);
- BindingValue(std::shared_ptr<ScriptExpression> o);
+ BindingValue(const std::shared_ptr<ScriptExpression> &o);
BindingValue(const QList<QmlObject> &l);
~BindingValue();
BindingValue(const BindingValue &o);
BindingValue &operator=(const BindingValue &o);
- DomItem value(DomItem &binding);
- void updatePathFromOwner(Path newPath);
+ DomItem value(const DomItem &binding) const;
+ void updatePathFromOwner(const Path &newPath);
private:
friend class Binding;
diff --git a/src/qmldom/qqmldomerrormessage.cpp b/src/qmldom/qqmldomerrormessage.cpp
index d4b95850e2..b48702822f 100644
--- a/src/qmldom/qqmldomerrormessage.cpp
+++ b/src/qmldom/qqmldomerrormessage.cpp
@@ -37,14 +37,14 @@ Every group has a unique string identifying it (the \l{groupId}), and it should
be translated to get the local name. The best way to acheive this is to create new groups using
the NewErrorGroup macro.
*/
-void ErrorGroup::dump(Sink sink) const
+void ErrorGroup::dump(const Sink &sink) const
{
sink(u"[");
sink(groupName());
sink(u"]");
}
-void ErrorGroup::dumpId(Sink sink) const
+void ErrorGroup::dumpId(const Sink &sink) const
{
sink(u"[");
sink(QString(groupId()));
@@ -70,13 +70,13 @@ The simplest way to create new ErrorMessages is to have an ErrorGroups instance,
and use it to create new ErrorMessages using its debug, warning, error,... methods
*/
-void ErrorGroups::dump(Sink sink) const
+void ErrorGroups::dump(const Sink &sink) const
{
for (int i = 0; i < groups.size(); ++i)
groups.at(i).dump(sink);
}
-void ErrorGroups::dumpId(Sink sink) const
+void ErrorGroups::dumpId(const Sink &sink) const
{
for (int i = 0; i < groups.size(); ++i)
groups.at(i).dumpId(sink);
@@ -138,14 +138,16 @@ errorHandler(ErrorMessage::load(QLatin1String("my.company.error1")));
The \l{withItem} method can be used to set the path file and location if not aready set.
*/
-ErrorMessage ErrorGroups::errorMessage(Dumper msg, ErrorLevel level, Path element, QString canonicalFilePath, SourceLocation location) const
+ErrorMessage ErrorGroups::errorMessage(
+ const Dumper &msg, ErrorLevel level, const Path &element, const QString &canonicalFilePath,
+ SourceLocation location) const
{
if (level == ErrorLevel::Fatal)
fatal(msg, element, canonicalFilePath, location);
return ErrorMessage(dumperToString(msg), *this, level, element, canonicalFilePath, location);
}
-ErrorMessage ErrorGroups::errorMessage(const DiagnosticMessage &msg, Path element, QString canonicalFilePath) const
+ErrorMessage ErrorGroups::errorMessage(const DiagnosticMessage &msg, const Path &element, const QString &canonicalFilePath) const
{
ErrorMessage res(*this, msg, element, canonicalFilePath);
if (res.location == SourceLocation()
@@ -156,7 +158,9 @@ ErrorMessage ErrorGroups::errorMessage(const DiagnosticMessage &msg, Path elemen
return res;
}
-void ErrorGroups::fatal(Dumper msg, Path element, QStringView canonicalFilePath, SourceLocation location) const
+void ErrorGroups::fatal(
+ const Dumper &msg, const Path &element, QStringView canonicalFilePath,
+ SourceLocation location) const
{
enum { FatalMsgMaxLen = 1023 };
char buf[FatalMsgMaxLen+1];
@@ -192,42 +196,42 @@ void ErrorGroups::fatal(Dumper msg, Path element, QStringView canonicalFilePath,
qFatal("%s", buf);
}
-ErrorMessage ErrorGroups::debug(QString message) const
+ErrorMessage ErrorGroups::debug(const QString &message) const
{
return ErrorMessage(message, *this, ErrorLevel::Debug);
}
-ErrorMessage ErrorGroups::debug(Dumper message) const
+ErrorMessage ErrorGroups::debug(const Dumper &message) const
{
return ErrorMessage(dumperToString(message), *this, ErrorLevel::Debug);
}
-ErrorMessage ErrorGroups::info(QString message) const
+ErrorMessage ErrorGroups::info(const QString &message) const
{
return ErrorMessage(message, *this, ErrorLevel::Info);
}
-ErrorMessage ErrorGroups::info(Dumper message) const
+ErrorMessage ErrorGroups::info(const Dumper &message) const
{
return ErrorMessage(dumperToString(message), *this, ErrorLevel::Info);
}
-ErrorMessage ErrorGroups::warning(QString message) const
+ErrorMessage ErrorGroups::warning(const QString &message) const
{
return ErrorMessage(message, *this, ErrorLevel::Warning);
}
-ErrorMessage ErrorGroups::warning(Dumper message) const
+ErrorMessage ErrorGroups::warning(const Dumper &message) const
{
return ErrorMessage(dumperToString(message), *this, ErrorLevel::Warning);
}
-ErrorMessage ErrorGroups::error(QString message) const
+ErrorMessage ErrorGroups::error(const QString &message) const
{
return ErrorMessage(message, *this, ErrorLevel::Error);
}
-ErrorMessage ErrorGroups::error(Dumper message) const
+ErrorMessage ErrorGroups::error(const Dumper &message) const
{
return ErrorMessage(dumperToString(message), *this, ErrorLevel::Error);
}
@@ -248,17 +252,31 @@ int ErrorGroups::cmp(const ErrorGroups &o1, const ErrorGroups &o2)
return 0;
}
-ErrorMessage::ErrorMessage(QString msg, ErrorGroups errorGroups, Level level, Path element, QString canonicalFilePath, SourceLocation location, QLatin1String errorId):
- errorId(errorId), message(msg), errorGroups(errorGroups), level(level), path(element), file(canonicalFilePath), location(location)
+ErrorMessage::ErrorMessage(
+ const QString &msg, const ErrorGroups &errorGroups, Level level, const Path &element,
+ const QString &canonicalFilePath, SourceLocation location, QLatin1String errorId)
+ : errorId(errorId)
+ , message(msg)
+ , errorGroups(errorGroups)
+ , level(level)
+ , path(element)
+ , file(canonicalFilePath)
+ , location(location)
{
if (level == Level::Fatal) // we should not end up here, it should have been handled at a higher level already
errorGroups.fatal(msg, element, canonicalFilePath, location);
}
-ErrorMessage::ErrorMessage(ErrorGroups errorGroups, const DiagnosticMessage &msg, Path element,
- QString canonicalFilePath, QLatin1String errorId):
- errorId(errorId), message(msg.message), errorGroups(errorGroups),
- level(errorLevelFromQtMsgType(msg.type)), path(element), file(canonicalFilePath), location(msg.loc)
+ErrorMessage::ErrorMessage(
+ const ErrorGroups &errorGroups, const DiagnosticMessage &msg, const Path &element,
+ const QString &canonicalFilePath, QLatin1String errorId)
+ : errorId(errorId)
+ , message(msg.message)
+ , errorGroups(errorGroups)
+ , level(errorLevelFromQtMsgType(msg.type))
+ , path(element)
+ , file(canonicalFilePath)
+ , location(msg.loc)
{
if (level == Level::Fatal) // we should not end up here, it should have been handled at a higher level already
errorGroups.fatal(msg.message, element, canonicalFilePath, location);
@@ -287,6 +305,10 @@ struct StorableMsg {
msg(e)
{}
+ StorableMsg(ErrorMessage &&e):
+ msg(std::move(e))
+ {}
+
ErrorMessage msg;
};
@@ -296,12 +318,12 @@ static QHash<QLatin1String, StorableMsg> &registry()
return r;
}
-QLatin1String ErrorMessage::msg(const char *errorId, ErrorMessage err)
+QLatin1String ErrorMessage::msg(const char *errorId, ErrorMessage &&err)
{
- return msg(QLatin1String(errorId), err);
+ return msg(QLatin1String(errorId), std::move(err));
}
-QLatin1String ErrorMessage::msg(QLatin1String errorId, ErrorMessage err)
+QLatin1String ErrorMessage::msg(QLatin1String errorId, ErrorMessage &&err)
{
bool doubleRegister = false;
ErrorMessage old = myErrors().debug(u"dummy");
@@ -312,14 +334,14 @@ QLatin1String ErrorMessage::msg(QLatin1String errorId, ErrorMessage err)
old = r[err.errorId].msg;
doubleRegister = true;
}
- r[errorId] = StorableMsg{err.withErrorId(errorId)};
+ r[errorId] = StorableMsg{std::move(err.withErrorId(errorId))};
}
if (doubleRegister)
defaultErrorHandler(myErrors().warning(tr("Double registration of error %1: (%2) vs (%3)").arg(errorId, err.withErrorId(errorId).toString(), old.toString())));
return errorId;
}
-void ErrorMessage::visitRegisteredMessages(function_ref<bool (ErrorMessage)> visitor)
+void ErrorMessage::visitRegisteredMessages(function_ref<bool(const ErrorMessage &)> visitor)
{
QHash<QLatin1String, StorableMsg> r;
{
@@ -336,7 +358,7 @@ void ErrorMessage::visitRegisteredMessages(function_ref<bool (ErrorMessage)> vis
ErrorMessage ErrorMessage::load(QLatin1String errorId)
{
- ErrorMessage res = myErrors().error([errorId](Sink s){
+ ErrorMessage res = myErrors().error([errorId](const Sink &s){
s(u"Unregistered error ");
s(QString(errorId)); });
{
@@ -363,7 +385,7 @@ ErrorMessage &ErrorMessage::withPath(const Path &path)
return *this;
}
-ErrorMessage &ErrorMessage::withFile(QString f)
+ErrorMessage &ErrorMessage::withFile(const QString &f)
{
file=f;
return *this;
@@ -381,15 +403,15 @@ ErrorMessage &ErrorMessage::withLocation(SourceLocation loc)
return *this;
}
-ErrorMessage &ErrorMessage::withItem(DomItem el)
+ErrorMessage &ErrorMessage::withItem(const DomItem &el)
{
if (path.length() == 0)
path = el.canonicalPath();
if (file.isEmpty())
file = el.canonicalFilePath();
if (location == SourceLocation()) {
- if (const FileLocations *fLocPtr = FileLocations::fileLocationsPtr(el)) {
- location = fLocPtr->regions.value(QString(), fLocPtr->fullRegion);
+ if (const FileLocations::Tree tree = FileLocations::treeOf(el)) {
+ location = FileLocations::region(tree, MainRegion);
}
}
return *this;
@@ -404,7 +426,7 @@ ErrorMessage ErrorMessage::handle(const ErrorHandler &errorHandler)
return *this;
}
-void ErrorMessage::dump(Sink sink) const
+void ErrorMessage::dump(const Sink &sink) const
{
if (!file.isEmpty()) {
sink(file);
@@ -436,7 +458,7 @@ void ErrorMessage::dump(Sink sink) const
QString ErrorMessage::toString() const
{
- return dumperToString([this](Sink sink){ this->dump(sink); });
+ return dumperToString([this](const Sink &sink){ this->dump(sink); });
}
QCborMap ErrorMessage::toCbor() const
@@ -463,7 +485,7 @@ QCborMap ErrorMessage::toCbor() const
*/
void errorToQDebug(const ErrorMessage &error)
{
- dumperToQDebug([&error](Sink s){ error.dump(s); }, error.level);
+ dumperToQDebug([&error](const Sink &s){ error.dump(s); }, error.level);
}
/*!
@@ -474,7 +496,7 @@ void silentError(const ErrorMessage &)
{
}
-void errorHandlerHandler(const ErrorMessage &msg, ErrorHandler *h = nullptr)
+void errorHandlerHandler(const ErrorMessage &msg, const ErrorHandler *h = nullptr)
{
static ErrorHandler handler = &errorToQDebug;
if (h) {
@@ -497,7 +519,7 @@ void defaultErrorHandler(const ErrorMessage &error)
* \internal
* \brief Sets the default error handler
*/
-void setDefaultErrorHandler(ErrorHandler h)
+void setDefaultErrorHandler(const ErrorHandler &h)
{
errorHandlerHandler(ErrorMessage(QString(), ErrorGroups({})), &h);
}
diff --git a/src/qmldom/qqmldomerrormessage_p.h b/src/qmldom/qqmldomerrormessage_p.h
index ad9c1d56ec..20e2d817e0 100644
--- a/src/qmldom/qqmldomerrormessage_p.h
+++ b/src/qmldom/qqmldomerrormessage_p.h
@@ -51,8 +51,8 @@ public:
{}
- void dump(Sink sink) const;
- void dumpId(Sink sink) const;
+ void dump(const Sink &sink) const;
+ void dumpId(const Sink &sink) const;
QLatin1String groupId() const;
QString groupName() const;
@@ -63,23 +63,28 @@ public:
class QMLDOM_EXPORT ErrorGroups{
Q_GADGET
public:
- void dump(Sink sink) const;
- void dumpId(Sink sink) const;
+ void dump(const Sink &sink) const;
+ void dumpId(const Sink &sink) const;
QCborArray toCbor() const;
- [[nodiscard]] ErrorMessage errorMessage(Dumper msg, ErrorLevel level, Path element = Path(), QString canonicalFilePath = QString(), SourceLocation location = SourceLocation()) const;
- [[nodiscard]] ErrorMessage errorMessage(const DiagnosticMessage &msg, Path element = Path(), QString canonicalFilePath = QString()) const;
-
- void fatal(Dumper msg, Path element = Path(), QStringView canonicalFilePath = u"", SourceLocation location = SourceLocation()) const;
-
- [[nodiscard]] ErrorMessage debug(QString message) const;
- [[nodiscard]] ErrorMessage debug(Dumper message) const;
- [[nodiscard]] ErrorMessage info(QString message) const;
- [[nodiscard]] ErrorMessage info(Dumper message) const;
- [[nodiscard]] ErrorMessage warning(QString message) const;
- [[nodiscard]] ErrorMessage warning(Dumper message) const;
- [[nodiscard]] ErrorMessage error(QString message) const;
- [[nodiscard]] ErrorMessage error(Dumper message) const;
+ [[nodiscard]] ErrorMessage errorMessage(
+ const Dumper &msg, ErrorLevel level, const Path &element = Path(),
+ const QString &canonicalFilePath = QString(), SourceLocation location = SourceLocation()) const;
+ [[nodiscard]] ErrorMessage errorMessage(
+ const DiagnosticMessage &msg, const Path &element = Path(),
+ const QString &canonicalFilePath = QString()) const;
+
+ void fatal(const Dumper &msg, const Path &element = Path(), QStringView canonicalFilePath = u"",
+ SourceLocation location = SourceLocation()) const;
+
+ [[nodiscard]] ErrorMessage debug(const QString &message) const;
+ [[nodiscard]] ErrorMessage debug(const Dumper &message) const;
+ [[nodiscard]] ErrorMessage info(const QString &message) const;
+ [[nodiscard]] ErrorMessage info(const Dumper &message) const;
+ [[nodiscard]] ErrorMessage warning(const QString &message) const;
+ [[nodiscard]] ErrorMessage warning(const Dumper &message) const;
+ [[nodiscard]] ErrorMessage error(const QString &message) const;
+ [[nodiscard]] ErrorMessage error(const Dumper &message) const;
static int cmp(const ErrorGroups &g1, const ErrorGroups &g2);
@@ -99,9 +104,9 @@ class QMLDOM_EXPORT ErrorMessage { // reuse Some of the other DiagnosticMessages
public:
using Level = ErrorLevel;
// error registry (usage is optional)
- static QLatin1String msg(const char *errorId, ErrorMessage err);
- static QLatin1String msg(QLatin1String errorId, ErrorMessage err);
- static void visitRegisteredMessages(function_ref<bool(ErrorMessage)> visitor);
+ static QLatin1String msg(const char *errorId, ErrorMessage &&err);
+ static QLatin1String msg(QLatin1String errorId, ErrorMessage &&err);
+ static void visitRegisteredMessages(function_ref<bool (const ErrorMessage &)> visitor);
[[nodiscard]] static ErrorMessage load(QLatin1String errorId);
[[nodiscard]] static ErrorMessage load(const char *errorId);
template<typename... T>
@@ -111,19 +116,24 @@ public:
return res;
}
- ErrorMessage(QString message, ErrorGroups errorGroups, Level level = Level::Warning, Path path = Path(), QString file = QString(), SourceLocation location = SourceLocation(), QLatin1String errorId = QLatin1String(""));
- ErrorMessage(ErrorGroups errorGroups, const DiagnosticMessage &msg, Path path = Path(), QString file = QString(), QLatin1String errorId = QLatin1String(""));
+ ErrorMessage(
+ const QString &message, const ErrorGroups &errorGroups, Level level = Level::Warning,
+ const Path &path = Path(), const QString &file = QString(),
+ SourceLocation location = SourceLocation(), QLatin1String errorId = QLatin1String(""));
+ ErrorMessage(
+ const ErrorGroups &errorGroups, const DiagnosticMessage &msg, const Path &path = Path(),
+ const QString &file = QString(), QLatin1String errorId = QLatin1String(""));
[[nodiscard]] ErrorMessage &withErrorId(QLatin1String errorId);
[[nodiscard]] ErrorMessage &withPath(const Path &);
- [[nodiscard]] ErrorMessage &withFile(QString);
+ [[nodiscard]] ErrorMessage &withFile(const QString &);
[[nodiscard]] ErrorMessage &withFile(QStringView);
[[nodiscard]] ErrorMessage &withLocation(SourceLocation);
- [[nodiscard]] ErrorMessage &withItem(DomItem);
+ [[nodiscard]] ErrorMessage &withItem(const DomItem &);
ErrorMessage handle(const ErrorHandler &errorHandler=nullptr);
- void dump(Sink s) const;
+ void dump(const Sink &s) const;
QString toString() const;
QCborMap toCbor() const;
friend int compare(const ErrorMessage &msg1, const ErrorMessage &msg2)
@@ -203,7 +213,7 @@ QMLDOM_EXPORT void silentError(const ErrorMessage &);
QMLDOM_EXPORT void errorToQDebug(const ErrorMessage &);
QMLDOM_EXPORT void defaultErrorHandler(const ErrorMessage &);
-QMLDOM_EXPORT void setDefaultErrorHandler(ErrorHandler h);
+QMLDOM_EXPORT void setDefaultErrorHandler(const ErrorHandler &h);
} // end namespace Dom
} // end namespace QQmlJS
diff --git a/src/qmldom/qqmldomexternalitems.cpp b/src/qmldom/qqmldomexternalitems.cpp
index d46c258f94..6f48aa19e3 100644
--- a/src/qmldom/qqmldomexternalitems.cpp
+++ b/src/qmldom/qqmldomexternalitems.cpp
@@ -6,6 +6,7 @@
#include "qqmldomcomments_p.h"
#include "qqmldommock_p.h"
#include "qqmldomelements_p.h"
+#include "qqmldom_utils_p.h"
#include <QtQml/private/qqmljslexer_p.h>
#include <QtQml/private/qqmljsparser_p.h>
@@ -15,7 +16,6 @@
#include <QtCore/QDir>
#include <QtCore/QScopeGuard>
#include <QtCore/QFileInfo>
-#include <QtCore/QRegularExpression>
#include <QtCore/QRegularExpressionMatch>
#include <algorithm>
@@ -27,15 +27,16 @@ using namespace Qt::StringLiterals;
namespace QQmlJS {
namespace Dom {
-ExternalOwningItem::ExternalOwningItem(QString filePath, QDateTime lastDataUpdateAt, Path path,
- int derivedFrom, QString code)
+ExternalOwningItem::ExternalOwningItem(
+ const QString &filePath, const QDateTime &lastDataUpdateAt, const Path &path,
+ int derivedFrom, const QString &code)
: OwningItem(derivedFrom, lastDataUpdateAt),
m_canonicalFilePath(filePath),
m_code(code),
m_path(path)
{}
-QString ExternalOwningItem::canonicalFilePath(DomItem &) const
+QString ExternalOwningItem::canonicalFilePath(const DomItem &) const
{
return m_canonicalFilePath;
}
@@ -45,7 +46,7 @@ QString ExternalOwningItem::canonicalFilePath() const
return m_canonicalFilePath;
}
-Path ExternalOwningItem::canonicalPath(DomItem &) const
+Path ExternalOwningItem::canonicalPath(const DomItem &) const
{
return m_path;
}
@@ -62,7 +63,7 @@ ErrorGroups QmldirFile::myParsingErrors()
return res;
}
-std::shared_ptr<QmldirFile> QmldirFile::fromPathAndCode(QString path, QString code)
+std::shared_ptr<QmldirFile> QmldirFile::fromPathAndCode(const QString &path, const QString &code)
{
QString canonicalFilePath = QFileInfo(path).canonicalFilePath();
@@ -158,8 +159,11 @@ void QmldirFile::setFromQmldir()
}
for (QQmlDirParser::Import const &imp : m_qmldir.dependencies()) {
QString uri = imp.module;
- if (imp.flags & QQmlDirParser::Import::Auto)
- qWarning() << "qmldir contains dependency with auto keyword";
+ if (imp.flags & QQmlDirParser::Import::Auto) {
+ qCDebug(QQmlJSDomImporting) << "QmldirFile::setFromQmlDir: ignoring initial version"
+ " 'auto' in depends command, using latest version"
+ " instead.";
+ }
Version v = Version(
(imp.version.hasMajorVersion() ? imp.version.majorVersion() : int(Version::Latest)),
(imp.version.hasMinorVersion() ? imp.version.minorVersion()
@@ -192,9 +196,9 @@ void QmldirFile::setFromQmldir()
bool hasErrors = false;
for (auto const &el : m_qmldir.errors(uri().toString())) {
ErrorMessage msg = myParsingErrors().errorMessage(el);
- addErrorLocal(msg);
if (msg.level == ErrorLevel::Error || msg.level == ErrorLevel::Fatal)
hasErrors = true;
+ addErrorLocal(std::move(msg));
}
setIsValid(!hasErrors); // consider it valid also with errors?
m_plugins = m_qmldir.plugins();
@@ -210,7 +214,7 @@ void QmldirFile::setAutoExports(const QList<ModuleAutoExport> &autoExport)
m_autoExports = autoExport;
}
-void QmldirFile::ensureInModuleIndex(DomItem &self, QString uri)
+void QmldirFile::ensureInModuleIndex(const DomItem &self, const QString &uri) const
{
// ModuleIndex keeps the various sources of types from a given module uri import
// this method ensures that all major versions that are contained in this qmldir
@@ -226,17 +230,17 @@ void QmldirFile::ensureInModuleIndex(DomItem &self, QString uri)
}
}
-QCborValue pluginData(QQmlDirParser::Plugin &pl, QStringList cNames)
+QCborValue pluginData(const QQmlDirParser::Plugin &pl, const QStringList &cNames)
{
QCborArray names;
- for (QString n : cNames)
+ for (const QString &n : cNames)
names.append(n);
return QCborMap({ { QCborValue(QStringView(Fields::name)), pl.name },
{ QStringView(Fields::path), pl.path },
{ QStringView(Fields::classNames), names } });
}
-bool QmldirFile::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool QmldirFile::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = ExternalOwningItem::iterateDirectSubpaths(self, visitor);
cont = cont && self.dvValueField(visitor, Fields::uri, uri().toString());
@@ -248,8 +252,8 @@ bool QmldirFile::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
QStringList cNames = classNames();
return self.subListItem(List::fromQListRef<QQmlDirParser::Plugin>(
self.pathFromOwner().field(Fields::plugins), m_plugins,
- [cNames](DomItem &list, const PathEls::PathComponent &p,
- QQmlDirParser::Plugin &plugin) {
+ [cNames](const DomItem &list, const PathEls::PathComponent &p,
+ const QQmlDirParser::Plugin &plugin) {
return list.subDataItem(p, pluginData(plugin, cNames));
}));
});
@@ -259,7 +263,7 @@ bool QmldirFile::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
const QMap<QString, QString> typeFileMap = qmlFiles();
return self.subMapItem(Map(
self.pathFromOwner().field(Fields::qmlFiles),
- [typeFileMap](DomItem &map, QString typeV) {
+ [typeFileMap](const DomItem &map, const QString &typeV) {
QString path = typeFileMap.value(typeV);
if (path.isEmpty())
return DomItem();
@@ -268,7 +272,7 @@ bool QmldirFile::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
PathEls::Key(typeV),
QList<Path>({ Paths::qmlFileObjectPath(path) }));
},
- [typeFileMap](DomItem &) {
+ [typeFileMap](const DomItem &) {
return QSet<QString>(typeFileMap.keyBegin(), typeFileMap.keyEnd());
},
QStringLiteral(u"QList<Reference>")));
@@ -289,41 +293,172 @@ QMap<QString, QString> QmldirFile::qmlFiles() const
return res;
}
-std::shared_ptr<OwningItem> QmlFile::doCopy(DomItem &) const
+JsFile::JsFile(
+ const QString &filePath, const QString &code, const QDateTime &lastDataUpdateAt,
+ int derivedFrom)
+ : ExternalOwningItem(filePath, lastDataUpdateAt, Paths::qmlFilePath(filePath), derivedFrom,
+ code)
{
- auto res = std::make_shared<QmlFile>(*this);
+ m_engine = std::make_shared<QQmlJS::Engine>();
+ LegacyDirectivesCollector directivesCollector(*this);
+ m_engine->setDirectives(&directivesCollector);
+
+ QQmlJS::Lexer lexer(m_engine.get());
+ lexer.setCode(code, /*lineno = */ 1, /*qmlMode=*/false);
+ QQmlJS::Parser parser(m_engine.get());
+
+ bool isESM = filePath.endsWith(u".mjs", Qt::CaseInsensitive);
+ bool isValid = isESM ? parser.parseModule() : parser.parseProgram();
+ setIsValid(isValid);
+
+ const auto diagnostics = parser.diagnosticMessages();
+ for (const DiagnosticMessage &msg : diagnostics) {
+ addErrorLocal(
+ std::move(myParsingErrors().errorMessage(msg).withFile(filePath).withPath(m_path)));
+ }
+
+ auto astComments = std::make_shared<AstComments>(m_engine);
+
+ CommentCollector collector;
+ collector.collectComments(m_engine, parser.rootNode(), astComments);
+ m_script = std::make_shared<ScriptExpression>(code, m_engine, parser.rootNode(), astComments,
+ isESM ? ScriptExpression::ExpressionType::ESMCode
+ : ScriptExpression::ExpressionType::JSCode);
+}
+
+ErrorGroups JsFile::myParsingErrors()
+{
+ static ErrorGroups res = { { DomItem::domErrorGroup, NewErrorGroup("JsFile"),
+ NewErrorGroup("Parsing") } };
return res;
}
-QmlFile::QmlFile(const QmlFile &o)
- : ExternalOwningItem(o),
- m_engine(o.m_engine),
- m_ast(o.m_ast),
- m_astComments(o.m_astComments),
- m_comments(o.m_comments),
- m_fileLocationsTree(o.m_fileLocationsTree),
- m_components(o.m_components),
- m_pragmas(o.m_pragmas),
- m_imports(o.m_imports),
- m_importScope(o.m_importScope)
+bool JsFile::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
- if (m_astComments)
- m_astComments = std::make_shared<AstComments>(*m_astComments);
+ bool cont = ExternalOwningItem::iterateDirectSubpaths(self, visitor);
+ cont = cont && self.dvWrapField(visitor, Fields::fileLocationsTree, m_fileLocationsTree);
+ if (m_script)
+ cont = cont && self.dvItemField(visitor, Fields::expression, [this, &self]() {
+ return self.subOwnerItem(PathEls::Field(Fields::expression), m_script);
+ });
+ return cont;
+}
+
+void JsFile::writeOut(const DomItem &self, OutWriter &ow) const
+{
+ writeOutDirectives(ow);
+ ow.ensureNewline(2);
+ if (DomItem script = self.field(Fields::expression)) {
+ ow.ensureNewline();
+ script.writeOut(ow);
+ }
}
-QmlFile::QmlFile(QString filePath, QString code, QDateTime lastDataUpdateAt, int derivedFrom)
+void JsFile::addFileImport(const QString &jsfile, const QString &module)
+{
+ LegacyImport import;
+ import.fileName = jsfile;
+ import.asIdentifier = module;
+ m_imports.append(std::move(import));
+}
+
+void JsFile::addModuleImport(const QString &uri, const QString &version, const QString &module)
+{
+ LegacyImport import;
+ import.uri = uri;
+ import.version = version;
+ import.asIdentifier = module;
+ m_imports.append(std::move(import));
+}
+
+void JsFile::LegacyPragmaLibrary::writeOut(OutWriter &lw) const
+{
+ lw.write(u".pragma").space().write(u"library").ensureNewline();
+}
+
+void JsFile::LegacyImport::writeOut(OutWriter &lw) const
+{
+ // either filename or module uri must be present
+ Q_ASSERT(!fileName.isEmpty() || !uri.isEmpty());
+
+ lw.write(u".import").space();
+ if (!uri.isEmpty()) {
+ lw.write(uri).space();
+ if (!version.isEmpty()) {
+ lw.write(version).space();
+ }
+ } else {
+ lw.write(u"\"").write(fileName).write(u"\"").space();
+ }
+ lw.writeRegion(AsTokenRegion).space().write(asIdentifier);
+
+ lw.ensureNewline();
+}
+
+/*!
+ * \internal JsFile::writeOutDirectives
+ * \brief Performs writeOut of the .js Directives (.import, .pragma)
+ *
+ * Watch out!
+ * Currently directives in .js files do not have representative AST::Node-s (see QTBUG-119770),
+ * which makes it hard to preserve attached comments during the WriteOut process,
+ * because currently they are being attached to the first AST::Node.
+ * In case when the first AST::Node is absent, they are not collected, hence lost.
+ */
+void JsFile::writeOutDirectives(OutWriter &ow) const
+{
+ if (m_pragmaLibrary.has_value()) {
+ m_pragmaLibrary->writeOut(ow);
+ }
+ for (const auto &import : m_imports) {
+ import.writeOut(ow);
+ }
+}
+
+std::shared_ptr<OwningItem> QmlFile::doCopy(const DomItem &) const
+{
+ auto res = std::make_shared<QmlFile>(*this);
+ return res;
+}
+
+/*!
+ \class QmlFile
+
+ A QmlFile, when loaded in a DomEnvironment that has the DomCreationOption::WithSemanticAnalysis,
+ will be lazily constructed. That means that its member m_lazyMembers is uninitialized, and will
+ only be populated when it is accessed (through a getter, a setter or the DomItem interface).
+
+ The reason for the laziness is that the qqmljsscopes are created lazily and at the same time as
+ the Dom QmlFile representations. So instead of eagerly generating all qqmljsscopes when
+ constructing the Dom, the QmlFile itself becomes lazy and will only be populated on demand at
+ the same time as the corresponding qqmljsscopes.
+
+ The QDeferredFactory<QQmlJSScope> will, when the qqmljsscope is populated, take care of
+ populating all fields of the QmlFile.
+ Therefore, population of the QmlFile is done by populating the qqmljsscope.
+
+*/
+
+QmlFile::QmlFile(
+ const QString &filePath, const QString &code, const QDateTime &lastDataUpdateAt,
+ int derivedFrom, RecoveryOption option)
: ExternalOwningItem(filePath, lastDataUpdateAt, Paths::qmlFilePath(filePath), derivedFrom,
code),
- m_engine(new QQmlJS::Engine),
- m_astComments(new AstComments(m_engine)),
- m_fileLocationsTree(FileLocations::createTree(canonicalPath()))
+ m_engine(new QQmlJS::Engine)
{
QQmlJS::Lexer lexer(m_engine.get());
lexer.setCode(code, /*lineno = */ 1, /*qmlMode=*/true);
QQmlJS::Parser parser(m_engine.get());
+ if (option == EnableParserRecovery) {
+ parser.setIdentifierInsertionEnabled(true);
+ parser.setIncompleteBindingsEnabled(true);
+ }
m_isValid = parser.parse();
- for (DiagnosticMessage msg : parser.diagnosticMessages())
- addErrorLocal(myParsingErrors().errorMessage(msg).withFile(filePath).withPath(m_path));
+ const auto diagnostics = parser.diagnosticMessages();
+ for (const DiagnosticMessage &msg : diagnostics) {
+ addErrorLocal(
+ std::move(myParsingErrors().errorMessage(msg).withFile(filePath).withPath(m_path)));
+ }
m_ast = parser.ast();
}
@@ -334,34 +469,38 @@ ErrorGroups QmlFile::myParsingErrors()
return res;
}
-bool QmlFile::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool QmlFile::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
+ auto &members = lazyMembers();
bool cont = ExternalOwningItem::iterateDirectSubpaths(self, visitor);
- cont = cont && self.dvWrapField(visitor, Fields::components, m_components);
- cont = cont && self.dvWrapField(visitor, Fields::pragmas, m_pragmas);
- cont = cont && self.dvWrapField(visitor, Fields::imports, m_imports);
- cont = cont && self.dvWrapField(visitor, Fields::importScope, m_importScope);
- cont = cont && self.dvWrapField(visitor, Fields::fileLocationsTree, m_fileLocationsTree);
- cont = cont && self.dvWrapField(visitor, Fields::comments, m_comments);
- cont = cont && self.dvWrapField(visitor, Fields::astComments, m_astComments);
+ cont = cont && self.dvWrapField(visitor, Fields::components, members.m_components);
+ cont = cont && self.dvWrapField(visitor, Fields::pragmas, members.m_pragmas);
+ cont = cont && self.dvWrapField(visitor, Fields::imports, members.m_imports);
+ cont = cont && self.dvWrapField(visitor, Fields::importScope, members.m_importScope);
+ cont = cont
+ && self.dvWrapField(visitor, Fields::fileLocationsTree, members.m_fileLocationsTree);
+ cont = cont && self.dvWrapField(visitor, Fields::comments, members.m_comments);
+ cont = cont && self.dvWrapField(visitor, Fields::astComments, members.m_astComments);
return cont;
}
-DomItem QmlFile::field(DomItem &self, QStringView name)
+DomItem QmlFile::field(const DomItem &self, QStringView name) const
{
+ ensurePopulated();
if (name == Fields::components)
- return self.wrapField(Fields::components, m_components);
+ return self.wrapField(Fields::components, lazyMembers().m_components);
return DomBase::field(self, name);
}
-void QmlFile::addError(DomItem &self, ErrorMessage msg)
+void QmlFile::addError(const DomItem &self, ErrorMessage &&msg)
{
- self.containingObject().addError(msg);
+ self.containingObject().addError(std::move(msg));
}
-void QmlFile::writeOut(DomItem &self, OutWriter &ow) const
+void QmlFile::writeOut(const DomItem &self, OutWriter &ow) const
{
- for (DomItem &p : self.field(Fields::pragmas).values()) {
+ ensurePopulated();
+ for (const DomItem &p : self.field(Fields::pragmas).values()) {
p.writeOut(ow);
}
for (auto i : self.field(Fields::imports).values()) {
@@ -372,20 +511,20 @@ void QmlFile::writeOut(DomItem &self, OutWriter &ow) const
mainC.writeOut(ow);
}
-std::shared_ptr<OwningItem> GlobalScope::doCopy(DomItem &self) const
+std::shared_ptr<OwningItem> GlobalScope::doCopy(const DomItem &self) const
{
auto res = std::make_shared<GlobalScope>(
canonicalFilePath(self), lastDataUpdateAt(), revision());
return res;
}
-bool GlobalScope::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool GlobalScope::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = ExternalOwningItem::iterateDirectSubpaths(self, visitor);
return cont;
}
-void QmltypesFile::ensureInModuleIndex(DomItem &self)
+void QmltypesFile::ensureInModuleIndex(const DomItem &self) const
{
auto it = m_uris.begin();
auto end = m_uris.end();
@@ -403,7 +542,7 @@ void QmltypesFile::ensureInModuleIndex(DomItem &self)
}
}
-bool QmltypesFile::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool QmltypesFile::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = ExternalOwningItem::iterateDirectSubpaths(self, visitor);
cont = cont && self.dvWrapField(visitor, Fields::components, m_components);
@@ -411,30 +550,31 @@ bool QmltypesFile::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
cont = cont && self.dvItemField(visitor, Fields::uris, [this, &self]() {
return self.subMapItem(Map::fromMapRef<QSet<int>>(
self.pathFromOwner().field(Fields::uris), m_uris,
- [](DomItem &map, const PathEls::PathComponent &p, QSet<int> &el) {
+ [](const DomItem &map, const PathEls::PathComponent &p, const QSet<int> &el) {
QList<int> l(el.cbegin(), el.cend());
std::sort(l.begin(), l.end());
return map.subListItem(
List::fromQList<int>(map.pathFromOwner().appendComponent(p), l,
- [](DomItem &list, const PathEls::PathComponent &p,
- int &el) { return list.subDataItem(p, el); }));
+ [](const DomItem &list, const PathEls::PathComponent &p,
+ int el) { return list.subDataItem(p, el); }));
}));
});
cont = cont && self.dvWrapField(visitor, Fields::imports, m_imports);
return cont;
}
-QmlDirectory::QmlDirectory(QString filePath, QStringList dirList, QDateTime lastDataUpdateAt,
- int derivedFrom)
+QmlDirectory::QmlDirectory(
+ const QString &filePath, const QStringList &dirList, const QDateTime &lastDataUpdateAt,
+ int derivedFrom)
: ExternalOwningItem(filePath, lastDataUpdateAt, Paths::qmlDirectoryPath(filePath), derivedFrom,
dirList.join(QLatin1Char('\n')))
{
- for (QString f : dirList) {
+ for (const QString &f : dirList) {
addQmlFilePath(f);
}
}
-bool QmlDirectory::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool QmlDirectory::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = ExternalOwningItem::iterateDirectSubpaths(self, visitor);
cont = cont && self.dvWrapField(visitor, Fields::exports, m_exports);
@@ -442,7 +582,7 @@ bool QmlDirectory::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
QDir baseDir(canonicalFilePath());
return self.subMapItem(Map(
self.pathFromOwner().field(Fields::qmlFiles),
- [this, baseDir](DomItem &map, QString key) -> DomItem {
+ [this, baseDir](const DomItem &map, const QString &key) -> DomItem {
QList<Path> res;
auto it = m_qmlFiles.find(key);
while (it != m_qmlFiles.end() && it.key() == key) {
@@ -452,7 +592,7 @@ bool QmlDirectory::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
}
return map.subReferencesItem(PathEls::Key(key), res);
},
- [this](DomItem &) {
+ [this](const DomItem &) {
auto keys = m_qmlFiles.keys();
return QSet<QString>(keys.begin(), keys.end());
},
@@ -461,11 +601,13 @@ bool QmlDirectory::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
return cont;
}
-bool QmlDirectory::addQmlFilePath(QString relativePath)
+bool QmlDirectory::addQmlFilePath(const QString &relativePath)
{
- QRegularExpression qmlFileRe(QRegularExpression::anchoredPattern(
- uR"((?<compName>[a-zA-z0-9_]+)\.(?:qml|qmlannotation))"));
- QRegularExpressionMatch m = qmlFileRe.match(relativePath);
+ static const QRegularExpression qmlFileRegularExpression{
+ QRegularExpression::anchoredPattern(
+ uR"((?<compName>[a-zA-z0-9_]+)\.(?:qml|qmlannotation|ui\.qml))")
+ };
+ QRegularExpressionMatch m = qmlFileRegularExpression.match(relativePath);
if (m.hasMatch() && !m_qmlFiles.values(m.captured(u"compName")).contains(relativePath)) {
m_qmlFiles.insert(m.captured(u"compName"), relativePath);
Export e;
diff --git a/src/qmldom/qqmldomexternalitems_p.h b/src/qmldom/qqmldomexternalitems_p.h
index 8072d2fa8a..97328b40de 100644
--- a/src/qmldom/qqmldomexternalitems_p.h
+++ b/src/qmldom/qqmldomexternalitems_p.h
@@ -23,9 +23,12 @@
#include <QtQml/private/qqmljsast_p.h>
#include <QtQml/private/qqmljsengine_p.h>
#include <QtQml/private/qqmldirparser_p.h>
+#include <QtQmlCompiler/private/qqmljstyperesolver_p.h>
#include <QtCore/QMetaType>
+#include <QtCore/qregularexpression.h>
#include <limits>
+#include <memory>
Q_DECLARE_METATYPE(QQmlDirParser::Plugin)
@@ -46,14 +49,15 @@ Every owning item has a file or directory it refers to.
*/
class QMLDOM_EXPORT ExternalOwningItem: public OwningItem {
public:
- ExternalOwningItem(QString filePath, QDateTime lastDataUpdateAt, Path pathFromTop,
- int derivedFrom = 0, QString code = QString());
+ ExternalOwningItem(
+ const QString &filePath, const QDateTime &lastDataUpdateAt, const Path &pathFromTop,
+ int derivedFrom = 0, const QString &code = QString());
ExternalOwningItem(const ExternalOwningItem &o) = default;
- QString canonicalFilePath(DomItem &) const override;
+ QString canonicalFilePath(const DomItem &) const override;
QString canonicalFilePath() const;
- Path canonicalPath(DomItem &) const override;
+ Path canonicalPath(const DomItem &) const override;
Path canonicalPath() const;
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) override
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override
{
bool cont = OwningItem::iterateDirectSubpaths(self, visitor);
cont = cont && self.dvValueLazyField(visitor, Fields::canonicalFilePath, [this]() {
@@ -67,12 +71,12 @@ public:
return cont;
}
- bool iterateSubOwners(DomItem &self, function_ref<bool(DomItem &owner)> visitor) override
+ bool iterateSubOwners(const DomItem &self, function_ref<bool(const DomItem &owner)> visitor) override
{
bool cont = OwningItem::iterateSubOwners(self, visitor);
- cont = cont && self.field(Fields::components).visitKeys([visitor](QString, DomItem &comps) {
- return comps.visitIndexes([visitor](DomItem &comp) {
- return comp.field(Fields::objects).visitIndexes([visitor](DomItem &qmlObj) {
+ cont = cont && self.field(Fields::components).visitKeys([visitor](const QString &, const DomItem &comps) {
+ return comps.visitIndexes([visitor](const DomItem &comp) {
+ return comp.field(Fields::objects).visitIndexes([visitor](const DomItem &qmlObj) {
if (const QmlObject *qmlObjPtr = qmlObj.as<QmlObject>())
return qmlObjPtr->iterateSubOwners(qmlObj, visitor);
Q_ASSERT(false);
@@ -104,7 +108,7 @@ protected:
class QMLDOM_EXPORT QmlDirectory final : public ExternalOwningItem
{
protected:
- std::shared_ptr<OwningItem> doCopy(DomItem &) const override
+ std::shared_ptr<OwningItem> doCopy(const DomItem &) const override
{
return std::make_shared<QmlDirectory>(*this);
}
@@ -112,23 +116,24 @@ protected:
public:
constexpr static DomType kindValue = DomType::QmlDirectory;
DomType kind() const override { return kindValue; }
- QmlDirectory(QString filePath = QString(), QStringList dirList = QStringList(),
- QDateTime lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
- int derivedFrom = 0);
+ QmlDirectory(
+ const QString &filePath = QString(), const QStringList &dirList = QStringList(),
+ const QDateTime &lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
+ int derivedFrom = 0);
QmlDirectory(const QmlDirectory &o) = default;
- std::shared_ptr<QmlDirectory> makeCopy(DomItem &self) const
+ std::shared_ptr<QmlDirectory> makeCopy(const DomItem &self) const
{
return std::static_pointer_cast<QmlDirectory>(doCopy(self));
}
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) override;
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override;
const QMultiMap<QString, Export> &exports() const & { return m_exports; }
const QMultiMap<QString, QString> &qmlFiles() const & { return m_qmlFiles; }
- bool addQmlFilePath(QString relativePath);
+ bool addQmlFilePath(const QString &relativePath);
private:
QMultiMap<QString, Export> m_exports;
@@ -139,7 +144,7 @@ class QMLDOM_EXPORT QmldirFile final : public ExternalOwningItem
{
Q_DECLARE_TR_FUNCTIONS(QmldirFile)
protected:
- std::shared_ptr<OwningItem> doCopy(DomItem &) const override
+ std::shared_ptr<OwningItem> doCopy(const DomItem &) const override
{
auto copy = std::make_shared<QmldirFile>(*this);
return copy;
@@ -151,23 +156,24 @@ public:
static ErrorGroups myParsingErrors();
- QmldirFile(QString filePath = QString(), QString code = QString(),
- QDateTime lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
- int derivedFrom = 0)
+ QmldirFile(
+ const QString &filePath = QString(), const QString &code = QString(),
+ const QDateTime &lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
+ int derivedFrom = 0)
: ExternalOwningItem(filePath, lastDataUpdateAt, Paths::qmldirFilePath(filePath),
derivedFrom, code)
{
}
QmldirFile(const QmldirFile &o) = default;
- static std::shared_ptr<QmldirFile> fromPathAndCode(QString path, QString code);
+ static std::shared_ptr<QmldirFile> fromPathAndCode(const QString &path, const QString &code);
- std::shared_ptr<QmldirFile> makeCopy(DomItem &self) const
+ std::shared_ptr<QmldirFile> makeCopy(const DomItem &self) const
{
return std::static_pointer_cast<QmldirFile>(doCopy(self));
}
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) override;
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override;
QmlUri uri() const { return m_uri; }
@@ -188,7 +194,7 @@ public:
QList<ModuleAutoExport> autoExports() const;
void setAutoExports(const QList<ModuleAutoExport> &autoExport);
- void ensureInModuleIndex(DomItem &self, QString uri);
+ void ensureInModuleIndex(const DomItem &self, const QString &uri) const;
private:
void parse();
@@ -207,7 +213,7 @@ private:
class QMLDOM_EXPORT JsFile final : public ExternalOwningItem
{
protected:
- std::shared_ptr<OwningItem> doCopy(DomItem &) const override
+ std::shared_ptr<OwningItem> doCopy(const DomItem &) const override
{
auto copy = std::make_shared<JsFile>(*this);
return copy;
@@ -216,129 +222,272 @@ protected:
public:
constexpr static DomType kindValue = DomType::JsFile;
DomType kind() const override { return kindValue; }
- JsFile(QString filePath = QString(),
- QDateTime lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
- Path pathFromTop = Path(), int derivedFrom = 0)
+ JsFile(const QString &filePath = QString(),
+ const QDateTime &lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
+ const Path &pathFromTop = Path(), int derivedFrom = 0)
: ExternalOwningItem(filePath, lastDataUpdateAt, pathFromTop, derivedFrom)
{
}
+ JsFile(const QString &filePath = QString(), const QString &code = QString(),
+ const QDateTime &lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
+ int derivedFrom = 0);
JsFile(const JsFile &o) = default;
- std::shared_ptr<JsFile> makeCopy(DomItem &self) const
+ std::shared_ptr<JsFile> makeCopy(const DomItem &self) const
{
return std::static_pointer_cast<JsFile>(doCopy(self));
}
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const
+ override; // iterates the *direct* subpaths, returns false if a quick end was requested
+
std::shared_ptr<QQmlJS::Engine> engine() const { return m_engine; }
JsResource rootComponent() const { return m_rootComponent; }
+ void setFileLocationsTree(const FileLocations::Tree &v) { m_fileLocationsTree = std::move(v); }
+
+ static ErrorGroups myParsingErrors();
+
+ void writeOut(const DomItem &self, OutWriter &lw) const override;
+ void setExpression(const std::shared_ptr<ScriptExpression> &script) { m_script = script; }
+
+ void initPragmaLibrary() { m_pragmaLibrary = LegacyPragmaLibrary{}; };
+ void addFileImport(const QString &jsfile, const QString &module);
+ void addModuleImport(const QString &uri, const QString &version, const QString &module);
+
+private:
+ void writeOutDirectives(OutWriter &lw) const;
+
+ /*
+ Entities with Legacy prefix are here to support formatting of the discouraged
+ .import, .pragma directives in .js files.
+ Taking into account that usage of these directives is discouraged and
+ the fact that current usecase is limited to the formatting of .js, it's arguably should not
+ be exposed and kept private.
+
+ LegacyPragma corresponds to the only one existing .pragma library
+
+ LegacyImport is capable of representing the following import statements:
+ .import T_STRING_LITERAL as T_IDENTIFIER
+ .import T_IDENTIFIER (. T_IDENTIFIER)* (T_VERSION_NUMBER (. T_VERSION_NUMBER)?)? as T_IDENTIFIER
+
+ LegacyDirectivesCollector is a workaround for collecting those directives.
+ At the moment of writing .import, .pragma in .js files do not have corresponding
+ representative AST::Node-s. Collecting of those is happening during the lexing
+ */
+
+ struct LegacyPragmaLibrary
+ {
+ void writeOut(OutWriter &lw) const;
+ };
+
+ struct LegacyImport
+ {
+ QString fileName; // file import
+ QString uri; // module import
+ QString version; // used for module import
+ QString asIdentifier; // .import ... as T_Identifier
+
+ void writeOut(OutWriter &lw) const;
+ };
+
+ class LegacyDirectivesCollector : public QQmlJS::Directives
+ {
+ public:
+ LegacyDirectivesCollector(JsFile &file) : m_file(file){};
+
+ void pragmaLibrary() override { m_file.initPragmaLibrary(); };
+ void importFile(const QString &jsfile, const QString &module, int, int) override
+ {
+ m_file.addFileImport(jsfile, module);
+ };
+ void importModule(const QString &uri, const QString &version, const QString &module, int,
+ int) override
+ {
+ m_file.addModuleImport(uri, version, module);
+ };
+
+ private:
+ JsFile &m_file;
+ };
private:
std::shared_ptr<QQmlJS::Engine> m_engine;
+ std::optional<LegacyPragmaLibrary> m_pragmaLibrary = std::nullopt;
+ QList<LegacyImport> m_imports;
+ std::shared_ptr<ScriptExpression> m_script;
JsResource m_rootComponent;
+ FileLocations::Tree m_fileLocationsTree;
};
class QMLDOM_EXPORT QmlFile final : public ExternalOwningItem
{
protected:
- std::shared_ptr<OwningItem> doCopy(DomItem &self) const override;
+ std::shared_ptr<OwningItem> doCopy(const DomItem &self) const override;
public:
constexpr static DomType kindValue = DomType::QmlFile;
DomType kind() const override { return kindValue; }
- QmlFile(const QmlFile &o);
- QmlFile(QString filePath = QString(), QString code = QString(),
- QDateTime lastDataUpdate = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
- int derivedFrom = 0);
+ enum RecoveryOption { DisableParserRecovery, EnableParserRecovery };
+
+ QmlFile(const QString &filePath = QString(), const QString &code = QString(),
+ const QDateTime &lastDataUpdate = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
+ int derivedFrom = 0, RecoveryOption option = DisableParserRecovery);
static ErrorGroups myParsingErrors();
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor)
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const
override; // iterates the *direct* subpaths, returns false if a quick end was requested
- DomItem field(DomItem &self, QStringView name) const override
- {
- return const_cast<QmlFile *>(this)->field(self, name);
- }
- DomItem field(DomItem &self, QStringView name);
- std::shared_ptr<QmlFile> makeCopy(DomItem &self) const
+ DomItem field(const DomItem &self, QStringView name) const override;
+ std::shared_ptr<QmlFile> makeCopy(const DomItem &self) const
{
return std::static_pointer_cast<QmlFile>(doCopy(self));
}
- void addError(DomItem &self, ErrorMessage msg) override;
+ void addError(const DomItem &self, ErrorMessage &&msg) override;
- const QMultiMap<QString, QmlComponent> &components() const & { return m_components; }
+ const QMultiMap<QString, QmlComponent> &components() const &
+ {
+ return lazyMembers().m_components;
+ }
void setComponents(const QMultiMap<QString, QmlComponent> &components)
{
- m_components = components;
+ lazyMembers().m_components = components;
}
Path addComponent(const QmlComponent &component, AddOption option = AddOption::Overwrite,
QmlComponent **cPtr = nullptr)
{
QStringList nameEls = component.name().split(QChar::fromLatin1('.'));
QString key = nameEls.mid(1).join(QChar::fromLatin1('.'));
- return insertUpdatableElementInMultiMap(Path::Field(Fields::components), m_components, key,
- component, option, cPtr);
+ return insertUpdatableElementInMultiMap(Path::Field(Fields::components), lazyMembers().m_components,
+ key, component, option, cPtr);
}
- void writeOut(DomItem &self, OutWriter &lw) const override;
+ void writeOut(const DomItem &self, OutWriter &lw) const override;
AST::UiProgram *ast() const
{
return m_ast; // avoid making it public? would make moving away from it easier
}
- const QList<Import> &imports() const & { return m_imports; }
- void setImports(const QList<Import> &imports) { m_imports = imports; }
+ const QList<Import> &imports() const &
+ {
+ return lazyMembers().m_imports;
+ }
+ void setImports(const QList<Import> &imports) { lazyMembers().m_imports = imports; }
Path addImport(const Import &i)
{
- index_type idx = index_type(m_imports.size());
- m_imports.append(i);
+ auto &members = lazyMembers();
+ index_type idx = index_type(members.m_imports.size());
+ members.m_imports.append(i);
if (i.uri.isModule()) {
- m_importScope.addImport((i.importId.isEmpty()
- ? QStringList()
- : i.importId.split(QChar::fromLatin1('.'))),
- i.importedPath());
+ members.m_importScope.addImport((i.importId.isEmpty()
+ ? QStringList()
+ : i.importId.split(QChar::fromLatin1('.'))),
+ i.importedPath());
} else {
QString path = i.uri.absoluteLocalPath(canonicalFilePath());
if (!path.isEmpty())
- m_importScope.addImport((i.importId.isEmpty()
- ? QStringList()
- : i.importId.split(QChar::fromLatin1('.'))),
- Paths::qmlDirPath(path));
+ members.m_importScope.addImport(
+ (i.importId.isEmpty() ? QStringList()
+ : i.importId.split(QChar::fromLatin1('.'))),
+ Paths::qmlDirPath(path));
}
return Path::Field(Fields::imports).index(idx);
}
std::shared_ptr<QQmlJS::Engine> engine() const { return m_engine; }
- RegionComments &comments() { return m_comments; }
- std::shared_ptr<AstComments> astComments() const { return m_astComments; }
- void setAstComments(std::shared_ptr<AstComments> comm) { m_astComments = comm; }
- FileLocations::Tree fileLocationsTree() const { return m_fileLocationsTree; }
- void setFileLocationsTree(FileLocations::Tree v) { m_fileLocationsTree = v; }
- const QList<Pragma> &pragmas() const & { return m_pragmas; }
- void setPragmas(QList<Pragma> pragmas) { m_pragmas = pragmas; }
+ RegionComments &comments() { return lazyMembers().m_comments; }
+ std::shared_ptr<AstComments> astComments() const { return lazyMembers().m_astComments; }
+ void setAstComments(const std::shared_ptr<AstComments> &comm) { lazyMembers().m_astComments = comm; }
+ FileLocations::Tree fileLocationsTree() const { return lazyMembers().m_fileLocationsTree; }
+ void setFileLocationsTree(const FileLocations::Tree &v) { lazyMembers().m_fileLocationsTree = v; }
+ const QList<Pragma> &pragmas() const & { return lazyMembers().m_pragmas; }
+ void setPragmas(QList<Pragma> pragmas) { lazyMembers().m_pragmas = pragmas; }
Path addPragma(const Pragma &pragma)
{
- int idx = m_pragmas.size();
- m_pragmas.append(pragma);
+ auto &members = lazyMembers();
+ int idx = members.m_pragmas.size();
+ members.m_pragmas.append(pragma);
return Path::Field(Fields::pragmas).index(idx);
}
- ImportScope &importScope() { return m_importScope; }
- const ImportScope &importScope() const { return m_importScope; }
+ ImportScope &importScope() { return lazyMembers().m_importScope; }
+ const ImportScope &importScope() const { return lazyMembers().m_importScope; }
+
+ std::shared_ptr<QQmlJSTypeResolver> typeResolver() const
+ {
+ return lazyMembers().m_typeResolver;
+ }
+ void setTypeResolverWithDependencies(const std::shared_ptr<QQmlJSTypeResolver> &typeResolver,
+ const QQmlJSTypeResolverDependencies &dependencies)
+ {
+ auto &members = lazyMembers();
+ members.m_typeResolver = typeResolver;
+ members.m_typeResolverDependencies = dependencies;
+ }
+
+ DomCreationOptions creationOptions() const { return lazyMembers().m_creationOptions; }
+
+ QQmlJSScope::ConstPtr handleForPopulation() const
+ {
+ return m_handleForPopulation;
+ }
+
+ void setHandleForPopulation(const QQmlJSScope::ConstPtr &scope)
+ {
+ m_handleForPopulation = scope;
+ }
+
private:
- friend class QmlDomAstCreator;
- std::shared_ptr<Engine> m_engine;
+ // The lazy parts of QmlFile are inside of QmlFileLazy.
+ struct QmlFileLazy
+ {
+ QmlFileLazy(FileLocations::Tree fileLocationsTree, AstComments *astComments)
+ : m_fileLocationsTree(fileLocationsTree), m_astComments(astComments)
+ {
+ }
+ RegionComments m_comments;
+ QMultiMap<QString, QmlComponent> m_components;
+ QList<Pragma> m_pragmas;
+ QList<Import> m_imports;
+ ImportScope m_importScope;
+ FileLocations::Tree m_fileLocationsTree;
+ std::shared_ptr<AstComments> m_astComments;
+ DomCreationOptions m_creationOptions;
+ std::shared_ptr<QQmlJSTypeResolver> m_typeResolver;
+ QQmlJSTypeResolverDependencies m_typeResolverDependencies;
+ };
+ friend class QQmlDomAstCreator;
AST::UiProgram *m_ast; // avoid? would make moving away from it easier
- std::shared_ptr<AstComments> m_astComments;
- RegionComments m_comments;
- FileLocations::Tree m_fileLocationsTree;
- QMultiMap<QString, QmlComponent> m_components;
- QList<Pragma> m_pragmas;
- QList<Import> m_imports;
- ImportScope m_importScope;
+ std::shared_ptr<Engine> m_engine;
+ QQmlJSScope::ConstPtr m_handleForPopulation;
+ mutable std::optional<QmlFileLazy> m_lazyMembers;
+
+ void ensurePopulated() const
+ {
+ if (m_lazyMembers)
+ return;
+
+ m_lazyMembers.emplace(FileLocations::createTree(canonicalPath()), new AstComments(m_engine));
+
+ // populate via the QQmlJSScope by accessing the (lazy) pointer
+ if (m_handleForPopulation.factory()) {
+ // silence no-discard attribute:
+ Q_UNUSED(m_handleForPopulation.data());
+ }
+ }
+ const QmlFileLazy &lazyMembers() const
+ {
+ ensurePopulated();
+ return *m_lazyMembers;
+ }
+ QmlFileLazy &lazyMembers()
+ {
+ ensurePopulated();
+ return *m_lazyMembers;
+ }
};
class QMLDOM_EXPORT QmltypesFile final : public ExternalOwningItem
{
protected:
- std::shared_ptr<OwningItem> doCopy(DomItem &) const override
+ std::shared_ptr<OwningItem> doCopy(const DomItem &) const override
{
auto res = std::make_shared<QmltypesFile>(*this);
return res;
@@ -348,9 +497,10 @@ public:
constexpr static DomType kindValue = DomType::QmltypesFile;
DomType kind() const override { return kindValue; }
- QmltypesFile(QString filePath = QString(), QString code = QString(),
- QDateTime lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
- int derivedFrom = 0)
+ QmltypesFile(
+ const QString &filePath = QString(), const QString &code = QString(),
+ const QDateTime &lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
+ int derivedFrom = 0)
: ExternalOwningItem(filePath, lastDataUpdateAt, Paths::qmltypesFilePath(filePath),
derivedFrom, code)
{
@@ -358,10 +508,10 @@ public:
QmltypesFile(const QmltypesFile &o) = default;
- void ensureInModuleIndex(DomItem &self);
+ void ensureInModuleIndex(const DomItem &self) const;
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override;
- std::shared_ptr<QmltypesFile> makeCopy(DomItem &self) const
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override;
+ std::shared_ptr<QmltypesFile> makeCopy(const DomItem &self) const
{
return std::static_pointer_cast<QmltypesFile>(doCopy(self));
}
@@ -392,7 +542,7 @@ public:
}
const QMap<QString, QSet<int>> &uris() const & { return m_uris; }
- void addUri(QString uri, int majorVersion)
+ void addUri(const QString &uri, int majorVersion)
{
QSet<int> &v = m_uris[uri];
if (!v.contains(majorVersion)) {
@@ -410,30 +560,31 @@ private:
class QMLDOM_EXPORT GlobalScope final : public ExternalOwningItem
{
protected:
- std::shared_ptr<OwningItem> doCopy(DomItem &) const override;
+ std::shared_ptr<OwningItem> doCopy(const DomItem &) const override;
public:
constexpr static DomType kindValue = DomType::GlobalScope;
DomType kind() const override { return kindValue; }
- GlobalScope(QString filePath = QString(),
- QDateTime lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
- int derivedFrom = 0)
+ GlobalScope(
+ const QString &filePath = QString(),
+ const QDateTime &lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
+ int derivedFrom = 0)
: ExternalOwningItem(filePath, lastDataUpdateAt, Paths::globalScopePath(filePath),
derivedFrom)
{
setIsValid(true);
}
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) override;
- std::shared_ptr<GlobalScope> makeCopy(DomItem &self) const
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override;
+ std::shared_ptr<GlobalScope> makeCopy(const DomItem &self) const
{
return std::static_pointer_cast<GlobalScope>(doCopy(self));
}
QString name() const { return m_name; }
Language language() const { return m_language; }
GlobalComponent rootComponent() const { return m_rootComponent; }
- void setName(QString name) { m_name = name; }
+ void setName(const QString &name) { m_name = name; }
void setLanguage(Language language) { m_language = language; }
void setRootComponent(const GlobalComponent &ob)
{
diff --git a/src/qmldom/qqmldomfieldfilter.cpp b/src/qmldom/qqmldomfieldfilter.cpp
index 17529de4e9..67b33bbb7e 100644
--- a/src/qmldom/qqmldomfieldfilter.cpp
+++ b/src/qmldom/qqmldomfieldfilter.cpp
@@ -1,7 +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 "qqmldomfieldfilter_p.h"
#include "qqmldompath_p.h"
+#include "qqmldomitem_p.h"
#include "QtCore/qglobal.h"
QT_BEGIN_NAMESPACE
@@ -61,7 +63,7 @@ QString FieldFilter::describeFieldsFilter() const
return fieldFilterStr;
}
-bool FieldFilter::operator()(DomItem &obj, Path p, DomItem &i) const
+bool FieldFilter::operator()(const DomItem &obj, const Path &p, const DomItem &i) const
{
if (p)
return this->operator()(obj, p.component(0), i);
@@ -69,7 +71,7 @@ bool FieldFilter::operator()(DomItem &obj, Path p, DomItem &i) const
return this->operator()(obj, PathEls::Empty(), i);
}
-bool FieldFilter::operator()(DomItem &base, const PathEls::PathComponent &c, DomItem &obj) const
+bool FieldFilter::operator()(const DomItem &base, const PathEls::PathComponent &c, const DomItem &obj) const
{
DomType baseK = base.internalKind();
if (c.kind() == Path::Kind::Field) {
@@ -95,7 +97,7 @@ bool FieldFilter::operator()(DomItem &base, const PathEls::PathComponent &c, Dom
return true;
}
-bool FieldFilter::addFilter(QString fFields)
+bool FieldFilter::addFilter(const QString &fFields)
{
// parses a base filter of the form <op><typeName>:<fieldName> or <op><fieldName>
// as described in this class documentation
@@ -119,6 +121,11 @@ bool FieldFilter::addFilter(QString fFields)
return true;
}
+FieldFilter FieldFilter::noFilter()
+{
+ return FieldFilter{ {}, {} };
+}
+
FieldFilter FieldFilter::defaultFilter()
{
QMultiMap<QString, QString> fieldFilterAdd { { QLatin1String("ScriptExpression"),
diff --git a/src/qmldom/qqmldomfieldfilter_p.h b/src/qmldom/qqmldomfieldfilter_p.h
index e40ce4459e..8ee5caa2c4 100644
--- a/src/qmldom/qqmldomfieldfilter_p.h
+++ b/src/qmldom/qqmldomfieldfilter_p.h
@@ -15,11 +15,13 @@
// We mean it.
//
+#include "qqmldom_fwd_p.h"
#include "qqmldom_global.h"
-#include "qqmldomitem_p.h"
-#include "qqmldomastcreator_p.h"
-#include "qqmldomcomments_p.h"
+#include "qqmldompath_p.h"
+#include <QtCore/qobject.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qset.h>
#include <QtQml/private/qqmljsastvisitor_p.h>
QT_BEGIN_NAMESPACE
@@ -32,9 +34,10 @@ class QMLDOM_EXPORT FieldFilter
Q_GADGET
public:
QString describeFieldsFilter() const;
- bool addFilter(QString f);
- bool operator()(DomItem &, Path, DomItem &) const;
- bool operator()(DomItem &, const PathEls::PathComponent &c, DomItem &) const;
+ bool addFilter(const QString &f);
+ bool operator()(const DomItem &, const Path &, const DomItem &) const;
+ bool operator()(const DomItem &, const PathEls::PathComponent &c, const DomItem &) const;
+ static FieldFilter noFilter();
static FieldFilter defaultFilter();
static FieldFilter noLocationFilter();
static FieldFilter compareFilter();
diff --git a/src/qmldom/qqmldomfilewriter.cpp b/src/qmldom/qqmldomfilewriter.cpp
index f6fd650c13..82f2aca496 100644
--- a/src/qmldom/qqmldomfilewriter.cpp
+++ b/src/qmldom/qqmldomfilewriter.cpp
@@ -9,7 +9,7 @@ QT_BEGIN_NAMESPACE
namespace QQmlJS {
namespace Dom {
-FileWriter::Status FileWriter::write(QString tFile, function_ref<bool(QTextStream &)> write,
+FileWriter::Status FileWriter::write(const QString &tFile, function_ref<bool(QTextStream &)> write,
int nBk)
{
if (shouldRemoveTempFile)
diff --git a/src/qmldom/qqmldomfilewriter_p.h b/src/qmldom/qqmldomfilewriter_p.h
index 08a148ef5d..d9987f3f7a 100644
--- a/src/qmldom/qqmldomfilewriter_p.h
+++ b/src/qmldom/qqmldomfilewriter_p.h
@@ -37,14 +37,15 @@ public:
~FileWriter()
{
- if (!silentWarnings)
- for (QString w : warnings)
+ if (!silentWarnings) {
+ for (const QString &w : std::as_const(warnings))
qWarning() << w;
+ }
if (shouldRemoveTempFile)
tempFile.remove();
}
- Status write(QString targetFile, function_ref<bool(QTextStream &)> write, int nBk = 2);
+ Status write(const QString &targetFile, function_ref<bool(QTextStream &)> write, int nBk = 2);
bool shouldRemoveTempFile = false;
bool silentWarnings = false;
diff --git a/src/qmldom/qqmldomfunctionref_p.h b/src/qmldom/qqmldomfunctionref_p.h
index 65ef513ec2..525178e841 100644
--- a/src/qmldom/qqmldomfunctionref_p.h
+++ b/src/qmldom/qqmldomfunctionref_p.h
@@ -17,32 +17,44 @@
#include <QtCore/private/qglobal_p.h>
-#include <functional>
-// function_ref has been proposed for the C++20 standard, see
-// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0792r2.html
-// uses it if available, replace it with a const ref to std::function otherwise
-
-#ifndef __cpp_lib_function_ref
+#if !defined(Q_CC_MSVC) || Q_CC_MSVC >= 1930
+#include <QtCore/qxpfunctional.h>
QT_BEGIN_NAMESPACE
namespace QQmlJS {
namespace Dom {
template <typename T>
-using function_ref = const std::function<T> &;
+using function_ref = qxp::function_ref<T>;
} // namespace Dom
} // namespace QQmlJS
QT_END_NAMESPACE
#else
+#include <functional>
+
QT_BEGIN_NAMESPACE
namespace QQmlJS {
namespace Dom {
-using std::function_ref;
+namespace _detail {
+template <typename T>
+struct function_ref_helper { using type = std::function<T>; };
+// std::function doesn't grok the const in <int(int) const>, so remove:
+template <typename R, typename...Args>
+struct function_ref_helper<R(Args...) const> : function_ref_helper<R(Args...)> {};
+// std::function doesn't grok the noexcept in <int(int) noexcept>, so remove:
+template <typename R, typename...Args>
+struct function_ref_helper<R(Args...) noexcept> : function_ref_helper<R(Args...)> {};
+// and both together:
+template <typename R, typename...Args>
+struct function_ref_helper<R(Args...) const noexcept> : function_ref_helper<R(Args...)> {};
+} // namespace _detail
+template <typename T>
+using function_ref = const typename _detail::function_ref_helper<T>::type &;
} // namespace Dom
} // namespace QQmlJS
QT_END_NAMESPACE
-#endif // __cpp_lib_function_ref
+#endif
#endif // QQMLDOMFUNCTIONREF_P_H
diff --git a/src/qmldom/qqmldomindentinglinewriter.cpp b/src/qmldom/qqmldomindentinglinewriter.cpp
index 734a56943f..99f81c1717 100644
--- a/src/qmldom/qqmldomindentinglinewriter.cpp
+++ b/src/qmldom/qqmldomindentinglinewriter.cpp
@@ -24,7 +24,7 @@ void IndentingLineWriter::willCommit()
m_preCachedStatus = fStatus().currentStatus;
}
-void IndentingLineWriter::reindentAndSplit(QString eol, bool eof)
+void IndentingLineWriter::reindentAndSplit(const QString &eol, bool eof)
{
bool shouldReindent = m_reindent;
indentAgain:
diff --git a/src/qmldom/qqmldomindentinglinewriter_p.h b/src/qmldom/qqmldomindentinglinewriter_p.h
index f066d370c9..63ec3fc432 100644
--- a/src/qmldom/qqmldomindentinglinewriter_p.h
+++ b/src/qmldom/qqmldomindentinglinewriter_p.h
@@ -31,7 +31,7 @@ QMLDOM_EXPORT class IndentingLineWriter : public LineWriter
{
Q_GADGET
public:
- IndentingLineWriter(SinkF innerSink, QString fileName,
+ IndentingLineWriter(const SinkF &innerSink, const QString &fileName,
const LineWriterOptions &options = LineWriterOptions(),
const FormatTextStatus &initialStatus = FormatTextStatus::initialStatus(),
int lineNr = 0, int columnNr = 0, int utf16Offset = 0,
@@ -40,7 +40,7 @@ public:
m_preCachedStatus(initialStatus)
{
}
- void reindentAndSplit(QString eol, bool eof = false) override;
+ void reindentAndSplit(const QString &eol, bool eof = false) override;
FormatPartialStatus &fStatus();
void lineChanged() override { m_fStatusValid = false; }
diff --git a/src/qmldom/qqmldomitem.cpp b/src/qmldom/qqmldomitem.cpp
index e3f871acf0..8e4f8acd40 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
@@ -39,7 +47,38 @@ namespace QQmlJS {
namespace Dom {
Q_LOGGING_CATEGORY(writeOutLog, "qt.qmldom.writeOut", QtWarningMsg);
-static Q_LOGGING_CATEGORY(refLog, "qt.qmldom.ref", QtWarningMsg);
+Q_STATIC_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;
/*!
@@ -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
diff --git a/src/qmldom/qqmldomitem_p.h b/src/qmldom/qqmldomitem_p.h
index 631a0ff335..c27fa48c46 100644
--- a/src/qmldom/qqmldomitem_p.h
+++ b/src/qmldom/qqmldomitem_p.h
@@ -17,6 +17,7 @@
#include "qqmldom_global.h"
#include "qqmldom_fwd_p.h"
+#include "qqmldom_utils_p.h"
#include "qqmldomconstants_p.h"
#include "qqmldomstringdumper_p.h"
#include "qqmldompath_p.h"
@@ -24,6 +25,7 @@
#include "qqmldomfunctionref_p.h"
#include "qqmldomfilewriter_p.h"
#include "qqmldomlinewriter_p.h"
+#include "qqmldomfieldfilter_p.h"
#include <QtCore/QMap>
#include <QtCore/QMultiMap>
@@ -36,6 +38,7 @@
#include <QtCore/QCborValue>
#include <QtCore/QTimeZone>
#include <QtQml/private/qqmljssourcelocation_p.h>
+#include <QtQmlCompiler/private/qqmljsscope_p.h>
#include <memory>
#include <typeinfo>
@@ -53,13 +56,14 @@ namespace Dom {
class Path;
-Q_DECLARE_LOGGING_CATEGORY(writeOutLog);
+QT_DECLARE_EXPORTED_QT_LOGGING_CATEGORY(writeOutLog, QMLDOM_EXPORT);
constexpr bool domTypeIsObjWrap(DomType k);
constexpr bool domTypeIsValueWrap(DomType k);
constexpr bool domTypeIsDomElement(DomType);
constexpr bool domTypeIsOwningItem(DomType);
constexpr bool domTypeIsUnattachedOwningItem(DomType);
+constexpr bool domTypeIsScriptElement(DomType);
QMLDOM_EXPORT bool domTypeIsExternalItem(DomType k);
QMLDOM_EXPORT bool domTypeIsTopItem(DomType k);
QMLDOM_EXPORT bool domTypeIsContainer(DomType k);
@@ -72,6 +76,7 @@ constexpr bool domTypeCanBeInline(DomType k)
case DomType::ListP:
case DomType::ConstantData:
case DomType::SimpleObjectWrap:
+ case DomType::ScriptElementWrap:
case DomType::Reference:
return true;
default:
@@ -85,15 +90,13 @@ QMLDOM_EXPORT QString domTypeToString(DomType k);
QMLDOM_EXPORT QMap<DomKind, QString> domKindToStringMap();
QMLDOM_EXPORT QString domKindToString(DomKind k);
-QMLDOM_EXPORT QCborValue locationToData(SourceLocation loc, QStringView strValue=u"");
-
-inline bool noFilter(DomItem &, const PathEls::PathComponent &, DomItem &)
+inline bool noFilter(const DomItem &, const PathEls::PathComponent &, const DomItem &)
{
return true;
}
using DirectVisitor = function_ref<bool(const PathEls::PathComponent &, function_ref<DomItem()>)>;
-// using DirectVisitor = function_ref<bool(Path, DomItem &)>;
+// using DirectVisitor = function_ref<bool(Path, const DomItem &)>;
namespace {
template<typename T>
@@ -176,8 +179,11 @@ template<typename T>
union SubclassStorage {
int i;
T lp;
+
+ // TODO: these are extremely nasty. What is this int doing in here?
T *data() { return reinterpret_cast<T *>(this); }
const T *data() const { return reinterpret_cast<const T *>(this); }
+
SubclassStorage() { }
SubclassStorage(T &&el) { el.moveTo(data()); }
SubclassStorage(const T *el) { el->copyTo(data()); }
@@ -192,42 +198,47 @@ union SubclassStorage {
~SubclassStorage() { data()->~T(); }
};
-class QMLDOM_EXPORT DomBase{
+class QMLDOM_EXPORT DomBase
+{
public:
+ using FilterT = function_ref<bool(const DomItem &, const PathEls::PathComponent &, const DomItem &)>;
+
virtual ~DomBase() = default;
+ DomBase *domBase() { return this; }
+ const DomBase *domBase() const { return this; }
+
// minimal overload set:
virtual DomType kind() const = 0;
virtual DomKind domKind() const;
- virtual Path pathFromOwner(DomItem &self) const = 0;
- virtual Path canonicalPath(DomItem &self) const = 0;
+ virtual Path pathFromOwner(const DomItem &self) const = 0;
+ virtual Path canonicalPath(const DomItem &self) const = 0;
virtual bool
- iterateDirectSubpaths(DomItem &self,
- DirectVisitor visitor) = 0; // iterates the *direct* subpaths, returns
- // false if a quick end was requested
- bool iterateDirectSubpathsConst(DomItem &self, DirectVisitor)
+ iterateDirectSubpaths(const DomItem &self,
+ DirectVisitor visitor) const = 0; // iterates the *direct* subpaths, returns
+ // false if a quick end was requested
+
+ bool iterateDirectSubpathsConst(const DomItem &self, DirectVisitor)
const; // iterates the *direct* subpaths, returns false if a quick end was requested
virtual DomItem containingObject(
- DomItem &self) const; // the DomItem corresponding to the canonicalSource source
- virtual void
- dump(DomItem &, Sink sink, int indent,
- function_ref<bool(DomItem &, const PathEls::PathComponent &, DomItem &)> filter) const;
+ const DomItem &self) const; // the DomItem corresponding to the canonicalSource source
+ virtual void dump(const DomItem &, const Sink &sink, int indent, FilterT filter) const;
virtual quintptr id() const;
QString typeName() const;
- virtual QList<QString> fields(DomItem &self) const;
- virtual DomItem field(DomItem &self, QStringView name) const;
+ virtual QList<QString> fields(const DomItem &self) const;
+ virtual DomItem field(const DomItem &self, QStringView name) const;
- virtual index_type indexes(DomItem &self) const;
- virtual DomItem index(DomItem &self, index_type index) const;
+ virtual index_type indexes(const DomItem &self) const;
+ virtual DomItem index(const DomItem &self, index_type index) const;
- virtual QSet<QString> const keys(DomItem &self) const;
- virtual DomItem key(DomItem &self, QString name) const;
+ virtual QSet<QString> const keys(const DomItem &self) const;
+ virtual DomItem key(const DomItem &self, const QString &name) const;
- virtual QString canonicalFilePath(DomItem &self) const;
+ virtual QString canonicalFilePath(const DomItem &self) const;
- virtual void writeOut(DomItem &self, OutWriter &lw) const;
+ virtual void writeOut(const DomItem &self, OutWriter &lw) const;
virtual QCborValue value() const {
return QCborValue();
@@ -264,12 +275,12 @@ public:
Empty();
quintptr id() const override { return ~quintptr(0); }
- Path pathFromOwner(DomItem &self) const override;
- Path canonicalPath(DomItem &self) const override;
- DomItem containingObject(DomItem &self) const override;
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override;
- void dump(DomItem &, Sink s, int indent,
- function_ref<bool(DomItem &, const PathEls::PathComponent &, DomItem &)> filter)
+ Path pathFromOwner(const DomItem &self) const override;
+ Path canonicalPath(const DomItem &self) const override;
+ DomItem containingObject(const DomItem &self) const override;
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override;
+ void dump(const DomItem &, const Sink &s, int indent,
+ function_ref<bool(const DomItem &, const PathEls::PathComponent &, const DomItem &)> filter)
const override;
};
@@ -277,13 +288,14 @@ class QMLDOM_EXPORT DomElement: public DomBase {
protected:
DomElement& operator=(const DomElement&) = default;
public:
- DomElement(Path pathFromOwner = Path());
+ DomElement(const Path &pathFromOwner = Path());
DomElement(const DomElement &o) = default;
- Path pathFromOwner(DomItem &self) const override;
+ Path pathFromOwner(const DomItem &self) const override;
Path pathFromOwner() const { return m_pathFromOwner; }
- Path canonicalPath(DomItem &self) const override;
- DomItem containingObject(DomItem &self) const override;
- virtual void updatePathFromOwner(Path newPath);
+ Path canonicalPath(const DomItem &self) const override;
+ DomItem containingObject(const DomItem &self) const override;
+ virtual void updatePathFromOwner(const Path &newPath);
+
private:
Path m_pathFromOwner;
};
@@ -299,22 +311,35 @@ public:
Map &operator*() { return *this; }
const Map &operator*() const { return *this; }
- using LookupFunction = std::function<DomItem(DomItem &, QString)>;
- using Keys = std::function<QSet<QString>(DomItem &)>;
- Map(Path pathFromOwner, LookupFunction lookup, Keys keys, QString targetType);
+ using LookupFunction = std::function<DomItem(const DomItem &, QString)>;
+ using Keys = std::function<QSet<QString>(const DomItem &)>;
+ Map(const Path &pathFromOwner, const LookupFunction &lookup,
+ const Keys &keys, const QString &targetType);
quintptr id() const override;
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override;
- QSet<QString> const keys(DomItem &self) const override;
- DomItem key(DomItem &self, QString name) const override;
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override;
+ QSet<QString> const keys(const DomItem &self) const override;
+ DomItem key(const DomItem &self, const QString &name) const override;
template<typename T>
- static Map fromMultiMapRef(Path pathFromOwner, QMultiMap<QString, T> &mmap);
+ static Map fromMultiMapRef(const Path &pathFromOwner, const QMultiMap<QString, T> &mmap);
+ template<typename T>
+ static Map fromMultiMap(const Path &pathFromOwner, const QMultiMap<QString, T> &mmap);
template<typename T>
static Map
- fromMapRef(Path pathFromOwner, QMap<QString, T> &mmap,
- std::function<DomItem(DomItem &, const PathEls::PathComponent &, T &)> elWrapper);
+ fromMapRef(
+ const Path &pathFromOwner, const QMap<QString, T> &mmap,
+ const std::function<DomItem(const DomItem &, const PathEls::PathComponent &, const T &)> &elWrapper);
+
+ template<typename T>
+ static Map fromFileRegionMap(
+ const Path &pathFromOwner, const QMap<FileLocationRegion, T> &map);
+ template<typename T>
+ static Map fromFileRegionListMap(
+ const Path &pathFromOwner, const QMap<FileLocationRegion, QList<T>> &map);
private:
+ template<typename MapT>
+ static QSet<QString> fileRegionKeysFromMap(const MapT &map);
LookupFunction m_lookup;
Keys m_keys;
QString m_targetType;
@@ -331,32 +356,33 @@ public:
List &operator*() { return *this; }
const List &operator*() const { return *this; }
- using LookupFunction = std::function<DomItem(DomItem &, index_type)>;
- using Length = std::function<index_type(DomItem &)>;
+ using LookupFunction = std::function<DomItem(const DomItem &, index_type)>;
+ using Length = std::function<index_type(const DomItem &)>;
using IteratorFunction =
- std::function<bool(DomItem &, function_ref<bool(index_type, function_ref<DomItem()>)>)>;
+ std::function<bool(const DomItem &, function_ref<bool(index_type, function_ref<DomItem()>)>)>;
- List(Path pathFromOwner, LookupFunction lookup, Length length, IteratorFunction iterator, QString elType);
+ List(const Path &pathFromOwner, const LookupFunction &lookup, const Length &length,
+ const IteratorFunction &iterator, const QString &elType);
quintptr id() const override;
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override;
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override;
void
- dump(DomItem &, Sink s, int indent,
- function_ref<bool(DomItem &, const PathEls::PathComponent &, DomItem &)>) const override;
- index_type indexes(DomItem &self) const override;
- DomItem index(DomItem &self, index_type index) const override;
+ dump(const DomItem &, const Sink &s, int indent,
+ function_ref<bool(const DomItem &, const PathEls::PathComponent &, const DomItem &)>) const override;
+ index_type indexes(const DomItem &self) const override;
+ DomItem index(const DomItem &self, index_type index) const override;
template<typename T>
static List
- fromQList(Path pathFromOwner, QList<T> list,
- std::function<DomItem(DomItem &, const PathEls::PathComponent &, T &)> elWrapper,
+ fromQList(const Path &pathFromOwner, const QList<T> &list,
+ const std::function<DomItem(const DomItem &, const PathEls::PathComponent &, const T &)> &elWrapper,
ListOptions options = ListOptions::Normal);
template<typename T>
static List
- fromQListRef(Path pathFromOwner, QList<T> &list,
- std::function<DomItem(DomItem &, const PathEls::PathComponent &, T &)> elWrapper,
+ fromQListRef(const Path &pathFromOwner, const QList<T> &list,
+ const std::function<DomItem(const DomItem &, const PathEls::PathComponent &, const T &)> &elWrapper,
ListOptions options = ListOptions::Normal);
- void writeOut(DomItem &self, OutWriter &ow, bool compact) const;
- void writeOut(DomItem &self, OutWriter &ow) const override { writeOut(self, ow, true); }
+ void writeOut(const DomItem &self, OutWriter &ow, bool compact) const;
+ void writeOut(const DomItem &self, OutWriter &ow) const override { writeOut(self, ow, true); }
private:
LookupFunction m_lookup;
@@ -371,20 +397,20 @@ public:
constexpr static DomType kindValue = DomType::ListP;
DomType kind() const override { return kindValue; }
- ListPBase(Path pathFromOwner, const QList<void *> &pList, QString elType)
+ ListPBase(const Path &pathFromOwner, const QList<const void *> &pList, const QString &elType)
: DomElement(pathFromOwner), m_pList(pList), m_elType(elType)
{
}
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor v) override;
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor v) const override;
virtual void copyTo(ListPBase *) const { Q_ASSERT(false); };
virtual void moveTo(ListPBase *) const { Q_ASSERT(false); };
quintptr id() const override { return quintptr(0); }
- index_type indexes(DomItem &) const override { return index_type(m_pList.size()); }
- void writeOut(DomItem &self, OutWriter &ow, bool compact) const;
- void writeOut(DomItem &self, OutWriter &ow) const override { writeOut(self, ow, true); }
+ index_type indexes(const DomItem &) const override { return index_type(m_pList.size()); }
+ void writeOut(const DomItem &self, OutWriter &ow, bool compact) const;
+ void writeOut(const DomItem &self, OutWriter &ow) const override { writeOut(self, ow, true); }
protected:
- QList<void *> m_pList;
+ QList<const void *> m_pList;
QString m_elType;
};
@@ -394,7 +420,7 @@ class ListPT final : public ListPBase
public:
constexpr static DomType kindValue = DomType::ListP;
- ListPT(Path pathFromOwner, QList<T *> pList, QString elType = QString(),
+ ListPT(const Path &pathFromOwner, const QList<T *> &pList, const QString &elType = QString(),
ListOptions options = ListOptions::Normal)
: ListPBase(pathFromOwner, {},
(elType.isEmpty() ? QLatin1String(typeid(T).name()) : elType))
@@ -405,7 +431,7 @@ public:
"ListPT does not have the same size as ListPBase");
m_pList.reserve(pList.size());
if (options == ListOptions::Normal) {
- for (void *p : pList)
+ for (const void *p : pList)
m_pList.append(p);
} else if (options == ListOptions::Reverse) {
for (qsizetype i = pList.size(); i-- != 0;)
@@ -417,9 +443,9 @@ public:
}
void copyTo(ListPBase *t) const override { new (t) ListPT(*this); }
void moveTo(ListPBase *t) const override { new (t) ListPT(std::move(*this)); }
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor v) override;
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor v) const override;
- DomItem index(DomItem &self, index_type index) const override;
+ DomItem index(const DomItem &self, index_type index) const override;
};
class QMLDOM_EXPORT ListP
@@ -427,7 +453,7 @@ class QMLDOM_EXPORT ListP
public:
constexpr static DomType kindValue = DomType::ListP;
template<typename T>
- ListP(Path pathFromOwner, QList<T *> pList, QString elType = QString(),
+ ListP(const Path &pathFromOwner, const QList<T *> &pList, const QString &elType = QString(),
ListOptions options = ListOptions::Normal)
: list(ListPT<T>(pathFromOwner, pList, elType, options))
{
@@ -459,8 +485,9 @@ public:
ConstantData &operator*() { return *this; }
const ConstantData &operator*() const { return *this; }
- ConstantData(Path pathFromOwner, QCborValue value, Options options = Options::MapIsMap);
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override;
+ ConstantData(const Path &pathFromOwner, const QCborValue &value,
+ Options options = Options::MapIsMap);
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override;
quintptr id() const override;
DomKind domKind() const override;
QCborValue value() const override { return m_value; }
@@ -484,27 +511,17 @@ public:
{
if (m_options & SimpleWrapOption::ValueType) {
if (m_value.metaType() == QMetaType::fromType<T>())
- return reinterpret_cast<const T *>(m_value.constData());
- return nullptr;
- } else {
- return m_value.value<T *>();
- }
- }
- template <typename T>
- T *mutableAs()
- {
- if (m_options & SimpleWrapOption::ValueType) {
- if (m_value.metaType() == QMetaType::fromType<T>())
- return reinterpret_cast<T *>(m_value.data());
+ return static_cast<const T *>(m_value.constData());
return nullptr;
} else {
- return m_value.value<T *>();
+ return m_value.value<const T *>();
}
}
+
SimpleObjectWrapBase() = delete;
virtual void copyTo(SimpleObjectWrapBase *) const { Q_ASSERT(false); }
virtual void moveTo(SimpleObjectWrapBase *) const { Q_ASSERT(false); }
- bool iterateDirectSubpaths(DomItem &, DirectVisitor) override
+ bool iterateDirectSubpaths(const DomItem &, DirectVisitor) const override
{
Q_ASSERT(false);
return true;
@@ -512,7 +529,7 @@ public:
protected:
friend class TestDomItem;
- SimpleObjectWrapBase(Path pathFromOwner, QVariant value, quintptr idValue,
+ SimpleObjectWrapBase(const Path &pathFromOwner, const QVariant &value, quintptr idValue,
DomType kind = kindValue,
SimpleWrapOptions options = SimpleWrapOption::None)
: DomElement(pathFromOwner),
@@ -537,21 +554,21 @@ class SimpleObjectWrapT final : public SimpleObjectWrapBase
public:
constexpr static DomType kindValue = DomType::SimpleObjectWrap;
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) override
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override
{
- return mutableAsT()->iterateDirectSubpaths(self, visitor);
+ return asT()->iterateDirectSubpaths(self, visitor);
}
- void writeOut(DomItem &self, OutWriter &lw) const override;
+ void writeOut(const DomItem &self, OutWriter &lw) const override;
- T const *asT() const
+ const T *asT() const
{
if constexpr (domTypeIsValueWrap(T::kindValue)) {
if (m_value.metaType() == QMetaType::fromType<T>())
- return reinterpret_cast<const T *>(m_value.constData());
+ return static_cast<const T *>(m_value.constData());
return nullptr;
} else if constexpr (domTypeIsObjWrap(T::kindValue)) {
- return m_value.value<T *>();
+ return m_value.value<const T *>();
} else {
// need dependent static assert to not unconditially trigger
static_assert(!std::is_same_v<T, T>, "wrapping of unexpected type");
@@ -559,20 +576,6 @@ public:
}
}
- T *mutableAsT()
- {
- if (domTypeIsValueWrap(T::kindValue)) {
- if (m_value.metaType() == QMetaType::fromType<T>())
- return reinterpret_cast<T *>(m_value.data());
- return nullptr;
- } else if constexpr (domTypeIsObjWrap(T::kindValue)) {
- return m_value.value<T *>();
- } else {
- Q_ASSERT_X(false, "SimpleObjectWrap", "wrapping of unexpected type");
- return nullptr;
- }
- }
-
void copyTo(SimpleObjectWrapBase *target) const override
{
static_assert(sizeof(SimpleObjectWrapBase) == sizeof(SimpleObjectWrapT),
@@ -591,7 +594,8 @@ public:
new (target) SimpleObjectWrapT(std::move(*this));
}
- SimpleObjectWrapT(Path pathFromOwner, QVariant v, quintptr idValue, SimpleWrapOptions o)
+ SimpleObjectWrapT(const Path &pathFromOwner, const QVariant &v,
+ quintptr idValue, SimpleWrapOptions o)
: SimpleObjectWrapBase(pathFromOwner, v, idValue, T::kindValue, o)
{
Q_ASSERT(domTypeIsValueWrap(T::kindValue) == bool(o & SimpleWrapOption::ValueType));
@@ -609,7 +613,7 @@ public:
const SimpleObjectWrapBase &operator*() const { return *wrap.data(); }
template<typename T>
- static SimpleObjectWrap fromObjectRef(Path pathFromOwner, T &value)
+ static SimpleObjectWrap fromObjectRef(const Path &pathFromOwner, T &value)
{
return SimpleObjectWrap(pathFromOwner, value);
}
@@ -617,7 +621,7 @@ public:
private:
template<typename T>
- SimpleObjectWrap(Path pathFromOwner, T &value)
+ SimpleObjectWrap(const Path &pathFromOwner, T &value)
{
using BaseT = std::decay_t<T>;
if constexpr (domTypeIsObjWrap(BaseT::kindValue)) {
@@ -651,57 +655,248 @@ public:
const Reference &operator*() const { return *this; }
bool shouldCache() const;
- Reference(Path referredObject = Path(), Path pathFromOwner = Path(), const SourceLocation & loc = SourceLocation());
+ Reference(const Path &referredObject = Path(), const Path &pathFromOwner = Path(),
+ const SourceLocation &loc = SourceLocation());
quintptr id() const override;
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override;
- DomItem field(DomItem &self, QStringView name) const override;
- QList<QString> fields(DomItem &self) const override;
- index_type indexes(DomItem &) const override { return 0; }
- DomItem index(DomItem &, index_type) const override;
- QSet<QString> const keys(DomItem &) const override { return {}; }
- DomItem key(DomItem &, QString) const override;
-
- DomItem get(DomItem &self, ErrorHandler h = nullptr, QList<Path> *visitedRefs = nullptr) const;
- QList<DomItem> getAll(DomItem &self, ErrorHandler h = nullptr,
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override;
+ DomItem field(const DomItem &self, QStringView name) const override;
+ QList<QString> fields(const DomItem &self) const override;
+ index_type indexes(const DomItem &) const override { return 0; }
+ DomItem index(const DomItem &, index_type) const override;
+ QSet<QString> const keys(const DomItem &) const override { return {}; }
+ DomItem key(const DomItem &, const QString &) const override;
+
+ DomItem get(const DomItem &self, const ErrorHandler &h = nullptr,
+ QList<Path> *visitedRefs = nullptr) const;
+ QList<DomItem> getAll(const DomItem &self, const ErrorHandler &h = nullptr,
QList<Path> *visitedRefs = nullptr) const;
Path referredObjectPath;
};
-using ElementT = std::variant<
- Empty, Map, List, ListP, ConstantData, SimpleObjectWrap, Reference, GlobalComponent *,
- JsResource *, QmlComponent *, QmltypesComponent *, EnumDecl *, MockObject *, ModuleScope *,
- AstComments *, AttachedInfo *, DomEnvironment *, DomUniverse *, ExternalItemInfoBase *,
- ExternalItemPairBase *, GlobalScope *, JsFile *, QmlDirectory *, QmlFile *, QmldirFile *,
- QmlObject *, QmltypesFile *, LoadInfo *, MockOwner *, ModuleIndex *, ScriptExpression *>;
+template<typename Info>
+class AttachedInfoT;
+class FileLocations;
+
+/*!
+ \internal
+ \brief A common base class for all the script elements.
+
+ This marker class allows to use all the script elements as a ScriptElement*, using virtual
+ dispatch. For now, it does not add any extra functionality, compared to a DomElement, but allows
+ to forbid DomElement* at the places where only script elements are required.
+ */
+// TODO: do we need another marker struct like this one to differentiate expressions from
+// statements? This would allow to avoid mismatchs between script expressions and script statements,
+// using type-safety.
+struct ScriptElement : public DomElement
+{
+ template<typename T>
+ using PointerType = std::shared_ptr<T>;
+
+ using DomElement::DomElement;
+ virtual void createFileLocations(
+ const std::shared_ptr<AttachedInfoT<FileLocations>> &fileLocationOfOwner) = 0;
+
+ QQmlJSScope::ConstPtr semanticScope();
+ void setSemanticScope(const QQmlJSScope::ConstPtr &scope);
+
+private:
+ QQmlJSScope::ConstPtr m_scope;
+};
+
+/*!
+ \internal
+ \brief Use this to contain any script element.
+ */
+class ScriptElementVariant
+{
+private:
+ template<typename... T>
+ using VariantOfPointer = std::variant<ScriptElement::PointerType<T>...>;
+
+ template<typename T, typename Variant>
+ struct TypeIsInVariant;
+
+ template<typename T, typename... Ts>
+ struct TypeIsInVariant<T, std::variant<Ts...>> : public std::disjunction<std::is_same<T, Ts>...>
+ {
+ };
+
+public:
+ using ScriptElementT =
+ VariantOfPointer<ScriptElements::BlockStatement, ScriptElements::IdentifierExpression,
+ ScriptElements::ForStatement, ScriptElements::BinaryExpression,
+ ScriptElements::VariableDeclarationEntry, ScriptElements::Literal,
+ ScriptElements::IfStatement, ScriptElements::GenericScriptElement,
+ ScriptElements::VariableDeclaration, ScriptElements::ReturnStatement>;
+
+ template<typename T>
+ static ScriptElementVariant fromElement(const T &element)
+ {
+ static_assert(TypeIsInVariant<T, ScriptElementT>::value,
+ "Cannot construct ScriptElementVariant from T, as it is missing from the "
+ "ScriptElementT.");
+ ScriptElementVariant p;
+ p.m_data = element;
+ return p;
+ }
+
+ ScriptElement::PointerType<ScriptElement> base() const;
+
+ operator bool() const { return m_data.has_value(); }
+
+ template<typename F>
+ void visitConst(F &&visitor) const
+ {
+ if (m_data)
+ std::visit(std::forward<F>(visitor), *m_data);
+ }
+
+ template<typename F>
+ void visit(F &&visitor)
+ {
+ if (m_data)
+ std::visit(std::forward<F>(visitor), *m_data);
+ }
+ std::optional<ScriptElementT> data() { return m_data; }
+ void setData(const ScriptElementT &data) { m_data = data; }
+
+private:
+ std::optional<ScriptElementT> m_data;
+};
+
+/*!
+ \internal
+
+ To avoid cluttering the already unwieldy \l ElementT type below with all the types that the
+ different script elements can have, wrap them in an extra class. It will behave like an internal
+ Dom structure (e.g. like a List or a Map) and contain a pointer the the script element.
+ */
+class ScriptElementDomWrapper
+{
+public:
+ ScriptElementDomWrapper(const ScriptElementVariant &element) : m_element(element) { }
+
+ static constexpr DomType kindValue = DomType::ScriptElementWrap;
-using TopT = std::variant<std::shared_ptr<DomEnvironment>, std::shared_ptr<DomUniverse>>;
+ DomBase *operator->() { return m_element.base().get(); }
+ const DomBase *operator->() const { return m_element.base().get(); }
+ DomBase &operator*() { return *m_element.base(); }
+ const DomBase &operator*() const { return *m_element.base(); }
-using OwnerT =
- std::variant<std::shared_ptr<ModuleIndex>, std::shared_ptr<MockOwner>,
- std::shared_ptr<ExternalItemInfoBase>, std::shared_ptr<ExternalItemPairBase>,
- std::shared_ptr<QmlDirectory>, std::shared_ptr<QmldirFile>,
- std::shared_ptr<JsFile>, std::shared_ptr<QmlFile>,
- std::shared_ptr<QmltypesFile>, std::shared_ptr<GlobalScope>,
- std::shared_ptr<ScriptExpression>, std::shared_ptr<AstComments>,
- std::shared_ptr<LoadInfo>, std::shared_ptr<AttachedInfo>,
- std::shared_ptr<DomEnvironment>, std::shared_ptr<DomUniverse>>;
+ ScriptElementVariant element() const { return m_element; }
-inline bool emptyChildrenVisitor(Path, DomItem &, bool)
+private:
+ ScriptElementVariant m_element;
+};
+
+// TODO: create more "groups" to simplify this variant? Maybe into Internal, ScriptExpression, ???
+using ElementT =
+ std::variant<
+ ConstantData,
+ Empty,
+ List,
+ ListP,
+ Map,
+ Reference,
+ ScriptElementDomWrapper,
+ SimpleObjectWrap,
+ const AstComments *,
+ const AttachedInfo *,
+ const DomEnvironment *,
+ const DomUniverse *,
+ const EnumDecl *,
+ const ExternalItemInfoBase *,
+ const ExternalItemPairBase *,
+ const GlobalComponent *,
+ const GlobalScope *,
+ const JsFile *,
+ const JsResource *,
+ const LoadInfo *,
+ const MockObject *,
+ const MockOwner *,
+ const ModuleIndex *,
+ const ModuleScope *,
+ const QmlComponent *,
+ const QmlDirectory *,
+ const QmlFile *,
+ const QmlObject *,
+ const QmldirFile *,
+ const QmltypesComponent *,
+ const QmltypesFile *,
+ const ScriptExpression *
+ >;
+
+using TopT = std::variant<
+ std::monostate,
+ std::shared_ptr<DomEnvironment>,
+ std::shared_ptr<DomUniverse>>;
+
+using OwnerT = std::variant<
+ std::monostate,
+ std::shared_ptr<ModuleIndex>,
+ std::shared_ptr<MockOwner>,
+ std::shared_ptr<ExternalItemInfoBase>,
+ std::shared_ptr<ExternalItemPairBase>,
+ std::shared_ptr<QmlDirectory>,
+ std::shared_ptr<QmldirFile>,
+ std::shared_ptr<JsFile>,
+ std::shared_ptr<QmlFile>,
+ std::shared_ptr<QmltypesFile>,
+ std::shared_ptr<GlobalScope>,
+ std::shared_ptr<ScriptExpression>,
+ std::shared_ptr<AstComments>,
+ std::shared_ptr<LoadInfo>,
+ std::shared_ptr<AttachedInfo>,
+ std::shared_ptr<DomEnvironment>,
+ std::shared_ptr<DomUniverse>>;
+
+inline bool emptyChildrenVisitor(Path, const DomItem &, bool)
{
return true;
}
class MutableDomItem;
+class FileToLoad
+{
+public:
+ struct InMemoryContents
+ {
+ QString data;
+ QDateTime date = QDateTime::currentDateTimeUtc();
+ };
+
+ FileToLoad(const std::weak_ptr<DomEnvironment> &environment, const QString &canonicalPath,
+ const QString &logicalPath, const std::optional<InMemoryContents> &content);
+ FileToLoad() = default;
+
+ static FileToLoad fromMemory(const std::weak_ptr<DomEnvironment> &environment,
+ const QString &path, const QString &data);
+ static FileToLoad fromFileSystem(const std::weak_ptr<DomEnvironment> &environment,
+ const QString &canonicalPath);
+
+ std::weak_ptr<DomEnvironment> environment() const { return m_environment; }
+ QString canonicalPath() const { return m_canonicalPath; }
+ QString logicalPath() const { return m_logicalPath; }
+ std::optional<InMemoryContents> content() const { return m_content; }
+
+private:
+ std::weak_ptr<DomEnvironment> m_environment;
+ QString m_canonicalPath;
+ QString m_logicalPath;
+ std::optional<InMemoryContents> m_content;
+};
+
class QMLDOM_EXPORT DomItem {
Q_DECLARE_TR_FUNCTIONS(DomItem);
public:
- using Callback = function<void(Path, DomItem &, DomItem &)>;
+ using Callback = function<void(const Path &, const DomItem &, const DomItem &)>;
using InternalKind = DomType;
- using Visitor = function_ref<bool(Path, DomItem &)>;
- using ChildrenVisitor = function_ref<bool(Path, DomItem &, bool)>;
+ using Visitor = function_ref<bool(const Path &, const DomItem &)>;
+ using ChildrenVisitor = function_ref<bool(const Path &, const DomItem &, bool)>;
static ErrorGroup domErrorGroup;
static ErrorGroups myErrors();
@@ -711,12 +906,7 @@ public:
enum class CopyOption { EnvConnected, EnvDisconnected };
template<typename F>
- auto visitMutableEl(F f)
- {
- return std::visit(f, this->m_element);
- }
- template<typename F>
- auto visitEl(F f)
+ auto visitEl(F f) const
{
return std::visit(f, this->m_element);
}
@@ -734,48 +924,55 @@ public:
return kind2domKind(m_kind);
}
- Path canonicalPath();
+ Path canonicalPath() const;
- DomItem filterUp(function_ref<bool(DomType k, DomItem &)> filter, FilterUpOptions options);
- DomItem containingObject();
- DomItem container();
- DomItem owner();
- DomItem top();
- DomItem environment();
- DomItem universe();
+ DomItem filterUp(function_ref<bool(DomType k, const DomItem &)> filter, FilterUpOptions options) const;
+ DomItem containingObject() const;
+ DomItem container() const;
+ DomItem owner() const;
+ DomItem top() const;
+ DomItem environment() const;
+ DomItem universe() const;
+ DomItem containingFile() const;
+ DomItem containingScriptExpression() const;
+ DomItem goToFile(const QString &filePath) const;
+ DomItem goUp(int) const;
+ DomItem directParent() const;
DomItem qmlObject(GoTo option = GoTo::Strict,
- FilterUpOptions options = FilterUpOptions::ReturnOuter);
- DomItem fileObject(GoTo option = GoTo::Strict);
- DomItem rootQmlObject(GoTo option = GoTo::Strict);
- DomItem globalScope();
- DomItem component(GoTo option = GoTo::Strict);
- DomItem scope(FilterUpOptions options = FilterUpOptions::ReturnOuter);
+ FilterUpOptions options = FilterUpOptions::ReturnOuter) const;
+ DomItem fileObject(GoTo option = GoTo::Strict) const;
+ DomItem rootQmlObject(GoTo option = GoTo::Strict) const;
+ DomItem globalScope() const;
+ DomItem component(GoTo option = GoTo::Strict) const;
+ DomItem scope(FilterUpOptions options = FilterUpOptions::ReturnOuter) const;
+ QQmlJSScope::ConstPtr nearestSemanticScope() const;
+ QQmlJSScope::ConstPtr semanticScope() const;
// convenience getters
- DomItem get(ErrorHandler h = nullptr, QList<Path> *visitedRefs = nullptr);
- QList<DomItem> getAll(ErrorHandler h = nullptr, QList<Path> *visitedRefs = nullptr);
- bool isOwningItem() { return domTypeIsOwningItem(internalKind()); }
- bool isExternalItem() { return domTypeIsExternalItem(internalKind()); }
- bool isTopItem() { return domTypeIsTopItem(internalKind()); }
- bool isContainer() { return domTypeIsContainer(internalKind()); }
- bool isScope() { return domTypeIsScope(internalKind()); }
- bool isCanonicalChild(DomItem &child);
- bool hasAnnotations();
- QString name() { return field(Fields::name).value().toString(); }
- DomItem pragmas() { return field(Fields::pragmas); }
- DomItem ids() { return field(Fields::ids); }
- QString idStr() { return field(Fields::idStr).value().toString(); }
- DomItem propertyInfos() { return field(Fields::propertyInfos); }
- PropertyInfo propertyInfoWithName(QString name);
- QSet<QString> propertyInfoNames();
- DomItem propertyDefs() { return field(Fields::propertyDefs); }
- DomItem bindings() { return field(Fields::bindings); }
- DomItem methods() { return field(Fields::methods); }
- DomItem enumerations() { return field(Fields::enumerations); }
- DomItem children() { return field(Fields::children); }
- DomItem child(index_type i) { return field(Fields::children).index(i); }
- DomItem annotations()
+ DomItem get(const ErrorHandler &h = nullptr, QList<Path> *visitedRefs = nullptr) const;
+ QList<DomItem> getAll(const ErrorHandler &h = nullptr, QList<Path> *visitedRefs = nullptr) const;
+ bool isOwningItem() const { return domTypeIsOwningItem(internalKind()); }
+ bool isExternalItem() const { return domTypeIsExternalItem(internalKind()); }
+ bool isTopItem() const { return domTypeIsTopItem(internalKind()); }
+ bool isContainer() const { return domTypeIsContainer(internalKind()); }
+ bool isScope() const { return domTypeIsScope(internalKind()); }
+ bool isCanonicalChild(const DomItem &child) const;
+ bool hasAnnotations() const;
+ QString name() const { return field(Fields::name).value().toString(); }
+ DomItem pragmas() const { return field(Fields::pragmas); }
+ DomItem ids() const { return field(Fields::ids); }
+ QString idStr() const { return field(Fields::idStr).value().toString(); }
+ DomItem propertyInfos() const { return field(Fields::propertyInfos); }
+ PropertyInfo propertyInfoWithName(const QString &name) const;
+ QSet<QString> propertyInfoNames() const;
+ DomItem propertyDefs() const { return field(Fields::propertyDefs); }
+ DomItem bindings() const { return field(Fields::bindings); }
+ DomItem methods() const { return field(Fields::methods); }
+ DomItem enumerations() const { return field(Fields::enumerations); }
+ DomItem children() const { return field(Fields::children); }
+ DomItem child(index_type i) const { return field(Fields::children).index(i); }
+ DomItem annotations() const
{
if (hasAnnotations())
return field(Fields::annotations);
@@ -783,200 +980,214 @@ public:
return DomItem();
}
- bool resolve(Path path, Visitor visitor, ErrorHandler errorHandler,
- ResolveOptions options = ResolveOption::None, Path fullPath = Path(),
- QList<Path> *visitedRefs = nullptr);
+ bool resolve(const Path &path, Visitor visitor, const ErrorHandler &errorHandler,
+ ResolveOptions options = ResolveOption::None, const Path &fullPath = Path(),
+ QList<Path> *visitedRefs = nullptr) const;
- DomItem operator[](Path path);
- DomItem operator[](QStringView component);
- DomItem operator[](const QString &component);
- DomItem operator[](const char16_t *component)
+ DomItem operator[](const Path &path) const;
+ DomItem operator[](QStringView component) const;
+ DomItem operator[](const QString &component) const;
+ DomItem operator[](const char16_t *component) const
{
return (*this)[QStringView(component)];
} // to avoid clash with stupid builtin ptrdiff_t[DomItem&], coming from C
- DomItem operator[](index_type i) { return index(i); }
- DomItem operator[](int i) { return index(i); }
- index_type size() { return indexes() + keys().size(); }
- index_type length() { return size(); }
-
- DomItem path(Path p, ErrorHandler h = &defaultErrorHandler);
- DomItem path(QString p, ErrorHandler h = &defaultErrorHandler);
- DomItem path(QStringView p, ErrorHandler h = &defaultErrorHandler);
-
- QList<QString> fields();
- DomItem field(QStringView name);
-
- index_type indexes();
- DomItem index(index_type);
- bool visitIndexes(function_ref<bool(DomItem &)> visitor);
-
- QSet<QString> keys();
- QStringList sortedKeys();
- DomItem key(QString name);
- DomItem key(QStringView name) { return key(name.toString()); }
- bool visitKeys(function_ref<bool(QString, DomItem &)> visitor);
-
- QList<DomItem> values();
- void writeOutPre(OutWriter &lw);
- void writeOut(OutWriter &lw);
- void writeOutPost(OutWriter &lw);
- DomItem writeOutForFile(OutWriter &ow, WriteOutChecks extraChecks);
- DomItem writeOut(QString path, int nBackups = 2,
- const LineWriterOptions &opt = LineWriterOptions(), FileWriter *fw = nullptr,
- WriteOutChecks extraChecks = WriteOutCheck::Default);
-
- bool visitTree(Path basePath, ChildrenVisitor visitor,
+ DomItem operator[](index_type i) const { return index(i); }
+ DomItem operator[](int i) const { return index(i); }
+ index_type size() const { return indexes() + keys().size(); }
+ index_type length() const { return size(); }
+
+ DomItem path(const Path &p, const ErrorHandler &h = &defaultErrorHandler) const;
+ DomItem path(const QString &p, const ErrorHandler &h = &defaultErrorHandler) const;
+ DomItem path(QStringView p, const ErrorHandler &h = &defaultErrorHandler) const;
+
+ QList<QString> fields() const;
+ DomItem field(QStringView name) const;
+
+ index_type indexes() const;
+ DomItem index(index_type) const;
+ bool visitIndexes(function_ref<bool(const DomItem &)> visitor) const;
+
+ QSet<QString> keys() const;
+ QStringList sortedKeys() const;
+ DomItem key(const QString &name) const;
+ DomItem key(QStringView name) const { return key(name.toString()); }
+ bool visitKeys(function_ref<bool(const QString &, const DomItem &)> visitor) const;
+
+ QList<DomItem> values() const;
+ void writeOutPre(OutWriter &lw) const;
+ void writeOut(OutWriter &lw) const;
+ void writeOutPost(OutWriter &lw) const;
+ bool writeOutForFile(OutWriter &ow, WriteOutChecks extraChecks) const;
+ bool writeOut(const QString &path, int nBackups = 2,
+ const LineWriterOptions &opt = LineWriterOptions(), FileWriter *fw = nullptr,
+ WriteOutChecks extraChecks = WriteOutCheck::Default) const;
+
+ bool visitTree(const Path &basePath, ChildrenVisitor visitor,
VisitOptions options = VisitOption::Default,
ChildrenVisitor openingVisitor = emptyChildrenVisitor,
- ChildrenVisitor closingVisitor = emptyChildrenVisitor);
- bool visitPrototypeChain(function_ref<bool(DomItem &)> visitor,
+ ChildrenVisitor closingVisitor = emptyChildrenVisitor,
+ const FieldFilter &filter = FieldFilter::noFilter()) const;
+ bool visitPrototypeChain(function_ref<bool(const DomItem &)> visitor,
VisitPrototypesOptions options = VisitPrototypesOption::Normal,
- ErrorHandler h = nullptr, QSet<quintptr> *visited = nullptr,
- QList<Path> *visitedRefs = nullptr);
- bool visitDirectAccessibleScopes(function_ref<bool(DomItem &)> visitor,
+ const ErrorHandler &h = nullptr, QSet<quintptr> *visited = nullptr,
+ QList<Path> *visitedRefs = nullptr) const;
+ bool visitDirectAccessibleScopes(function_ref<bool(const DomItem &)> visitor,
VisitPrototypesOptions options = VisitPrototypesOption::Normal,
- ErrorHandler h = nullptr, QSet<quintptr> *visited = nullptr,
- QList<Path> *visitedRefs = nullptr);
+ const ErrorHandler &h = nullptr, QSet<quintptr> *visited = nullptr,
+ QList<Path> *visitedRefs = nullptr) const;
bool
- visitStaticTypePrototypeChains(function_ref<bool(DomItem &)> visitor,
+ visitStaticTypePrototypeChains(function_ref<bool(const DomItem &)> visitor,
VisitPrototypesOptions options = VisitPrototypesOption::Normal,
- ErrorHandler h = nullptr, QSet<quintptr> *visited = nullptr,
- QList<Path> *visitedRefs = nullptr);
- bool visitScopeChain(function_ref<bool(DomItem &)> visitor,
- LookupOptions = LookupOption::Normal, ErrorHandler h = nullptr,
- QSet<quintptr> *visited = nullptr, QList<Path> *visitedRefs = nullptr);
- bool visitLocalSymbolsNamed(QString name, function_ref<bool(DomItem &)> visitor);
- QSet<QString> localSymbolNames(LocalSymbolsTypes lTypes = LocalSymbolsType::All);
- bool visitLookup1(QString symbolName, function_ref<bool(DomItem &)> visitor,
- LookupOptions = LookupOption::Normal, ErrorHandler h = nullptr,
- QSet<quintptr> *visited = nullptr, QList<Path> *visitedRefs = nullptr);
- bool visitLookup(QString symbolName, function_ref<bool(DomItem &)> visitor,
- LookupType type = LookupType::Symbol, LookupOptions = LookupOption::Normal,
- ErrorHandler errorHandler = nullptr, QSet<quintptr> *visited = nullptr,
- QList<Path> *visitedRefs = nullptr);
- bool visitSubSymbolsNamed(QString name, function_ref<bool(DomItem &)> visitor);
- DomItem proceedToScope(ErrorHandler h = nullptr, QList<Path> *visitedRefs = nullptr);
- QList<DomItem> lookup(QString symbolName, LookupType type = LookupType::Symbol,
- LookupOptions = LookupOption::Normal,
- ErrorHandler errorHandler = nullptr);
- DomItem lookupFirst(QString symbolName, LookupType type = LookupType::Symbol,
- LookupOptions = LookupOption::Normal, ErrorHandler errorHandler = nullptr);
-
- quintptr id();
- Path pathFromOwner();
- QString canonicalFilePath();
- DomItem fileLocationsTree();
- DomItem fileLocations();
- MutableDomItem makeCopy(CopyOption option = CopyOption::EnvConnected);
- bool commitToBase(std::shared_ptr<DomEnvironment> validPtr = nullptr);
- DomItem refreshed() { return top().path(canonicalPath()); }
- QCborValue value();
-
- void dumpPtr(Sink sink);
- void dump(Sink, int indent = 0,
- function_ref<bool(DomItem &, const PathEls::PathComponent &, DomItem &)> filter =
- noFilter);
+ const ErrorHandler &h = nullptr, QSet<quintptr> *visited = nullptr,
+ QList<Path> *visitedRefs = nullptr) const;
+
+ bool visitUp(function_ref<bool(const DomItem &)> visitor) const;
+ bool visitScopeChain(
+ function_ref<bool(const DomItem &)> visitor, LookupOptions = LookupOption::Normal,
+ const ErrorHandler &h = nullptr, QSet<quintptr> *visited = nullptr,
+ QList<Path> *visitedRefs = nullptr) const;
+ bool visitLocalSymbolsNamed(
+ const QString &name, function_ref<bool(const DomItem &)> visitor) const;
+ bool visitLookup1(
+ const QString &symbolName, function_ref<bool(const DomItem &)> visitor,
+ LookupOptions = LookupOption::Normal, const ErrorHandler &h = nullptr,
+ QSet<quintptr> *visited = nullptr, QList<Path> *visitedRefs = nullptr) const;
+ bool visitLookup(
+ const QString &symbolName, function_ref<bool(const DomItem &)> visitor,
+ LookupType type = LookupType::Symbol, LookupOptions = LookupOption::Normal,
+ const ErrorHandler &errorHandler = nullptr, QSet<quintptr> *visited = nullptr,
+ QList<Path> *visitedRefs = nullptr) const;
+ bool visitSubSymbolsNamed(
+ const QString &name, function_ref<bool(const DomItem &)> visitor) const;
+ DomItem proceedToScope(
+ const ErrorHandler &h = nullptr, QList<Path> *visitedRefs = nullptr) const;
+ QList<DomItem> lookup(
+ const QString &symbolName, LookupType type = LookupType::Symbol,
+ LookupOptions = LookupOption::Normal, const ErrorHandler &errorHandler = nullptr) const;
+ DomItem lookupFirst(
+ const QString &symbolName, LookupType type = LookupType::Symbol,
+ LookupOptions = LookupOption::Normal, const ErrorHandler &errorHandler = nullptr) const;
+
+ quintptr id() const;
+ Path pathFromOwner() const;
+ QString canonicalFilePath() const;
+ DomItem fileLocationsTree() const;
+ DomItem fileLocations() const;
+ MutableDomItem makeCopy(CopyOption option = CopyOption::EnvConnected) const;
+ bool commitToBase(const std::shared_ptr<DomEnvironment> &validPtr = nullptr) const;
+ DomItem refreshed() const { return top().path(canonicalPath()); }
+ QCborValue value() const;
+
+ void dumpPtr(const Sink &sink) const;
+ void dump(const Sink &, int indent = 0,
+ function_ref<bool(const DomItem &, const PathEls::PathComponent &, const DomItem &)> filter =
+ noFilter) const;
FileWriter::Status
- dump(QString path,
- function_ref<bool(DomItem &, const PathEls::PathComponent &, DomItem &)> filter = noFilter,
- int nBackups = 2, int indent = 0, FileWriter *fw = nullptr);
- QString toString();
- QString toString() const
- {
- DomItem self = *this;
- return self.toString();
- }
+ dump(const QString &path,
+ function_ref<bool(const DomItem &, const PathEls::PathComponent &, const DomItem &)> filter = noFilter,
+ int nBackups = 2, int indent = 0, FileWriter *fw = nullptr) const;
+ QString toString() const;
// OwnigItem elements
- int derivedFrom();
- int revision();
- QDateTime createdAt();
- QDateTime frozenAt();
- QDateTime lastDataUpdateAt();
+ int derivedFrom() const;
+ int revision() const;
+ QDateTime createdAt() const;
+ QDateTime frozenAt() const;
+ QDateTime lastDataUpdateAt() const;
- void addError(ErrorMessage msg);
- ErrorHandler errorHandler();
- void clearErrors(ErrorGroups groups = ErrorGroups({}), bool iterate = true);
+ void addError(ErrorMessage &&msg) const;
+ ErrorHandler errorHandler() const;
+ void clearErrors(const ErrorGroups &groups = ErrorGroups({}), bool iterate = true) const;
// return false if a quick exit was requested
- bool iterateErrors(function_ref<bool(DomItem source, ErrorMessage msg)> visitor, bool iterate,
- Path inPath = Path());
+ bool iterateErrors(
+ function_ref<bool (const DomItem &, const ErrorMessage &)> visitor, bool iterate,
+ Path inPath = Path()) const;
- bool iterateSubOwners(function_ref<bool(DomItem &owner)> visitor);
- bool iterateDirectSubpaths(DirectVisitor v);
+ bool iterateSubOwners(function_ref<bool(const DomItem &owner)> visitor) const;
+ bool iterateDirectSubpaths(DirectVisitor v) const;
template<typename T>
- DomItem subDataItem(const PathEls::PathComponent &c, T value,
- ConstantData::Options options = ConstantData::Options::MapIsMap);
+ DomItem subDataItem(const PathEls::PathComponent &c, const T &value,
+ ConstantData::Options options = ConstantData::Options::MapIsMap) const;
template<typename T>
- DomItem subDataItemField(QStringView f, T value,
- ConstantData::Options options = ConstantData::Options::MapIsMap)
+ DomItem subDataItemField(QStringView f, const T &value,
+ ConstantData::Options options = ConstantData::Options::MapIsMap) const
{
return subDataItem(PathEls::Field(f), value, options);
}
template<typename T>
- DomItem subValueItem(const PathEls::PathComponent &c, T value,
- ConstantData::Options options = ConstantData::Options::MapIsMap);
+ DomItem subValueItem(const PathEls::PathComponent &c, const T &value,
+ ConstantData::Options options = ConstantData::Options::MapIsMap) const;
template<typename T>
- bool dvValue(DirectVisitor visitor, const PathEls::PathComponent &c, T value,
- ConstantData::Options options = ConstantData::Options::MapIsMap);
+ bool dvValue(DirectVisitor visitor, const PathEls::PathComponent &c, const T &value,
+ ConstantData::Options options = ConstantData::Options::MapIsMap) const;
template<typename T>
- bool dvValueField(DirectVisitor visitor, QStringView f, T value,
- ConstantData::Options options = ConstantData::Options::MapIsMap)
+ bool dvValueField(DirectVisitor visitor, QStringView f, const T &value,
+ ConstantData::Options options = ConstantData::Options::MapIsMap) const
{
- return this->dvValue<T>(visitor, PathEls::Field(f), value, options);
+ return this->dvValue<T>(std::move(visitor), PathEls::Field(f), value, options);
}
template<typename F>
bool dvValueLazy(DirectVisitor visitor, const PathEls::PathComponent &c, F valueF,
- ConstantData::Options options = ConstantData::Options::MapIsMap);
+ ConstantData::Options options = ConstantData::Options::MapIsMap) const;
template<typename F>
bool dvValueLazyField(DirectVisitor visitor, QStringView f, F valueF,
- ConstantData::Options options = ConstantData::Options::MapIsMap)
+ ConstantData::Options options = ConstantData::Options::MapIsMap) const
{
- return this->dvValueLazy(visitor, PathEls::Field(f), valueF, options);
+ return this->dvValueLazy(std::move(visitor), PathEls::Field(f), valueF, options);
}
- DomItem subLocationItem(const PathEls::PathComponent &c, SourceLocation loc,
- QStringView code = QStringView())
+ DomItem subLocationItem(const PathEls::PathComponent &c, SourceLocation loc) const
{
- return this->subDataItem(c, locationToData(loc, code));
+ return this->subDataItem(c, sourceLocationToQCborValue(loc));
}
// bool dvSubReference(DirectVisitor visitor, const PathEls::PathComponent &c, Path
// referencedObject);
- DomItem subReferencesItem(const PathEls::PathComponent &c, QList<Path> paths);
- DomItem subReferenceItem(const PathEls::PathComponent &c, Path referencedObject);
- bool dvReference(DirectVisitor visitor, const PathEls::PathComponent &c, Path referencedObject)
+ DomItem subReferencesItem(const PathEls::PathComponent &c, const QList<Path> &paths) const;
+ DomItem subReferenceItem(const PathEls::PathComponent &c, const Path &referencedObject) const;
+ bool dvReference(DirectVisitor visitor, const PathEls::PathComponent &c, const Path &referencedObject) const
{
- return dvItem(visitor, c, [c, this, referencedObject]() {
+ return dvItem(std::move(visitor), c, [c, this, referencedObject]() {
return this->subReferenceItem(c, referencedObject);
});
}
- bool dvReferences(DirectVisitor visitor, const PathEls::PathComponent &c, QList<Path> paths)
+ bool dvReferences(
+ DirectVisitor visitor, const PathEls::PathComponent &c, const QList<Path> &paths) const
{
- return dvItem(visitor, c, [c, this, paths]() { return this->subReferencesItem(c, paths); });
+ return dvItem(std::move(visitor), c, [c, this, paths]() {
+ return this->subReferencesItem(c, paths);
+ });
}
- bool dvReferenceField(DirectVisitor visitor, QStringView f, Path referencedObject)
+ bool dvReferenceField(DirectVisitor visitor, QStringView f, const Path &referencedObject) const
{
- return dvReference(visitor, PathEls::Field(f), referencedObject);
+ return dvReference(std::move(visitor), PathEls::Field(f), referencedObject);
}
- bool dvReferencesField(DirectVisitor visitor, QStringView f, QList<Path> paths)
+ bool dvReferencesField(DirectVisitor visitor, QStringView f, const QList<Path> &paths) const
{
- return dvReferences(visitor, PathEls::Field(f), paths);
+ return dvReferences(std::move(visitor), PathEls::Field(f), paths);
}
- bool dvItem(DirectVisitor visitor, const PathEls::PathComponent &c, function_ref<DomItem()> it)
+ bool dvItem(DirectVisitor visitor, const PathEls::PathComponent &c, function_ref<DomItem()> it) const
{
return visitor(c, it);
}
- bool dvItemField(DirectVisitor visitor, QStringView f, function_ref<DomItem()> it)
+ bool dvItemField(DirectVisitor visitor, QStringView f, function_ref<DomItem()> it) const
{
- return dvItem(visitor, PathEls::Field(f), it);
+ return dvItem(std::move(visitor), PathEls::Field(f), it);
}
- DomItem subListItem(const List &list);
- DomItem subMapItem(const Map &map);
- DomItem subObjectWrapItem(SimpleObjectWrap obj)
+ DomItem subListItem(const List &list) const;
+ DomItem subMapItem(const Map &map) const;
+ DomItem subObjectWrapItem(SimpleObjectWrap obj) const
{
return DomItem(m_top, m_owner, m_ownerPath, obj);
}
+
+ DomItem subScriptElementWrapperItem(const ScriptElementVariant &obj) const
+ {
+ Q_ASSERT(obj);
+ return DomItem(m_top, m_owner, m_ownerPath, ScriptElementDomWrapper(obj));
+ }
+
template<typename Owner>
- DomItem subOwnerItem(const PathEls::PathComponent &c, Owner o)
+ DomItem subOwnerItem(const PathEls::PathComponent &c, Owner o) const
{
if constexpr (domTypeIsUnattachedOwningItem(Owner::element_type::kindValue))
return DomItem(m_top, o, canonicalPath().appendComponent(c), o.get());
@@ -984,46 +1195,35 @@ public:
return DomItem(m_top, o, Path(), o.get());
}
template<typename T>
- DomItem wrap(const PathEls::PathComponent &c, T &obj);
+ DomItem wrap(const PathEls::PathComponent &c, const T &obj) const;
template<typename T>
- DomItem wrapField(QStringView f, T &obj)
+ DomItem wrapField(QStringView f, const T &obj) const
{
return wrap<T>(PathEls::Field(f), obj);
}
template<typename T>
- bool dvWrap(DirectVisitor visitor, const PathEls::PathComponent &c, T &obj);
+ bool dvWrap(DirectVisitor visitor, const PathEls::PathComponent &c, T &obj) const;
template<typename T>
- bool dvWrapField(DirectVisitor visitor, QStringView f, T &obj)
+ bool dvWrapField(DirectVisitor visitor, QStringView f, T &obj) const
{
- return dvWrap<T>(visitor, PathEls::Field(f), obj);
+ return dvWrap<T>(std::move(visitor), PathEls::Field(f), obj);
}
DomItem() = default;
- DomItem(std::shared_ptr<DomEnvironment>);
- DomItem(std::shared_ptr<DomUniverse>);
-
- static DomItem fromCode(QString code, DomType fileType = DomType::QmlFile);
- void loadFile(QString filePath, QString logicalPath,
- std::function<void(Path, DomItem &, DomItem &)> callback, LoadOptions loadOptions,
- std::optional<DomType> fileType = std::optional<DomType>());
- void loadFile(QString canonicalFilePath, QString logicalPath, QString code, QDateTime codeDate,
- std::function<void(Path, DomItem &, DomItem &)> callback, LoadOptions loadOptions,
- std::optional<DomType> fileType = std::optional<DomType>());
- void loadModuleDependency(QString uri, Version v,
- std::function<void(Path, DomItem &, DomItem &)> callback = nullptr,
- ErrorHandler = nullptr);
- void loadBuiltins(std::function<void(Path, DomItem &, DomItem &)> callback = nullptr,
- ErrorHandler = nullptr);
- void loadPendingDependencies();
+ DomItem(const std::shared_ptr<DomEnvironment> &);
+ DomItem(const std::shared_ptr<DomUniverse> &);
+
+ // TODO move to DomEnvironment?
+ static DomItem fromCode(const QString &code, DomType fileType = DomType::QmlFile);
// --- start of potentially dangerous stuff, make private? ---
- std::shared_ptr<DomTop> topPtr();
- std::shared_ptr<OwningItem> owningItemPtr();
+ std::shared_ptr<DomTop> topPtr() const;
+ std::shared_ptr<OwningItem> owningItemPtr() const;
// keep the DomItem around to ensure that it doesn't get deleted
template<typename T, typename std::enable_if<std::is_base_of_v<DomBase, T>, bool>::type = true>
- T const *as()
+ T const *as() const
{
if (m_kind == T::kindValue) {
if constexpr (domTypeIsObjWrap(T::kindValue) || domTypeIsValueWrap(T::kindValue))
@@ -1035,7 +1235,7 @@ public:
}
template<typename T, typename std::enable_if<!std::is_base_of_v<DomBase, T>, bool>::type = true>
- T const *as()
+ T const *as() const
{
if (m_kind == T::kindValue) {
Q_ASSERT(domTypeIsObjWrap(m_kind) || domTypeIsValueWrap(m_kind));
@@ -1045,67 +1245,54 @@ public:
}
template<typename T>
- std::shared_ptr<T> ownerAs();
+ std::shared_ptr<T> ownerAs() const;
template<typename Owner, typename T>
- DomItem copy(Owner owner, Path ownerPath, T base)
+ DomItem copy(const Owner &owner, const Path &ownerPath, const T &base) const
{
- Q_ASSERT(m_top);
+ Q_ASSERT(!std::holds_alternative<std::monostate>(m_top));
static_assert(IsInlineDom<std::decay_t<T>>::value, "Expected an inline item or pointer");
return DomItem(m_top, owner, ownerPath, base);
}
template<typename Owner>
- DomItem copy(Owner owner, Path ownerPath)
+ DomItem copy(const Owner &owner, const Path &ownerPath) const
{
- Q_ASSERT(m_top);
+ Q_ASSERT(!std::holds_alternative<std::monostate>(m_top));
return DomItem(m_top, owner, ownerPath, owner.get());
}
template<typename T>
- DomItem copy(T base)
+ DomItem copy(const T &base) const
{
- Q_ASSERT(m_top);
+ Q_ASSERT(!std::holds_alternative<std::monostate>(m_top));
using BaseT = std::decay_t<T>;
static_assert(!std::is_same_v<BaseT, ElementT>,
"variant not supported, pass in the stored types");
- static_assert(IsInlineDom<BaseT>::value, "expected either a pointer or an inline item");
- if constexpr (IsSharedPointerToDomObject<BaseT>::value) {
+ static_assert(IsInlineDom<BaseT>::value || std::is_same_v<BaseT, std::monostate>,
+ "expected either a pointer or an inline item");
+
+ if constexpr (IsSharedPointerToDomObject<BaseT>::value)
return DomItem(m_top, base, Path(), base.get());
- } else {
+ else if constexpr (IsInlineDom<BaseT>::value)
return DomItem(m_top, m_owner, m_ownerPath, base);
- }
+
+ Q_UNREACHABLE_RETURN(DomItem(m_top, m_owner, m_ownerPath, nullptr));
}
private:
- DomBase const *base();
- template <typename T, typename std::enable_if<std::is_base_of<DomBase, T>::value, bool>::type = true>
- T *mutableAs() {
- if (m_kind == T::kindValue) {
- if constexpr (domTypeIsObjWrap(T::kindValue) || domTypeIsValueWrap(T::kindValue))
- return static_cast<SimpleObjectWrapBase *>(mutableBase())->mutableAs<T>();
- else
- return static_cast<T *>(mutableBase());
- }
- return nullptr;
- }
+ enum class WriteOutCheckResult { Success, Failed };
+ WriteOutCheckResult performWriteOutChecks(const DomItem &, const DomItem &, OutWriter &, WriteOutChecks) const;
+ const DomBase *base() const;
- template <typename T, typename std::enable_if<!std::is_base_of<DomBase, T>::value, bool>::type = true>
- T *mutableAs() {
- if (m_kind == T::kindValue) {
- Q_ASSERT(domTypeIsObjWrap(m_kind) || domTypeIsValueWrap(m_kind));
- return static_cast<SimpleObjectWrapBase *>(mutableBase())->mutableAs<T>();
- }
- return nullptr;
- }
- DomBase *mutableBase();
template<typename Env, typename Owner>
DomItem(Env, Owner, Path, std::nullptr_t) : DomItem()
{
}
+
template<typename Env, typename Owner, typename T,
typename = std::enable_if_t<IsInlineDom<std::decay_t<T>>::value>>
- DomItem(Env env, Owner owner, Path ownerPath, T el)
+ DomItem(Env env, Owner owner, const Path &ownerPath, const T &el)
: m_top(env), m_owner(owner), m_ownerPath(ownerPath), m_element(el)
{
using BaseT = std::decay_t<T>;
@@ -1113,8 +1300,8 @@ private:
if (!el || el->kind() == DomType::Empty) { // avoid null ptr, and allow only a
// single kind of Empty
m_kind = DomType::Empty;
- m_top.reset();
- m_owner.reset();
+ m_top = std::monostate();
+ m_owner = std::monostate();
m_ownerPath = Path();
m_element = Empty();
} else {
@@ -1144,8 +1331,8 @@ private:
friend class TestDomItem;
friend QMLDOM_EXPORT bool operator==(const DomItem &, const DomItem &);
DomType m_kind = DomType::Empty;
- std::optional<TopT> m_top;
- std::optional<OwnerT> m_owner;
+ TopT m_top;
+ OwnerT m_owner;
Path m_ownerPath;
ElementT m_element = Empty();
};
@@ -1158,123 +1345,179 @@ inline bool operator!=(const DomItem &o1, const DomItem &o2)
}
template<typename T>
-Map Map::fromMultiMapRef(Path pathFromOwner, QMultiMap<QString, T> &mmap)
+static DomItem keyMultiMapHelper(const DomItem &self, const QString &key,
+ const QMultiMap<QString, T> &mmap)
+{
+ auto it = mmap.find(key);
+ auto end = mmap.cend();
+ if (it == end)
+ return DomItem();
+ else {
+ // special case single element (++it == end || it.key() != key)?
+ QList<const T *> values;
+ while (it != end && it.key() == key)
+ values.append(&(*it++));
+ ListP ll(self.pathFromOwner().appendComponent(PathEls::Key(key)), values, QString(),
+ ListOptions::Reverse);
+ return self.copy(ll);
+ }
+}
+
+template<typename T>
+Map Map::fromMultiMapRef(const Path &pathFromOwner, const QMultiMap<QString, T> &mmap)
{
return Map(
pathFromOwner,
- [&mmap](DomItem &self, QString key) {
- auto it = mmap.find(key);
- auto end = mmap.cend();
- if (it == end)
- return DomItem();
- else {
- // special case single element (++it == end || it.key() != key)?
- QList<T *> values;
- while (it != end && it.key() == key)
- values.append(&(*it++));
- ListP ll(self.pathFromOwner().appendComponent(PathEls::Key(key)), values,
- QString(), ListOptions::Reverse);
- return self.copy(ll);
- }
+ [&mmap](const DomItem &self, const QString &key) {
+ return keyMultiMapHelper(self, key, mmap);
},
- [&mmap](DomItem &) { return QSet<QString>(mmap.keyBegin(), mmap.keyEnd()); },
+ [&mmap](const DomItem &) { return QSet<QString>(mmap.keyBegin(), mmap.keyEnd()); },
QLatin1String(typeid(T).name()));
}
template<typename T>
Map Map::fromMapRef(
- Path pathFromOwner, QMap<QString, T> &map,
- std::function<DomItem(DomItem &, const PathEls::PathComponent &, T &)> elWrapper)
+ const Path &pathFromOwner, const QMap<QString, T> &map,
+ const std::function<DomItem(const DomItem &, const PathEls::PathComponent &, const T &)> &elWrapper)
{
return Map(
pathFromOwner,
- [&map, elWrapper](DomItem &self, QString key) {
- if (!map.contains(key))
+ [&map, elWrapper](const DomItem &self, const QString &key) {
+ const auto it = map.constFind(key);
+ if (it == map.constEnd())
return DomItem();
- else {
- return elWrapper(self, PathEls::Key(key), map[key]);
- }
+ return elWrapper(self, PathEls::Key(key), it.value());
},
- [&map](DomItem &) { return QSet<QString>(map.keyBegin(), map.keyEnd()); },
+ [&map](const DomItem &) { return QSet<QString>(map.keyBegin(), map.keyEnd()); },
QLatin1String(typeid(T).name()));
}
+template<typename MapT>
+QSet<QString> Map::fileRegionKeysFromMap(const MapT &map)
+{
+ QSet<QString> keys;
+ std::transform(map.keyBegin(), map.keyEnd(), std::inserter(keys, keys.begin()), fileLocationRegionName);
+ return keys;
+}
+
+template<typename T>
+Map Map::fromFileRegionMap(const Path &pathFromOwner, const QMap<FileLocationRegion, T> &map)
+{
+ auto result = Map(
+ pathFromOwner,
+ [&map](const DomItem &mapItem, const QString &key) -> DomItem {
+ auto it = map.constFind(fileLocationRegionValue(key));
+ if (it == map.constEnd())
+ return {};
+
+ return mapItem.wrap(PathEls::Key(key), *it);
+ },
+ [&map](const DomItem &) { return fileRegionKeysFromMap(map); },
+ QString::fromLatin1(typeid(T).name()));
+ return result;
+}
+
+template<typename T>
+Map Map::fromFileRegionListMap(const Path &pathFromOwner,
+ const QMap<FileLocationRegion, QList<T>> &map)
+{
+ using namespace Qt::StringLiterals;
+ auto result = Map(
+ pathFromOwner,
+ [&map](const DomItem &mapItem, const QString &key) -> DomItem {
+ const QList<SourceLocation> locations = map.value(fileLocationRegionValue(key));
+ if (locations.empty())
+ return {};
+
+ auto list = List::fromQList<SourceLocation>(
+ mapItem.pathFromOwner(), locations,
+ [](const DomItem &self, const PathEls::PathComponent &path,
+ const SourceLocation &location) {
+ return self.subLocationItem(path, location);
+ });
+ return mapItem.subListItem(list);
+ },
+ [&map](const DomItem &) { return fileRegionKeysFromMap(map); },
+ u"QList<%1>"_s.arg(QString::fromLatin1(typeid(T).name())));
+ return result;
+}
+
template<typename T>
List List::fromQList(
- Path pathFromOwner, QList<T> list,
- std::function<DomItem(DomItem &, const PathEls::PathComponent &, T &)> elWrapper,
+ const Path &pathFromOwner, const QList<T> &list,
+ const std::function<DomItem(const DomItem &, const PathEls::PathComponent &, const T &)> &elWrapper,
ListOptions options)
{
index_type len = list.size();
if (options == ListOptions::Reverse) {
return List(
pathFromOwner,
- [list, elWrapper](DomItem &self, index_type i) mutable {
+ [list, elWrapper](const DomItem &self, index_type i) mutable {
if (i < 0 || i >= list.size())
return DomItem();
return elWrapper(self, PathEls::Index(i), list[list.size() - i - 1]);
},
- [len](DomItem &) { return len; }, nullptr, QLatin1String(typeid(T).name()));
+ [len](const DomItem &) { return len; }, nullptr, QLatin1String(typeid(T).name()));
} else {
return List(
pathFromOwner,
- [list, elWrapper](DomItem &self, index_type i) mutable {
+ [list, elWrapper](const DomItem &self, index_type i) mutable {
if (i < 0 || i >= list.size())
return DomItem();
return elWrapper(self, PathEls::Index(i), list[i]);
},
- [len](DomItem &) { return len; }, nullptr, QLatin1String(typeid(T).name()));
+ [len](const DomItem &) { return len; }, nullptr, QLatin1String(typeid(T).name()));
}
}
template<typename T>
List List::fromQListRef(
- Path pathFromOwner, QList<T> &list,
- std::function<DomItem(DomItem &, const PathEls::PathComponent &, T &)> elWrapper,
+ const Path &pathFromOwner, const QList<T> &list,
+ const std::function<DomItem(const DomItem &, const PathEls::PathComponent &, const T &)> &elWrapper,
ListOptions options)
{
if (options == ListOptions::Reverse) {
return List(
pathFromOwner,
- [&list, elWrapper](DomItem &self, index_type i) {
+ [&list, elWrapper](const DomItem &self, index_type i) {
if (i < 0 || i >= list.size())
return DomItem();
return elWrapper(self, PathEls::Index(i), list[list.size() - i - 1]);
},
- [&list](DomItem &) { return list.size(); }, nullptr,
+ [&list](const DomItem &) { return list.size(); }, nullptr,
QLatin1String(typeid(T).name()));
} else {
return List(
pathFromOwner,
- [&list, elWrapper](DomItem &self, index_type i) {
+ [&list, elWrapper](const DomItem &self, index_type i) {
if (i < 0 || i >= list.size())
return DomItem();
return elWrapper(self, PathEls::Index(i), list[i]);
},
- [&list](DomItem &) { return list.size(); }, nullptr,
+ [&list](const DomItem &) { return list.size(); }, nullptr,
QLatin1String(typeid(T).name()));
}
}
class QMLDOM_EXPORT OwningItem: public DomBase {
protected:
- virtual std::shared_ptr<OwningItem> doCopy(DomItem &self) const = 0;
+ virtual std::shared_ptr<OwningItem> doCopy(const DomItem &self) const = 0;
public:
OwningItem(const OwningItem &o);
OwningItem(int derivedFrom=0);
- OwningItem(int derivedFrom, QDateTime lastDataUpdateAt);
+ OwningItem(int derivedFrom, const QDateTime &lastDataUpdateAt);
OwningItem(const OwningItem &&) = delete;
OwningItem &operator=(const OwningItem &&) = delete;
static int nextRevision();
- Path canonicalPath(DomItem &self) const override = 0;
+ Path canonicalPath(const DomItem &self) const override = 0;
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override;
- std::shared_ptr<OwningItem> makeCopy(DomItem &self) const { return doCopy(self); }
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override;
+ std::shared_ptr<OwningItem> makeCopy(const DomItem &self) const { return doCopy(self); }
Path pathFromOwner() const { return Path(); }
- Path pathFromOwner(DomItem &) const override final { return Path(); }
- DomItem containingObject(DomItem &self) const override;
+ Path pathFromOwner(const DomItem &) const override final { return Path(); }
+ DomItem containingObject(const DomItem &self) const override;
int derivedFrom() const;
virtual int revision() const;
@@ -1287,18 +1530,20 @@ public:
virtual bool freeze();
QDateTime frozenAt() const;
- virtual void addError(DomItem &self, ErrorMessage msg);
- void addErrorLocal(ErrorMessage msg);
- void clearErrors(ErrorGroups groups = ErrorGroups({}));
+ virtual void addError(const DomItem &self, ErrorMessage &&msg);
+ void addErrorLocal(ErrorMessage &&msg);
+ void clearErrors(const ErrorGroups &groups = ErrorGroups({}));
// return false if a quick exit was requested
- bool iterateErrors(DomItem &self, function_ref<bool(DomItem source, ErrorMessage msg)> visitor,
- Path inPath = Path());
+ bool iterateErrors(
+ const DomItem &self,
+ function_ref<bool(const DomItem &source, const ErrorMessage &msg)> visitor,
+ const Path &inPath = Path());
QMultiMap<Path, ErrorMessage> localErrors() const {
QMutexLocker l(mutex());
return m_errors;
}
- virtual bool iterateSubOwners(DomItem &self, function_ref<bool(DomItem &owner)> visitor);
+ virtual bool iterateSubOwners(const DomItem &self, function_ref<bool(const DomItem &owner)> visitor);
QBasicMutex *mutex() const { return &m_mutex; }
private:
@@ -1313,25 +1558,25 @@ private:
};
template<typename T>
-std::shared_ptr<T> DomItem::ownerAs()
+std::shared_ptr<T> DomItem::ownerAs() const
{
if constexpr (domTypeIsOwningItem(T::kindValue)) {
- if (m_owner) {
+ if (!std::holds_alternative<std::monostate>(m_owner)) {
if constexpr (T::kindValue == DomType::AttachedInfo) {
- if (std::holds_alternative<std::shared_ptr<AttachedInfo>>(*m_owner))
+ if (std::holds_alternative<std::shared_ptr<AttachedInfo>>(m_owner))
return std::static_pointer_cast<T>(
- std::get<std::shared_ptr<AttachedInfo>>(*m_owner));
+ std::get<std::shared_ptr<AttachedInfo>>(m_owner));
} else if constexpr (T::kindValue == DomType::ExternalItemInfo) {
- if (std::holds_alternative<std::shared_ptr<ExternalItemInfoBase>>(*m_owner))
+ if (std::holds_alternative<std::shared_ptr<ExternalItemInfoBase>>(m_owner))
return std::static_pointer_cast<T>(
- std::get<std::shared_ptr<ExternalItemInfoBase>>(*m_owner));
+ std::get<std::shared_ptr<ExternalItemInfoBase>>(m_owner));
} else if constexpr (T::kindValue == DomType::ExternalItemPair) {
- if (std::holds_alternative<std::shared_ptr<ExternalItemPairBase>>(*m_owner))
+ if (std::holds_alternative<std::shared_ptr<ExternalItemPairBase>>(m_owner))
return std::static_pointer_cast<T>(
- std::get<std::shared_ptr<ExternalItemPairBase>>(*m_owner));
+ std::get<std::shared_ptr<ExternalItemPairBase>>(m_owner));
} else {
- if (std::holds_alternative<std::shared_ptr<T>>(*m_owner)) {
- return std::get<std::shared_ptr<T>>(*m_owner);
+ if (std::holds_alternative<std::shared_ptr<T>>(m_owner)) {
+ return std::get<std::shared_ptr<T>>(m_owner);
}
}
}
@@ -1352,26 +1597,26 @@ struct rank<0>
};
template<typename T>
-auto writeOutWrap(const T &t, DomItem &self, OutWriter &lw, rank<1>)
+auto writeOutWrap(const T &t, const DomItem &self, OutWriter &lw, rank<1>)
-> decltype(t.writeOut(self, lw))
{
t.writeOut(self, lw);
}
template<typename T>
-auto writeOutWrap(const T &, DomItem &, OutWriter &, rank<0>) -> void
+auto writeOutWrap(const T &, const DomItem &, OutWriter &, rank<0>) -> void
{
qCWarning(writeOutLog) << "Ignoring writeout to wrapped object not supporting it ("
<< typeid(T).name();
}
template<typename T>
-auto writeOutWrap(const T &t, DomItem &self, OutWriter &lw) -> void
+auto writeOutWrap(const T &t, const DomItem &self, OutWriter &lw) -> void
{
writeOutWrap(t, self, lw, rank<1>());
}
template<typename T>
-void SimpleObjectWrapT<T>::writeOut(DomItem &self, OutWriter &lw) const
+void SimpleObjectWrapT<T>::writeOut(const DomItem &self, OutWriter &lw) const
{
writeOutWrap<T>(*asT(), self, lw);
}
@@ -1390,7 +1635,7 @@ public:
QString internalKindStr() { return domTypeToString(internalKind()); }
DomKind domKind() { return kind2domKind(internalKind()); }
- Path canonicalPath() { return m_owner.canonicalPath().path(m_pathFromOwner); }
+ Path canonicalPath() const { return m_owner.canonicalPath().path(m_pathFromOwner); }
MutableDomItem containingObject()
{
if (m_pathFromOwner)
@@ -1458,28 +1703,27 @@ public:
MutableDomItem index(index_type i) { return MutableDomItem(item().index(i)); }
QSet<QString> const keys() { return item().keys(); }
- MutableDomItem key(QString name) { return MutableDomItem(item().key(name)); }
+ MutableDomItem key(const QString &name) { return MutableDomItem(item().key(name)); }
MutableDomItem key(QStringView name) { return key(name.toString()); }
void
- dump(Sink s, int indent = 0,
- function_ref<bool(DomItem &, const PathEls::PathComponent &, DomItem &)> filter = noFilter)
+ dump(const Sink &s, int indent = 0,
+ function_ref<bool(const DomItem &, const PathEls::PathComponent &, const DomItem &)> filter = noFilter)
{
item().dump(s, indent, filter);
}
FileWriter::Status
- dump(QString path,
- function_ref<bool(DomItem &, const PathEls::PathComponent &, DomItem &)> filter = noFilter,
+ dump(const QString &path,
+ function_ref<bool(const DomItem &, const PathEls::PathComponent &, const DomItem &)> filter = noFilter,
int nBackups = 2, int indent = 0, FileWriter *fw = nullptr)
{
return item().dump(path, filter, nBackups, indent, fw);
}
void writeOut(OutWriter &lw) { return item().writeOut(lw); }
- MutableDomItem writeOut(QString path, int nBackups = 2,
- const LineWriterOptions &opt = LineWriterOptions(),
- FileWriter *fw = nullptr)
+ bool writeOut(const QString &path, int nBackups = 2,
+ const LineWriterOptions &opt = LineWriterOptions(), FileWriter *fw = nullptr)
{
- return MutableDomItem(item().writeOut(path, nBackups, opt, fw));
+ return item().writeOut(path, nBackups, opt, fw);
}
MutableDomItem fileLocations() { return MutableDomItem(item().fileLocations()); }
@@ -1487,11 +1731,11 @@ public:
{
return item().makeCopy(option);
}
- bool commitToBase(std::shared_ptr<DomEnvironment> validEnvPtr = nullptr)
+ bool commitToBase(const std::shared_ptr<DomEnvironment> &validEnvPtr = nullptr)
{
return item().commitToBase(validEnvPtr);
}
- QString canonicalFilePath() { return item().canonicalFilePath(); }
+ QString canonicalFilePath() const { return item().canonicalFilePath(); }
MutableDomItem refreshed() { return MutableDomItem(item().refreshed()); }
@@ -1518,41 +1762,36 @@ public:
QDateTime frozenAt() { return m_owner.frozenAt(); }
QDateTime lastDataUpdateAt() { return m_owner.lastDataUpdateAt(); }
- void addError(ErrorMessage msg) { item().addError(msg); }
+ void addError(ErrorMessage &&msg) { item().addError(std::move(msg)); }
ErrorHandler errorHandler();
// convenience setters
- MutableDomItem addPrototypePath(Path prototypePath);
- MutableDomItem setNextScopePath(Path nextScopePath);
+ MutableDomItem addPrototypePath(const Path &prototypePath);
+ MutableDomItem setNextScopePath(const Path &nextScopePath);
MutableDomItem setPropertyDefs(QMultiMap<QString, PropertyDefinition> propertyDefs);
MutableDomItem setBindings(QMultiMap<QString, Binding> bindings);
MutableDomItem setMethods(QMultiMap<QString, MethodInfo> functionDefs);
- MutableDomItem setChildren(QList<QmlObject> children);
- MutableDomItem setAnnotations(QList<QmlObject> annotations);
- MutableDomItem setScript(std::shared_ptr<ScriptExpression> exp);
- MutableDomItem setCode(QString code);
- MutableDomItem addPropertyDef(PropertyDefinition propertyDef,
+ MutableDomItem setChildren(const QList<QmlObject> &children);
+ MutableDomItem setAnnotations(const QList<QmlObject> &annotations);
+ MutableDomItem setScript(const std::shared_ptr<ScriptExpression> &exp);
+ MutableDomItem setCode(const QString &code);
+ MutableDomItem addPropertyDef(const PropertyDefinition &propertyDef,
AddOption option = AddOption::Overwrite);
MutableDomItem addBinding(Binding binding, AddOption option = AddOption::Overwrite);
- MutableDomItem addMethod(MethodInfo functionDef, AddOption option = AddOption::Overwrite);
+ MutableDomItem addMethod(
+ const MethodInfo &functionDef, AddOption option = AddOption::Overwrite);
MutableDomItem addChild(QmlObject child);
MutableDomItem addAnnotation(QmlObject child);
- MutableDomItem addPreComment(const Comment &comment, QString regionName = QString());
- MutableDomItem addPreComment(const Comment &comment, QStringView regionName)
- {
- return addPreComment(comment, regionName.toString());
- }
- MutableDomItem addPostComment(const Comment &comment, QString regionName = QString());
- MutableDomItem addPostComment(const Comment &comment, QStringView regionName)
- {
- return addPostComment(comment, regionName.toString());
- }
+ MutableDomItem addPreComment(const Comment &comment, FileLocationRegion region);
+ MutableDomItem addPostComment(const Comment &comment, FileLocationRegion region);
+ QQmlJSScope::ConstPtr semanticScope();
+ void setSemanticScope(const QQmlJSScope::ConstPtr &scope);
MutableDomItem() = default;
- MutableDomItem(DomItem owner, Path pathFromOwner):
+ MutableDomItem(const DomItem &owner, const Path &pathFromOwner):
m_owner(owner), m_pathFromOwner(pathFromOwner)
{}
- MutableDomItem(DomItem item):
+ MutableDomItem(const DomItem &item):
m_owner(item.owner()), m_pathFromOwner(item.pathFromOwner())
{}
@@ -1568,18 +1807,32 @@ public:
template <typename T>
T *mutableAs() {
Q_ASSERT(!m_owner || !m_owner.owningItemPtr()->frozen());
- return item().mutableAs<T>();
+
+ DomItem self = item();
+ if (self.m_kind != T::kindValue)
+ return nullptr;
+
+ const T *t = nullptr;
+ if constexpr (domTypeIsObjWrap(T::kindValue) || domTypeIsValueWrap(T::kindValue))
+ t = static_cast<const SimpleObjectWrapBase *>(self.base())->as<T>();
+ else if constexpr (std::is_base_of<DomBase, T>::value)
+ t = static_cast<const T *>(self.base());
+ else
+ Q_UNREACHABLE_RETURN(nullptr);
+
+ // Nasty. But since ElementT has to store the const pointers, we allow it in this one place.
+ return const_cast<T *>(t);
}
template<typename T>
- std::shared_ptr<T> ownerAs()
+ std::shared_ptr<T> ownerAs() const
{
return m_owner.ownerAs<T>();
}
// it is dangerous to assume it stays valid when updates are preformed...
- DomItem item() { return m_owner.path(m_pathFromOwner); }
+ DomItem item() const { return m_owner.path(m_pathFromOwner); }
- friend bool operator==(const MutableDomItem o1, const MutableDomItem &o2)
+ friend bool operator==(const MutableDomItem &o1, const MutableDomItem &o2)
{
return o1.m_owner == o2.m_owner && o1.m_pathFromOwner == o2.m_pathFromOwner;
}
@@ -1596,7 +1849,7 @@ private:
QMLDOM_EXPORT QDebug operator<<(QDebug debug, const MutableDomItem &c);
template<typename K, typename T>
-Path insertUpdatableElementInMultiMap(Path mapPathFromOwner, QMultiMap<K, T> &mmap, K key,
+Path insertUpdatableElementInMultiMap(const Path &mapPathFromOwner, QMultiMap<K, T> &mmap, K key,
const T &value, AddOption option = AddOption::KeepExisting,
T **valuePtr = nullptr)
{
@@ -1633,7 +1886,7 @@ Path insertUpdatableElementInMultiMap(Path mapPathFromOwner, QMultiMap<K, T> &mm
}
template<typename T>
-Path appendUpdatableElementInQList(Path listPathFromOwner, QList<T> &list, const T &value,
+Path appendUpdatableElementInQList(const Path &listPathFromOwner, QList<T> &list, const T &value,
T **vPtr = nullptr)
{
int idx = list.size();
@@ -1647,7 +1900,7 @@ Path appendUpdatableElementInQList(Path listPathFromOwner, QList<T> &list, const
}
template <typename T, typename K = QString>
-void updatePathFromOwnerMultiMap(QMultiMap<K, T> &mmap, Path newPath)
+void updatePathFromOwnerMultiMap(QMultiMap<K, T> &mmap, const Path &newPath)
{
auto it = mmap.begin();
auto end = mmap.end();
@@ -1676,7 +1929,7 @@ void updatePathFromOwnerMultiMap(QMultiMap<K, T> &mmap, Path newPath)
}
template <typename T>
-void updatePathFromOwnerQList(QList<T> &list, Path newPath)
+void updatePathFromOwnerQList(QList<T> &list, const Path &newPath)
{
auto it = list.begin();
auto end = list.end();
@@ -1788,9 +2041,14 @@ constexpr bool domTypeIsUnattachedOwningItem(DomType k)
}
}
+constexpr bool domTypeIsScriptElement(DomType k)
+{
+ return DomType::ScriptElementStart <= k && k <= DomType::ScriptElementStop;
+}
+
template<typename T>
-DomItem DomItem::subValueItem(const PathEls::PathComponent &c, T value,
- ConstantData::Options options)
+DomItem DomItem::subValueItem(const PathEls::PathComponent &c, const T &value,
+ ConstantData::Options options) const
{
using BaseT = std::remove_cv_t<std::remove_reference_t<T>>;
if constexpr (
@@ -1805,8 +2063,8 @@ DomItem DomItem::subValueItem(const PathEls::PathComponent &c, T value,
} else if constexpr (IsList<T>::value && !std::is_convertible_v<BaseT, QStringView>) {
return subListItem(List::fromQList<typename BaseT::value_type>(
pathFromOwner().appendComponent(c), value,
- [options](DomItem &list, const PathEls::PathComponent &p,
- typename T::value_type &v) { return list.subValueItem(p, v, options); }));
+ [options](const DomItem &list, const PathEls::PathComponent &p,
+ const typename T::value_type &v) { return list.subValueItem(p, v, options); }));
} else if constexpr (IsSharedPointerToDomObject<BaseT>::value) {
Q_UNUSED(options);
return subOwnerItem(c, value);
@@ -1816,8 +2074,8 @@ DomItem DomItem::subValueItem(const PathEls::PathComponent &c, T value,
}
template<typename T>
-DomItem DomItem::subDataItem(const PathEls::PathComponent &c, T value,
- ConstantData::Options options)
+DomItem DomItem::subDataItem(const PathEls::PathComponent &c, const T &value,
+ ConstantData::Options options) const
{
using BaseT = std::remove_cv_t<std::remove_reference_t<T>>;
if constexpr (std::is_same_v<BaseT, ConstantData>) {
@@ -1833,8 +2091,8 @@ DomItem DomItem::subDataItem(const PathEls::PathComponent &c, T value,
}
template<typename T>
-bool DomItem::dvValue(DirectVisitor visitor, const PathEls::PathComponent &c, T value,
- ConstantData::Options options)
+bool DomItem::dvValue(DirectVisitor visitor, const PathEls::PathComponent &c, const T &value,
+ ConstantData::Options options) const
{
auto lazyWrap = [this, &c, &value, options]() {
return this->subValueItem<T>(c, value, options);
@@ -1844,7 +2102,7 @@ bool DomItem::dvValue(DirectVisitor visitor, const PathEls::PathComponent &c, T
template<typename F>
bool DomItem::dvValueLazy(DirectVisitor visitor, const PathEls::PathComponent &c, F valueF,
- ConstantData::Options options)
+ ConstantData::Options options) const
{
auto lazyWrap = [this, &c, &valueF, options]() {
return this->subValueItem<decltype(valueF())>(c, valueF(), options);
@@ -1853,7 +2111,7 @@ bool DomItem::dvValueLazy(DirectVisitor visitor, const PathEls::PathComponent &c
}
template<typename T>
-DomItem DomItem::wrap(const PathEls::PathComponent &c, T &obj)
+DomItem DomItem::wrap(const PathEls::PathComponent &c, const T &obj) const
{
using BaseT = std::decay_t<T>;
if constexpr (std::is_same_v<QString, BaseT> || std::is_arithmetic_v<BaseT>) {
@@ -1904,8 +2162,8 @@ DomItem DomItem::wrap(const PathEls::PathComponent &c, T &obj)
if constexpr (std::is_same_v<typename BaseT::key_type, QString>) {
return subMapItem(Map::fromMapRef<typename BaseT::mapped_type>(
pathFromOwner().appendComponent(c), obj,
- [](DomItem &map, const PathEls::PathComponent &p,
- typename BaseT::mapped_type &el) { return map.wrap(p, el); }));
+ [](const DomItem &map, const PathEls::PathComponent &p,
+ const typename BaseT::mapped_type &el) { return map.wrap(p, el); }));
} else {
Q_ASSERT_X(false, "DomItem::wrap", "non string keys not supported (try .toString()?)");
}
@@ -1913,8 +2171,8 @@ DomItem DomItem::wrap(const PathEls::PathComponent &c, T &obj)
if constexpr (IsDomObject<typename BaseT::value_type>::value) {
return subListItem(List::fromQListRef<typename BaseT::value_type>(
pathFromOwner().appendComponent(c), obj,
- [](DomItem &list, const PathEls::PathComponent &p,
- typename BaseT::value_type &el) { return list.wrap(p, el); }));
+ [](const DomItem &list, const PathEls::PathComponent &p,
+ const typename BaseT::value_type &el) { return list.wrap(p, el); }));
} else {
Q_ASSERT_X(false, "DomItem::wrap", "Unsupported list type T");
return DomItem();
@@ -1927,14 +2185,14 @@ DomItem DomItem::wrap(const PathEls::PathComponent &c, T &obj)
}
template<typename T>
-bool DomItem::dvWrap(DirectVisitor visitor, const PathEls::PathComponent &c, T &obj)
+bool DomItem::dvWrap(DirectVisitor visitor, const PathEls::PathComponent &c, T &obj) const
{
auto lazyWrap = [this, &c, &obj]() { return this->wrap<T>(c, obj); };
return visitor(c, lazyWrap);
}
template<typename T>
-bool ListPT<T>::iterateDirectSubpaths(DomItem &self, DirectVisitor v)
+bool ListPT<T>::iterateDirectSubpaths(const DomItem &self, DirectVisitor v) const
{
index_type len = index_type(m_pList.size());
for (index_type i = 0; i < len; ++i) {
@@ -1945,10 +2203,10 @@ bool ListPT<T>::iterateDirectSubpaths(DomItem &self, DirectVisitor v)
}
template<typename T>
-DomItem ListPT<T>::index(DomItem &self, index_type index) const
+DomItem ListPT<T>::index(const DomItem &self, index_type index) const
{
if (index >= 0 && index < m_pList.size())
- return self.wrap(PathEls::Index(index), *reinterpret_cast<T *>(m_pList.value(index)));
+ return self.wrap(PathEls::Index(index), *static_cast<const T *>(m_pList.value(index)));
return DomItem();
}
@@ -1958,13 +2216,13 @@ inline DomKind DomBase::domKind() const
return kind2domKind(kind());
}
-inline bool DomBase::iterateDirectSubpathsConst(DomItem &self, DirectVisitor visitor) const
+inline bool DomBase::iterateDirectSubpathsConst(const DomItem &self, DirectVisitor visitor) const
{
Q_ASSERT(self.base() == this);
- return self.iterateDirectSubpaths(visitor);
+ return self.iterateDirectSubpaths(std::move(visitor));
}
-inline DomItem DomBase::containingObject(DomItem &self) const
+inline DomItem DomBase::containingObject(const DomItem &self) const
{
Path path = pathFromOwner(self);
DomItem base = self.owner();
@@ -1986,7 +2244,7 @@ inline QString DomBase::typeName() const
return domTypeToString(kind());
}
-inline QList<QString> DomBase::fields(DomItem &self) const
+inline QList<QString> DomBase::fields(const DomItem &self) const
{
QList<QString> res;
self.iterateDirectSubpaths([&res](const PathEls::PathComponent &c, function_ref<DomItem()>) {
@@ -1997,7 +2255,7 @@ inline QList<QString> DomBase::fields(DomItem &self) const
return res;
}
-inline DomItem DomBase::field(DomItem &self, QStringView name) const
+inline DomItem DomBase::field(const DomItem &self, QStringView name) const
{
DomItem res;
self.iterateDirectSubpaths(
@@ -2011,7 +2269,7 @@ inline DomItem DomBase::field(DomItem &self, QStringView name) const
return res;
}
-inline index_type DomBase::indexes(DomItem &self) const
+inline index_type DomBase::indexes(const DomItem &self) const
{
index_type res = 0;
self.iterateDirectSubpaths([&res](const PathEls::PathComponent &c, function_ref<DomItem()>) {
@@ -2025,7 +2283,7 @@ inline index_type DomBase::indexes(DomItem &self) const
return res;
}
-inline DomItem DomBase::index(DomItem &self, qint64 index) const
+inline DomItem DomBase::index(const DomItem &self, qint64 index) const
{
DomItem res;
self.iterateDirectSubpaths(
@@ -2039,7 +2297,7 @@ inline DomItem DomBase::index(DomItem &self, qint64 index) const
return res;
}
-inline QSet<QString> const DomBase::keys(DomItem &self) const
+inline QSet<QString> const DomBase::keys(const DomItem &self) const
{
QSet<QString> res;
self.iterateDirectSubpaths([&res](const PathEls::PathComponent &c, function_ref<DomItem()>) {
@@ -2050,7 +2308,7 @@ inline QSet<QString> const DomBase::keys(DomItem &self) const
return res;
}
-inline DomItem DomBase::key(DomItem &self, QString name) const
+inline DomItem DomBase::key(const DomItem &self, const QString &name) const
{
DomItem res;
self.iterateDirectSubpaths(
@@ -2064,12 +2322,12 @@ inline DomItem DomBase::key(DomItem &self, QString name) const
return res;
}
-inline DomItem DomItem::subListItem(const List &list)
+inline DomItem DomItem::subListItem(const List &list) const
{
return DomItem(m_top, m_owner, m_ownerPath, list);
}
-inline DomItem DomItem::subMapItem(const Map &map)
+inline DomItem DomItem::subMapItem(const Map &map) const
{
return DomItem(m_top, m_owner, m_ownerPath, map);
}
diff --git a/src/qmldom/qqmldomlinewriter.cpp b/src/qmldom/qqmldomlinewriter.cpp
index 3200f4f9c5..33326cb01a 100644
--- a/src/qmldom/qqmldomlinewriter.cpp
+++ b/src/qmldom/qqmldomlinewriter.cpp
@@ -50,8 +50,9 @@ void PendingSourceLocation::commit()
updater(value);
}
-LineWriter::LineWriter(SinkF innerSink, QString fileName, const LineWriterOptions &options,
- int lineNr, int columnNr, int utf16Offset, QString currentLine)
+LineWriter::LineWriter(
+ const SinkF &innerSink, const QString &fileName, const LineWriterOptions &options,
+ int lineNr, int columnNr, int utf16Offset, const QString &currentLine)
: m_innerSinks({ innerSink }),
m_fileName(fileName),
m_lineNr(lineNr),
@@ -320,7 +321,7 @@ void LineWriter::handleTrailingSpace(LineWriterOptions::TrailingSpace trailingSp
}
}
-void LineWriter::reindentAndSplit(QString eol, bool eof)
+void LineWriter::reindentAndSplit(const QString &eol, bool eof)
{
// maybe write out
if (!eol.isEmpty() || eof) {
@@ -370,7 +371,7 @@ void LineWriter::textAddCallback(LineWriter::TextAddType t)
}
}
-void LineWriter::commitLine(QString eol, TextAddType tType, int untilChar)
+void LineWriter::commitLine(const QString &eol, TextAddType tType, int untilChar)
{
if (untilChar == -1)
untilChar = m_currentLine.size();
diff --git a/src/qmldom/qqmldomlinewriter_p.h b/src/qmldom/qqmldomlinewriter_p.h
index eb858f5b7d..86da8d6f54 100644
--- a/src/qmldom/qqmldomlinewriter_p.h
+++ b/src/qmldom/qqmldomlinewriter_p.h
@@ -88,7 +88,11 @@ public:
int maxLineLength = -1;
int strongMaxLineExtra = 20;
int minContentLength = 10;
+#if defined (Q_OS_WIN)
+ LineEndings lineEndings = LineEndings::Windows;
+#else
LineEndings lineEndings = LineEndings::Unix;
+#endif
TrailingSpace codeTrailingSpace = TrailingSpace::Remove;
TrailingSpace commentTrailingSpace = TrailingSpace::Remove;
TrailingSpace stringTrailingSpace = TrailingSpace::Preserve;
@@ -100,7 +104,8 @@ public:
};
Q_DECLARE_OPERATORS_FOR_FLAGS(LineWriterOptions::Updates)
-using PendingSourceLocationId = QAtomicInt;
+using PendingSourceLocationId = int;
+using PendingSourceLocationIdAtomic = QAtomicInt;
class LineWriter;
class QMLDOM_EXPORT PendingSourceLocation
@@ -132,9 +137,9 @@ public:
Eof
};
- LineWriter(SinkF innerSink, QString fileName,
+ LineWriter(const SinkF &innerSink, const QString &fileName,
const LineWriterOptions &options = LineWriterOptions(), int lineNr = 0,
- int columnNr = 0, int utf16Offset = 0, QString currentLine = QString());
+ int columnNr = 0, int utf16Offset = 0, const QString &currentLine = QString());
std::function<void(QStringView)> sink()
{
return [this](QStringView s) { this->write(s); };
@@ -143,7 +148,7 @@ public:
virtual ~LineWriter() { }
QList<SinkF> innerSinks() { return m_innerSinks; }
- void addInnerSink(SinkF s) { m_innerSinks.append(s); }
+ void addInnerSink(const SinkF &s) { m_innerSinks.append(s); }
LineWriter &ensureNewline(int nNewlines = 1, TextAddType t = TextAddType::Extra);
LineWriter &ensureSpace(TextAddType t = TextAddType::Extra);
LineWriter &ensureSpace(QStringView space, TextAddType t = TextAddType::Extra);
@@ -166,7 +171,7 @@ public:
endSourceLocation(pLoc);
return *this;
}
- void commitLine(QString eol, TextAddType t = TextAddType::Normal, int untilChar = -1);
+ void commitLine(const QString &eol, TextAddType t = TextAddType::Normal, int untilChar = -1);
void flush();
void eof(bool ensureNewline = true);
SourceLocation committedLocation() const;
@@ -183,7 +188,7 @@ public:
const QString &currentLine() const { return m_currentLine; }
const LineWriterOptions &options() const { return m_options; }
virtual void lineChanged() { }
- virtual void reindentAndSplit(QString eol, bool eof = false);
+ virtual void reindentAndSplit(const QString &eol, bool eof = false);
virtual void willCommit() { }
private:
@@ -205,7 +210,7 @@ protected:
int m_utf16Offset = 0; // utf16 offset since start for committed data
QString m_currentLine;
LineWriterOptions m_options;
- PendingSourceLocationId m_lastSourceLocationId;
+ PendingSourceLocationIdAtomic m_lastSourceLocationId;
QMap<PendingSourceLocationId, PendingSourceLocation> m_pendingSourceLocations;
QAtomicInt m_lastCallbackId;
QMap<int, std::function<bool(LineWriter &, TextAddType)>> m_textAddCallbacks;
diff --git a/src/qmldom/qqmldommock.cpp b/src/qmldom/qqmldommock.cpp
index 84f9452f9d..df49b9baaf 100644
--- a/src/qmldom/qqmldommock.cpp
+++ b/src/qmldom/qqmldommock.cpp
@@ -32,11 +32,11 @@ std::pair<QString, MockObject> MockObject::asStringPair() const
return std::make_pair(pathFromOwner().last().headName(), *this);
}
-bool MockObject::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool MockObject::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;
@@ -60,7 +60,7 @@ bool MockObject::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
return cont;
}
-std::shared_ptr<OwningItem> MockOwner::doCopy(DomItem &) const
+std::shared_ptr<OwningItem> MockOwner::doCopy(const DomItem &) const
{
return std::make_shared<MockOwner>(*this);
}
@@ -77,21 +77,21 @@ MockOwner::MockOwner(const MockOwner &o)
}
}
-std::shared_ptr<MockOwner> MockOwner::makeCopy(DomItem &self) const
+std::shared_ptr<MockOwner> MockOwner::makeCopy(const DomItem &self) const
{
return std::static_pointer_cast<MockOwner>(doCopy(self));
}
-Path MockOwner::canonicalPath(DomItem &) const
+Path MockOwner::canonicalPath(const DomItem &) const
{
return pathFromTop;
}
-bool MockOwner::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool MockOwner::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;
diff --git a/src/qmldom/qqmldommock_p.h b/src/qmldom/qqmldommock_p.h
index b35d4d2e1c..97504cc631 100644
--- a/src/qmldom/qqmldommock_p.h
+++ b/src/qmldom/qqmldommock_p.h
@@ -43,7 +43,7 @@ public:
constexpr static DomType kindValue = DomType::MockObject;
DomType kind() const override { return kindValue; }
- MockObject(Path pathFromOwner = Path(), QMap<QString, MockObject> subObjects = {},
+ MockObject(const Path &pathFromOwner = Path(), QMap<QString, MockObject> subObjects = {},
QMap<QString, QCborValue> subValues = {})
: CommentableDomElement(pathFromOwner), subObjects(subObjects), subValues(subValues)
{
@@ -52,7 +52,7 @@ public:
MockObject copy() const;
std::pair<QString, MockObject> asStringPair() const;
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override;
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override;
QMap<QString, MockObject> subObjects;
QMap<QString, QCborValue> subValues;
@@ -62,13 +62,13 @@ public:
class MockOwner final : public OwningItem
{
protected:
- std::shared_ptr<OwningItem> doCopy(DomItem &self) const override;
+ std::shared_ptr<OwningItem> doCopy(const DomItem &self) const override;
public:
constexpr static DomType kindValue = DomType::MockOwner;
DomType kind() const override { return kindValue; }
- MockOwner(Path pathFromTop = Path(), int derivedFrom = 0,
+ MockOwner(const Path &pathFromTop = Path(), int derivedFrom = 0,
QMap<QString, MockObject> subObjects = {}, QMap<QString, QCborValue> subValues = {},
QMap<QString, QMap<QString, MockObject>> subMaps = {},
QMap<QString, QMultiMap<QString, MockObject>> subMultiMaps = {},
@@ -83,7 +83,7 @@ public:
{
}
- MockOwner(Path pathFromTop, int derivedFrom, QDateTime dataRefreshedAt,
+ MockOwner(const Path &pathFromTop, int derivedFrom, QDateTime dataRefreshedAt,
QMap<QString, MockObject> subObjects = {}, QMap<QString, QCborValue> subValues = {})
: OwningItem(derivedFrom, dataRefreshedAt),
pathFromTop(pathFromTop),
@@ -94,10 +94,10 @@ public:
MockOwner(const MockOwner &o);
- std::shared_ptr<MockOwner> makeCopy(DomItem &self) const;
- Path canonicalPath(DomItem &self) const override;
+ std::shared_ptr<MockOwner> makeCopy(const DomItem &self) const;
+ Path canonicalPath(const DomItem &self) const override;
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override;
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override;
Path pathFromTop;
QMap<QString, MockObject> subObjects;
diff --git a/src/qmldom/qqmldommoduleindex.cpp b/src/qmldom/qqmldommoduleindex.cpp
index 3ba7814189..d44c9ae003 100644
--- a/src/qmldom/qqmldommoduleindex.cpp
+++ b/src/qmldom/qqmldommoduleindex.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmldomtop_p.h"
#include "qqmldomelements_p.h"
+#include "qqmldom_utils_p.h"
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
@@ -26,7 +27,7 @@ static ErrorGroups myExportErrors()
return res;
}
-bool ModuleScope::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool ModuleScope::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = true;
cont = cont && self.dvValueField(visitor, Fields::uri, uri);
@@ -35,19 +36,19 @@ bool ModuleScope::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
int minorVersion = version.minorVersion;
return self.subMapItem(Map(
self.pathFromOwner().field(Fields::exports),
- [minorVersion](DomItem &mapExp, QString name) -> DomItem {
+ [minorVersion](const DomItem &mapExp, const QString &name) -> DomItem {
DomItem mapExpOw = mapExp.owner();
QList<DomItem> exports =
mapExp.ownerAs<ModuleIndex>()->exportsWithNameAndMinorVersion(
mapExpOw, name, minorVersion);
return mapExp.subListItem(List::fromQList<DomItem>(
mapExp.pathFromOwner().key(name), exports,
- [](DomItem &, const PathEls::PathComponent &, DomItem &el) {
+ [](const DomItem &, const PathEls::PathComponent &, const DomItem &el) {
return el;
},
ListOptions::Normal));
},
- [](DomItem &mapExp) {
+ [](const DomItem &mapExp) {
DomItem mapExpOw = mapExp.owner();
return mapExp.ownerAs<ModuleIndex>()->exportNames(mapExpOw);
},
@@ -57,11 +58,11 @@ bool ModuleScope::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
Path basePath = Path::Current(PathCurrent::Obj).field(Fields::exports);
return self.subMapItem(Map(
self.pathFromOwner().field(Fields::symbols),
- [basePath](DomItem &mapExp, QString name) -> DomItem {
+ [basePath](const DomItem &mapExp, const QString &name) -> DomItem {
QList<Path> symb({ basePath.key(name) });
return mapExp.subReferencesItem(PathEls::Key(name), symb);
},
- [](DomItem &mapExp) {
+ [](const DomItem &mapExp) {
DomItem mapExpOw = mapExp.owner();
return mapExp.ownerAs<ModuleIndex>()->exportNames(mapExpOw);
},
@@ -73,7 +74,7 @@ bool ModuleScope::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
return cont;
}
-std::shared_ptr<OwningItem> ModuleIndex::doCopy(DomItem &) const
+std::shared_ptr<OwningItem> ModuleIndex::doCopy(const DomItem &) const
{
return std::make_shared<ModuleIndex>(*this);
}
@@ -113,14 +114,14 @@ ModuleIndex::~ModuleIndex()
}
}
-bool ModuleIndex::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool ModuleIndex::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = self.dvValueField(visitor, Fields::uri, uri());
cont = cont && self.dvValueField(visitor, Fields::majorVersion, majorVersion());
cont = cont && self.dvItemField(visitor, Fields::moduleScope, [this, &self]() {
return self.subMapItem(Map(
pathFromOwner(self).field(Fields::moduleScope),
- [](DomItem &map, QString minorVersionStr) {
+ [](const DomItem &map, const QString &minorVersionStr) {
bool ok;
int minorVersion = minorVersionStr.toInt(&ok);
if (minorVersionStr.isEmpty()
@@ -130,7 +131,7 @@ bool ModuleIndex::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
return DomItem();
return map.copy(map.ownerAs<ModuleIndex>()->ensureMinorVersion(minorVersion));
},
- [this](DomItem &) {
+ [this](const DomItem &) {
QSet<QString> res;
for (int el : minorVersions())
if (el >= 0)
@@ -150,7 +151,7 @@ bool ModuleIndex::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
return cont;
}
-QSet<QString> ModuleIndex::exportNames(DomItem &self) const
+QSet<QString> ModuleIndex::exportNames(const DomItem &self) const
{
QSet<QString> res;
QList<Path> mySources = sources();
@@ -161,7 +162,7 @@ QSet<QString> ModuleIndex::exportNames(DomItem &self) const
return res;
}
-QList<DomItem> ModuleIndex::autoExports(DomItem &self) const
+QList<DomItem> ModuleIndex::autoExports(const DomItem &self) const
{
QList<DomItem> res;
Path selfPath = canonicalPath(self).field(Fields::autoExports);
@@ -179,7 +180,7 @@ QList<DomItem> ModuleIndex::autoExports(DomItem &self) const
DomItem env = self.environment();
if (!cachedPaths.isEmpty()) {
bool outdated = false;
- for (Path p : cachedPaths) {
+ for (const Path &p : cachedPaths) {
DomItem newEl = env.path(p);
if (!newEl) {
outdated = true;
@@ -199,9 +200,9 @@ QList<DomItem> ModuleIndex::autoExports(DomItem &self) const
QList<Path> mySources = sources();
QSet<QString> knownAutoImportUris;
QList<ModuleAutoExport> knownExports;
- for (Path p : mySources) {
+ for (const Path &p : mySources) {
DomItem autoExports = self.path(p).field(Fields::autoExports);
- for (DomItem i : autoExports.values()) {
+ for (const DomItem &i : autoExports.values()) {
if (const ModuleAutoExport *iPtr = i.as<ModuleAutoExport>()) {
if (!knownAutoImportUris.contains(iPtr->import.uri.toString())
|| !knownExports.contains(*iPtr)) {
@@ -218,7 +219,7 @@ QList<DomItem> ModuleIndex::autoExports(DomItem &self) const
return res;
}
-QList<DomItem> ModuleIndex::exportsWithNameAndMinorVersion(DomItem &self, QString name,
+QList<DomItem> ModuleIndex::exportsWithNameAndMinorVersion(const DomItem &self, const QString &name,
int minorVersion) const
{
Path myPath = Paths::moduleScopePath(uri(), Version(majorVersion(), minorVersion))
@@ -245,12 +246,12 @@ QList<DomItem> ModuleIndex::exportsWithNameAndMinorVersion(DomItem &self, QStrin
undef.append(exportItem);
} else {
if (majorVersion() < 0)
- self.addError(myVersioningErrors()
+ self.addError(std::move(myVersioningErrors()
.error(tr("Module %1 (unversioned) has versioned entries "
"for '%2' from %3")
.arg(uri(), name,
source.canonicalPath().toString()))
- .withPath(myPath));
+ .withPath(myPath)));
if ((versionPtr->majorVersion == majorVersion()
|| versionPtr->majorVersion == Version::Undefined)
&& versionPtr->minorVersion >= vNow
@@ -265,11 +266,11 @@ QList<DomItem> ModuleIndex::exportsWithNameAndMinorVersion(DomItem &self, QStrin
}
if (!undef.isEmpty()) {
if (!res.isEmpty()) {
- self.addError(myVersioningErrors()
+ self.addError(std::move(myVersioningErrors()
.error(tr("Module %1 (major version %2) has versioned and "
"unversioned entries for '%3'")
.arg(uri(), QString::number(majorVersion()), name))
- .withPath(myPath));
+ .withPath(myPath)));
return res + undef;
} else {
return undef;
@@ -296,8 +297,8 @@ ModuleScope *ModuleIndex::ensureMinorVersion(int minorVersion)
minorVersion = Version::Latest;
{
QMutexLocker l(mutex());
- auto it = m_moduleScope.find(minorVersion);
- if (it != m_moduleScope.end())
+ auto it = m_moduleScope.constFind(minorVersion);
+ if (it != m_moduleScope.cend())
return *it;
}
ModuleScope *res = nullptr;
@@ -305,8 +306,8 @@ ModuleScope *ModuleIndex::ensureMinorVersion(int minorVersion)
auto cleanup = qScopeGuard([&newScope] { delete newScope; });
{
QMutexLocker l(mutex());
- auto it = m_moduleScope.find(minorVersion);
- if (it != m_moduleScope.end()) {
+ auto it = m_moduleScope.constFind(minorVersion);
+ if (it != m_moduleScope.cend()) {
res = *it;
} else {
res = newScope;
@@ -317,7 +318,7 @@ ModuleScope *ModuleIndex::ensureMinorVersion(int minorVersion)
return res;
}
-void ModuleIndex::mergeWith(std::shared_ptr<ModuleIndex> o)
+void ModuleIndex::mergeWith(const std::shared_ptr<ModuleIndex> &o)
{
if (o) {
QList<Path> qmltypesPaths;
@@ -329,7 +330,7 @@ void ModuleIndex::mergeWith(std::shared_ptr<ModuleIndex> o)
}
{
QMutexLocker l(mutex());
- for (Path qttPath : qmltypesPaths) {
+ for (const Path &qttPath : qmltypesPaths) {
if (!m_qmltypesFilesPaths.contains((qttPath)))
m_qmltypesFilesPaths.append(qttPath);
}
@@ -343,7 +344,7 @@ void ModuleIndex::mergeWith(std::shared_ptr<ModuleIndex> o)
}
}
-QList<Path> ModuleIndex::qmldirsToLoad(DomItem &self)
+QList<Path> ModuleIndex::qmldirsToLoad(const DomItem &self)
{
// this always checks the filesystem to the qmldir file to load
DomItem env = self.environment();
@@ -355,10 +356,15 @@ QList<Path> ModuleIndex::qmldirsToLoad(DomItem &self)
+ QLatin1String("/qmldir");
QString dirPath;
if (majorVersion() >= 0) {
- for (QString path : envPtr->loadPaths()) {
+ qCDebug(QQmlJSDomImporting)
+ << "ModuleIndex::qmldirsToLoad: Searching versioned module" << subPath
+ << majorVersion() << "in" << envPtr->loadPaths().join(u", ");
+ for (const QString &path : envPtr->loadPaths()) {
QDir dir(path);
QFileInfo fInfo(dir.filePath(subPathV));
if (fInfo.isFile()) {
+ qCDebug(QQmlJSDomImporting)
+ << "Found versioned module in " << fInfo.canonicalFilePath();
logicalPath = subPathV;
dirPath = fInfo.canonicalFilePath();
break;
@@ -366,10 +372,14 @@ QList<Path> ModuleIndex::qmldirsToLoad(DomItem &self)
}
}
if (dirPath.isEmpty()) {
- for (QString path : envPtr->loadPaths()) {
+ qCDebug(QQmlJSDomImporting) << "ModuleIndex::qmldirsToLoad: Searching unversioned module"
+ << subPath << "in" << envPtr->loadPaths().join(u", ");
+ for (const QString &path : envPtr->loadPaths()) {
QDir dir(path);
QFileInfo fInfo(dir.filePath(subPath + QLatin1String("/qmldir")));
if (fInfo.isFile()) {
+ qCDebug(QQmlJSDomImporting)
+ << "Found unversioned module in " << fInfo.canonicalFilePath();
logicalPath = subPath + QLatin1String("/qmldir");
dirPath = fInfo.canonicalFilePath();
break;
@@ -380,10 +390,14 @@ QList<Path> ModuleIndex::qmldirsToLoad(DomItem &self)
QMutexLocker l(mutex());
m_qmldirPaths = QList<Path>({ Paths::qmldirFilePath(dirPath) });
} else if (uri() != u"QML") {
- addErrorLocal(myExportErrors()
- .warning(tr("Failed to find main qmldir file for %1 %2")
- .arg(uri(), QString::number(majorVersion())))
- .handle());
+ const QString loadPaths = envPtr->loadPaths().join(u", "_s);
+ qCDebug(QQmlJSDomImporting) << "ModuleIndex::qmldirsToLoad: qmldir at"
+ << (uri() + u"/qmldir"_s) << " was not found in " << loadPaths;
+ addErrorLocal(
+ myExportErrors()
+ .warning(tr("Failed to find main qmldir file for %1 %2 in %3.")
+ .arg(uri(), QString::number(majorVersion()), loadPaths))
+ .handle());
}
return qmldirPaths();
}
diff --git a/src/qmldom/qqmldommoduleindex_p.h b/src/qmldom/qqmldommoduleindex_p.h
index 1d4d9be1df..f2b2731624 100644
--- a/src/qmldom/qqmldommoduleindex_p.h
+++ b/src/qmldom/qqmldommoduleindex_p.h
@@ -28,7 +28,7 @@ public:
constexpr static DomType kindValue = DomType::ModuleScope;
DomType kind() const override { return kindValue; }
- ModuleScope(QString uri = QString(), const Version &version = Version())
+ ModuleScope(const QString &uri = QString(), const Version &version = Version())
: uri(uri), version(version)
{
}
@@ -38,12 +38,12 @@ public:
return Path::Field(Fields::moduleScope)
.key(version.isValid() ? QString::number(version.minorVersion) : QString());
}
- Path pathFromOwner(DomItem &) const override { return pathFromOwner(); }
- Path canonicalPath(DomItem &self) const override
+ Path pathFromOwner(const DomItem &) const override { return pathFromOwner(); }
+ Path canonicalPath(const DomItem &self) const override
{
return self.owner().canonicalPath().path(pathFromOwner());
}
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) override;
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override;
QString uri;
Version version;
@@ -54,15 +54,16 @@ class QMLDOM_EXPORT ModuleIndex final : public OwningItem
Q_DECLARE_TR_FUNCTIONS(ModuleIndex);
protected:
- std::shared_ptr<OwningItem> doCopy(DomItem &self) const override;
+ std::shared_ptr<OwningItem> doCopy(const DomItem &self) const override;
public:
enum class Status { NotLoaded, Loading, Loaded };
constexpr static DomType kindValue = DomType::ModuleIndex;
DomType kind() const override { return kindValue; }
- ModuleIndex(QString uri, int majorVersion, int derivedFrom = 0,
- QDateTime lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC))
+ ModuleIndex(
+ const QString &uri, int majorVersion, int derivedFrom = 0,
+ const QDateTime &lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC))
: OwningItem(derivedFrom, lastDataUpdateAt), m_uri(uri), m_majorVersion(majorVersion)
{
}
@@ -71,21 +72,21 @@ public:
~ModuleIndex();
- std::shared_ptr<ModuleIndex> makeCopy(DomItem &self) const
+ std::shared_ptr<ModuleIndex> makeCopy(const DomItem &self) const
{
return std::static_pointer_cast<ModuleIndex>(doCopy(self));
}
- Path canonicalPath(DomItem &) const override
+ Path canonicalPath(const DomItem &) const override
{
return Paths::moduleIndexPath(uri(), majorVersion());
}
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) override;
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override;
- QSet<QString> exportNames(DomItem &self) const;
+ QSet<QString> exportNames(const DomItem &self) const;
- QList<DomItem> exportsWithNameAndMinorVersion(DomItem &self, QString name,
+ QList<DomItem> exportsWithNameAndMinorVersion(const DomItem &self, const QString &name,
int minorVersion) const;
QString uri() const { return m_uri; }
@@ -98,15 +99,15 @@ public:
return m_moduleScope.keys();
}
ModuleScope *ensureMinorVersion(int minorVersion);
- void mergeWith(std::shared_ptr<ModuleIndex> o);
- void addQmltypeFilePath(Path p)
+ void mergeWith(const std::shared_ptr<ModuleIndex> &o);
+ void addQmltypeFilePath(const Path &p)
{
QMutexLocker l(mutex());
if (!m_qmltypesFilesPaths.contains(p))
m_qmltypesFilesPaths.append(p);
}
- QList<Path> qmldirsToLoad(DomItem &self);
+ QList<Path> qmldirsToLoad(const DomItem &self);
QList<Path> qmltypesFilesPaths() const
{
QMutexLocker l(mutex());
@@ -122,7 +123,7 @@ public:
QMutexLocker l(mutex());
return m_directoryPaths;
}
- QList<DomItem> autoExports(DomItem &self) const;
+ QList<DomItem> autoExports(const DomItem &self) const;
private:
QString m_uri;
diff --git a/src/qmldom/qqmldomoutwriter.cpp b/src/qmldom/qqmldomoutwriter.cpp
index 7bdbf505e2..bcfc8ace69 100644
--- a/src/qmldom/qqmldomoutwriter.cpp
+++ b/src/qmldom/qqmldomoutwriter.cpp
@@ -15,14 +15,13 @@ QT_BEGIN_NAMESPACE
namespace QQmlJS {
namespace Dom {
-OutWriterState::OutWriterState(Path itCanonicalPath, DomItem &it, FileLocations::Tree fLoc)
+OutWriterState::OutWriterState(
+ const Path &itCanonicalPath, const DomItem &it, const FileLocations::Tree &fLoc)
: itemCanonicalPath(itCanonicalPath), item(it), currentMap(fLoc)
{
DomItem cRegions = it.field(Fields::comments);
- if (const RegionComments *cRegionsPtr = cRegions.as<RegionComments>()) {
- pendingComments = cRegionsPtr->regionComments;
- fLoc->info().ensureCommentLocations(pendingComments.keys());
- }
+ if (const RegionComments *cRegionsPtr = cRegions.as<RegionComments>())
+ pendingComments = cRegionsPtr->regionComments();
}
void OutWriterState::closeState(OutWriter &w)
@@ -50,7 +49,7 @@ OutWriterState &OutWriter::state(int i)
return states[states.size() - 1 - i];
}
-void OutWriter::itemStart(DomItem &it)
+void OutWriter::itemStart(const DomItem &it)
{
if (!topLocation->path())
topLocation->setPath(it.canonicalPath());
@@ -74,135 +73,304 @@ void OutWriter::itemStart(DomItem &it)
if (updateLocs)
state().fullRegionId = lineWriter.startSourceLocation(
[newFLoc](SourceLocation l) { FileLocations::updateFullLocation(newFLoc, l); });
- regionStart(QString());
+ regionStart(MainRegion);
}
-void OutWriter::itemEnd(DomItem &it)
+void OutWriter::itemEnd(const DomItem &it)
{
Q_ASSERT(states.size() > 0);
Q_ASSERT(state().item == it);
- regionEnd(QString());
+ regionEnd(MainRegion);
state().closeState(*this);
states.removeLast();
}
-void OutWriter::regionStart(QString rName)
+void OutWriter::regionStart(FileLocationRegion region)
{
- Q_ASSERT(!state().pendingRegions.contains(rName));
+ Q_ASSERT(!state().pendingRegions.contains(region));
FileLocations::Tree fMap = state().currentMap;
- if (!skipComments && state().pendingComments.contains(rName)) {
+ if (!skipComments && state().pendingComments.contains(region)) {
bool updateLocs = lineWriter.options().updateOptions & LineWriterOptions::Update::Locations;
QList<SourceLocation> *cLocs =
- (updateLocs ? &(fMap->info().preCommentLocations[rName]) : nullptr);
- state().pendingComments[rName].writePre(*this, cLocs);
+ (updateLocs ? &(fMap->info().preCommentLocations[region]) : nullptr);
+ state().pendingComments[region].writePre(*this, cLocs);
}
- state().pendingRegions[rName] = lineWriter.startSourceLocation(
- [rName, fMap](SourceLocation l) { FileLocations::addRegion(fMap, rName, l); });
+ state().pendingRegions[region] = lineWriter.startSourceLocation(
+ [region, fMap](SourceLocation l) { FileLocations::addRegion(fMap, region, l); });
}
-void OutWriter::regionEnd(QString rName)
+void OutWriter::regionEnd(FileLocationRegion region)
{
- Q_ASSERT(state().pendingRegions.contains(rName));
+ Q_ASSERT(state().pendingRegions.contains(region));
FileLocations::Tree fMap = state().currentMap;
- lineWriter.endSourceLocation(state().pendingRegions.value(rName));
- state().pendingRegions.remove(rName);
- if (state().pendingComments.contains(rName)) {
+ lineWriter.endSourceLocation(state().pendingRegions.value(region));
+ state().pendingRegions.remove(region);
+ if (state().pendingComments.contains(region)) {
if (!skipComments) {
bool updateLocs =
lineWriter.options().updateOptions & LineWriterOptions::Update::Locations;
QList<SourceLocation> *cLocs =
- (updateLocs ? &(fMap->info().postCommentLocations[rName]) : nullptr);
- state().pendingComments[rName].writePost(*this, cLocs);
+ (updateLocs ? &(fMap->info().postCommentLocations[region]) : nullptr);
+ state().pendingComments[region].writePost(*this, cLocs);
}
- state().pendingComments.remove(rName);
+ state().pendingComments.remove(region);
}
}
-OutWriter &OutWriter::writeRegion(QString rName, QStringView toWrite)
+/*!
+\internal
+Helper method for writeRegion(FileLocationRegion region) that allows to use
+\c{writeRegion(ColonTokenRegion);} instead of having to write out the more error-prone
+\c{writeRegion(ColonTokenRegion, ":");} for tokens and keywords.
+*/
+OutWriter &OutWriter::writeRegion(FileLocationRegion region)
{
- regionStart(rName);
+ QString codeForRegion;
+ switch (region) {
+ case ComponentKeywordRegion:
+ codeForRegion = u"component"_s;
+ break;
+ case IdColonTokenRegion:
+ case ColonTokenRegion:
+ codeForRegion = u":"_s;
+ break;
+ case ImportTokenRegion:
+ codeForRegion = u"import"_s;
+ break;
+ case AsTokenRegion:
+ codeForRegion = u"as"_s;
+ break;
+ case OnTokenRegion:
+ codeForRegion = u"on"_s;
+ break;
+ case IdTokenRegion:
+ codeForRegion = u"id"_s;
+ break;
+ case LeftBraceRegion:
+ codeForRegion = u"{"_s;
+ break;
+ case RightBraceRegion:
+ codeForRegion = u"}"_s;
+ break;
+ case LeftBracketRegion:
+ codeForRegion = u"["_s;
+ break;
+ case RightBracketRegion:
+ codeForRegion = u"]"_s;
+ break;
+ case LeftParenthesisRegion:
+ codeForRegion = u"("_s;
+ break;
+ case RightParenthesisRegion:
+ codeForRegion = u")"_s;
+ break;
+ case EnumKeywordRegion:
+ codeForRegion = u"enum"_s;
+ break;
+ case DefaultKeywordRegion:
+ codeForRegion = u"default"_s;
+ break;
+ case RequiredKeywordRegion:
+ codeForRegion = u"required"_s;
+ break;
+ case ReadonlyKeywordRegion:
+ codeForRegion = u"readonly"_s;
+ break;
+ case PropertyKeywordRegion:
+ codeForRegion = u"property"_s;
+ break;
+ case FunctionKeywordRegion:
+ codeForRegion = u"function"_s;
+ break;
+ case SignalKeywordRegion:
+ codeForRegion = u"signal"_s;
+ break;
+ case ReturnKeywordRegion:
+ codeForRegion = u"return"_s;
+ break;
+ case EllipsisTokenRegion:
+ codeForRegion = u"..."_s;
+ break;
+ case EqualTokenRegion:
+ codeForRegion = u"="_s;
+ break;
+ case PragmaKeywordRegion:
+ codeForRegion = u"pragma"_s;
+ break;
+ case CommaTokenRegion:
+ codeForRegion = u","_s;
+ break;
+ case ForKeywordRegion:
+ codeForRegion = u"for"_s;
+ break;
+ case ElseKeywordRegion:
+ codeForRegion = u"else"_s;
+ break;
+ case DoKeywordRegion:
+ codeForRegion = u"do"_s;
+ break;
+ case WhileKeywordRegion:
+ codeForRegion = u"while"_s;
+ break;
+ case TryKeywordRegion:
+ codeForRegion = u"try"_s;
+ break;
+ case CatchKeywordRegion:
+ codeForRegion = u"catch"_s;
+ break;
+ case FinallyKeywordRegion:
+ codeForRegion = u"finally"_s;
+ break;
+ case CaseKeywordRegion:
+ codeForRegion = u"case"_s;
+ break;
+ case ThrowKeywordRegion:
+ codeForRegion = u"throw"_s;
+ break;
+ case ContinueKeywordRegion:
+ codeForRegion = u"continue"_s;
+ break;
+ case BreakKeywordRegion:
+ codeForRegion = u"break"_s;
+ break;
+ case QuestionMarkTokenRegion:
+ codeForRegion = u"?"_s;
+ break;
+ case SemicolonTokenRegion:
+ codeForRegion = u";"_s;
+ break;
+ case IfKeywordRegion:
+ codeForRegion = u"if"_s;
+ break;
+ case SwitchKeywordRegion:
+ codeForRegion = u"switch"_s;
+ break;
+ case YieldKeywordRegion:
+ codeForRegion = u"yield"_s;
+ break;
+ // not keywords:
+ case ImportUriRegion:
+ case IdNameRegion:
+ case IdentifierRegion:
+ case PragmaValuesRegion:
+ case MainRegion:
+ case OnTargetRegion:
+ case TypeIdentifierRegion:
+ case FirstSemicolonTokenRegion:
+ case SecondSemicolonRegion:
+ case InOfTokenRegion:
+ case OperatorTokenRegion:
+ case VersionRegion:
+ case EnumValueRegion:
+ Q_ASSERT_X(false, "regionToString", "Using regionToString on a value or an identifier!");
+ return *this;
+ }
+
+ return writeRegion(region, codeForRegion);
+}
+
+OutWriter &OutWriter::writeRegion(FileLocationRegion region, QStringView toWrite)
+{
+ regionStart(region);
lineWriter.write(toWrite);
- regionEnd(rName);
+ regionEnd(region);
return *this;
}
+/*!
+ \internal
+ Restores written out FileItem using intermediate information saved during DOM traversal.
+ It enables verifying DOM consistency of the written item later.
-DomItem OutWriter::updatedFile(DomItem &qmlFile)
+ At the moment of writing, intermediate information consisting only of UpdatedScriptExpression,
+ however this is subject for change. The process of restoration is the following:
+ 1. Creating copy of the initial fileItem
+ 2. Updating relevant data/subitems modified during the WriteOut
+ 3. Returning an item containing updates.
+ */
+DomItem OutWriter::restoreWrittenFileItem(const DomItem &fileItem)
{
- Q_ASSERT(qmlFile.internalKind() == DomType::QmlFile);
- if (std::shared_ptr<QmlFile> qmlFilePtr = qmlFile.ownerAs<QmlFile>()) {
- std::shared_ptr<QmlFile> copyPtr = qmlFilePtr->makeCopy(qmlFile);
- DomItem env = qmlFile.environment();
- std::shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>();
- Q_ASSERT(envPtr);
- auto newEnvPtr = std::make_shared<DomEnvironment>(
- envPtr, envPtr->loadPaths(), envPtr->options());
- newEnvPtr->addQmlFile(copyPtr);
- MutableDomItem copy = MutableDomItem(DomItem(newEnvPtr).copy(copyPtr));
- FileLocations::Tree newLoc = topLocation;
- Path qmlFilePath = qmlFile.canonicalPath();
- if (newLoc->path() != qmlFilePath) {
- if (newLoc->path()) {
- if (newLoc->path().length() > qmlFilePath.length()
- && newLoc->path().mid(0, qmlFilePath.length()) == qmlFilePath) {
- newLoc = FileLocations::createTree(qmlFilePath);
- FileLocations::Tree loc =
- FileLocations::ensure(newLoc, newLoc->path().mid(qmlFilePath.length()),
- AttachedInfo::PathType::Relative);
- loc->setSubItems(topLocation->subItems());
- } else {
- qCWarning(writeOutLog)
- << "failed to base fileLocations in OutWriter (" << newLoc->path()
- << ") to current file (" << qmlFilePath << ")";
- }
- } else {
- newLoc = FileLocations::createTree(qmlFilePath);
- Q_ASSERT(newLoc->subItems().isEmpty() && newLoc->info().regions.isEmpty());
+ switch (fileItem.internalKind()) {
+ case DomType::QmlFile:
+ return writtenQmlFileItem(fileItem, fileItem.canonicalPath());
+ case DomType::JsFile:
+ return writtenJsFileItem(fileItem, fileItem.canonicalPath());
+ default:
+ qCWarning(writeOutLog) << fileItem.internalKind() << " is not supported";
+ return DomItem{};
+ }
+}
+
+DomItem OutWriter::writtenQmlFileItem(const DomItem &fileItem, const Path &filePath)
+{
+ Q_ASSERT(fileItem.internalKind() == DomType::QmlFile);
+ auto mutableFile = fileItem.makeCopy(DomItem::CopyOption::EnvDisconnected);
+ // QmlFile specific visitor for reformattedScriptExpressions tree
+ // lambda function responsible for the update of the initial expression by the formatted one
+ auto exprUpdater = [&mutableFile, filePath](
+ const Path &p, const UpdatedScriptExpression::Tree &t) {
+ if (std::shared_ptr<ScriptExpression> formattedExpr = t->info().expr) {
+ Q_ASSERT(p.mid(0, filePath.length()) == filePath);
+ MutableDomItem originalExprItem = mutableFile.path(p.mid(filePath.length()));
+ if (!originalExprItem)
+ qCWarning(writeOutLog) << "failed to get" << p.mid(filePath.length()) << "from"
+ << mutableFile.canonicalPath();
+ // Verifying originalExprItem.as<ScriptExpression>() == false is handy
+ // because we can't call setScript on the ScriptExpression itself and it needs to
+ // be called on the container / parent item. See setScript for details
+ else if (formattedExpr->ast()
+ || (!originalExprItem.as<ScriptExpression>()
+ || !originalExprItem.as<ScriptExpression>()->ast()))
+ originalExprItem.setScript(formattedExpr);
+ else {
+ logScriptExprUpdateSkipped(originalExprItem.item(),
+ originalExprItem.canonicalPath(), formattedExpr);
}
}
- copyPtr->setFileLocationsTree(newLoc);
- UpdatedScriptExpression::visitTree(
- reformattedScriptExpressions,
- [&copy, qmlFilePath](Path p, UpdatedScriptExpression::Tree t) {
- if (std::shared_ptr<ScriptExpression> exprPtr = t->info().expr) {
- Q_ASSERT(p.mid(0, qmlFilePath.length()) == qmlFilePath);
- MutableDomItem targetExpr = copy.path(p.mid(qmlFilePath.length()));
- if (!targetExpr)
- qCWarning(writeOutLog) << "failed to get" << p.mid(qmlFilePath.length())
- << "from" << copy.canonicalPath();
- else if (exprPtr->ast()
- || (!targetExpr.as<ScriptExpression>()
- || !targetExpr.as<ScriptExpression>()->ast()))
- targetExpr.setScript(exprPtr);
- else {
- qCWarning(writeOutLog).noquote()
- << "Skipped update of reformatted ScriptExpression with "
- "code:\n---------------\n"
- << exprPtr->code() << "\n---------------\n preCode:" <<
- [exprPtr](Sink s) { sinkEscaped(s, exprPtr->preCode()); }
- << "\n postCode: " <<
- [exprPtr](Sink s) { sinkEscaped(s, exprPtr->postCode()); }
- << "\n as it failed standalone reparse with errors:" <<
- [&targetExpr, exprPtr](Sink s) {
- targetExpr.item()
- .copy(exprPtr, targetExpr.canonicalPath())
- .iterateErrors(
- [s](DomItem, ErrorMessage msg) {
- s(u"\n ");
- msg.dump(s);
- return true;
- },
- true);
- }
- << "\n";
- }
- }
- return true;
- });
- return copy.item();
- }
- return DomItem();
+ return true;
+ };
+ // update relevant formatted expressions
+ UpdatedScriptExpression::visitTree(reformattedScriptExpressions, exprUpdater);
+ return mutableFile.item();
}
+DomItem OutWriter::writtenJsFileItem(const DomItem &fileItem, const Path &filePath)
+{
+ Q_ASSERT(fileItem.internalKind() == DomType::JsFile);
+ auto mutableFile = fileItem.makeCopy(DomItem::CopyOption::EnvDisconnected);
+ UpdatedScriptExpression::visitTree(
+ reformattedScriptExpressions,
+ [&mutableFile, filePath](const Path &p, const UpdatedScriptExpression::Tree &t) {
+ if (std::shared_ptr<ScriptExpression> formattedExpr = t->info().expr) {
+ Q_ASSERT(p.mid(0, filePath.length()) == filePath);
+ mutableFile.mutableAs<JsFile>()->setExpression(formattedExpr);
+ }
+ return true;
+ });
+ return mutableFile.item();
+}
+
+void OutWriter::logScriptExprUpdateSkipped(
+ const DomItem &exprItem, const Path &exprPath,
+ const std::shared_ptr<ScriptExpression> &formattedExpr)
+{
+ qCWarning(writeOutLog).noquote() << "Skipped update of reformatted ScriptExpression with "
+ "code:\n---------------\n"
+ << formattedExpr->code() << "\n---------------\n preCode:" <<
+ [&formattedExpr](Sink s) { sinkEscaped(s, formattedExpr->preCode()); }
+ << "\n postCode: " <<
+ [&formattedExpr](Sink s) { sinkEscaped(s, formattedExpr->postCode()); }
+ << "\n as it failed standalone reparse with errors:" <<
+ [&exprItem, &exprPath, &formattedExpr](Sink s) {
+ exprItem.copy(formattedExpr, exprPath)
+ .iterateErrors(
+ [s](const DomItem &, const ErrorMessage &msg) {
+ s(u"\n ");
+ msg.dump(s);
+ return true;
+ },
+ true);
+ } << "\n";
+}
} // namespace Dom
} // namespace QQmlJS
QT_END_NAMESPACE
diff --git a/src/qmldom/qqmldomoutwriter_p.h b/src/qmldom/qqmldomoutwriter_p.h
index 81251e60be..8b00223ea2 100644
--- a/src/qmldom/qqmldomoutwriter_p.h
+++ b/src/qmldom/qqmldomoutwriter_p.h
@@ -27,16 +27,10 @@ QT_BEGIN_NAMESPACE
namespace QQmlJS {
namespace Dom {
-#define QMLDOM_USTRING(s) u##s
-#define QMLDOM_REGION(name) constexpr const auto name = QMLDOM_USTRING(#name)
-// namespace, so it cam be reopened to add more entries
-namespace Regions {
-} // namespace Regions
-
class QMLDOM_EXPORT OutWriterState
{
public:
- OutWriterState(Path itPath, DomItem &it, FileLocations::Tree fLoc);
+ OutWriterState(const Path &itPath, const DomItem &it, const FileLocations::Tree &fLoc);
void closeState(OutWriter &);
@@ -44,8 +38,8 @@ public:
DomItem item;
PendingSourceLocationId fullRegionId;
FileLocations::Tree currentMap;
- QMap<QString, PendingSourceLocationId> pendingRegions;
- QMap<QString, CommentedElement> pendingComments;
+ QMap<FileLocationRegion, PendingSourceLocationId> pendingRegions;
+ QMap<FileLocationRegion, CommentedElement> pendingComments;
};
class QMLDOM_EXPORT OutWriter
@@ -92,21 +86,14 @@ public:
return indent;
}
- void itemStart(DomItem &it);
- void itemEnd(DomItem &it);
- void regionStart(QString rName);
- void regionStart(QStringView rName) { regionStart(rName.toString()); }
- void regionEnd(QString rName);
- void regionEnd(QStringView rName) { regionEnd(rName.toString()); }
+ void itemStart(const DomItem &it);
+ void itemEnd(const DomItem &it);
+ void regionStart(FileLocationRegion region);
+ void regionEnd(FileLocationRegion regino);
quint32 counter() const { return lineWriter.counter(); }
- OutWriter &writeRegion(QString rName, QStringView toWrite);
- OutWriter &writeRegion(QStringView rName, QStringView toWrite)
- {
- return writeRegion(rName.toString(), toWrite);
- }
- OutWriter &writeRegion(QString t) { return writeRegion(t, t); }
- OutWriter &writeRegion(QStringView t) { return writeRegion(t.toString(), t); }
+ OutWriter &writeRegion(FileLocationRegion region, QStringView toWrite);
+ OutWriter &writeRegion(FileLocationRegion region);
OutWriter &ensureNewline(int nNewlines = 1)
{
lineWriter.ensureNewline(nNewlines);
@@ -153,14 +140,21 @@ public:
return lineWriter.addTextAddCallback(callback);
}
bool removeTextAddCallback(int i) { return lineWriter.removeTextAddCallback(i); }
- void addReformattedScriptExpression(Path p, std::shared_ptr<ScriptExpression> exp)
+ void addReformattedScriptExpression(const Path &p, const std::shared_ptr<ScriptExpression> &exp)
{
if (auto updExp = UpdatedScriptExpression::ensure(reformattedScriptExpressions, p,
AttachedInfo::PathType::Canonical)) {
updExp->info().expr = exp;
}
}
- DomItem updatedFile(DomItem &qmlFile);
+ DomItem restoreWrittenFileItem(const DomItem &fileItem);
+
+private:
+ DomItem writtenQmlFileItem(const DomItem &fileItem, const Path &filePath);
+ DomItem writtenJsFileItem(const DomItem &fileItem, const Path &filePath);
+ static void logScriptExprUpdateSkipped(
+ const DomItem &exprItem, const Path &exprPath,
+ const std::shared_ptr<ScriptExpression> &formattedExpr);
};
} // end namespace Dom
diff --git a/src/qmldom/qqmldompath.cpp b/src/qmldom/qqmldompath.cpp
index 24eb9768eb..d2b4582bc0 100644
--- a/src/qmldom/qqmldompath.cpp
+++ b/src/qmldom/qqmldompath.cpp
@@ -74,15 +74,16 @@ The current contexts are:
\endlist
*/
-void Base::dump(Sink sink) const {
- if (hasSquareBrackets())
+void Base::dump(const Sink &sink, const QString &name, bool hasSquareBrackets) const {
+ if (hasSquareBrackets)
sink(u"[");
- sink(name());
- if (hasSquareBrackets())
+ sink(name);
+ if (hasSquareBrackets)
sink(u"]");
}
-Filter::Filter(function<bool(DomItem)> f, QStringView filterDescription): filterFunction(f), filterDescription(filterDescription) {}
+Filter::Filter(const function<bool(const DomItem &)> &f, QStringView filterDescription)
+ : filterFunction(f), filterDescription(filterDescription) {}
QString Filter::name() const {
return QLatin1String("?(%1)").arg(filterDescription); }
@@ -100,9 +101,6 @@ enum class ParserState{
End
};
-PathComponent::~PathComponent(){
-}
-
int PathComponent::cmp(const PathComponent &p1, const PathComponent &p2)
{
int k1 = static_cast<int>(p1.kind());
@@ -115,19 +113,19 @@ int PathComponent::cmp(const PathComponent &p1, const PathComponent &p2)
case Kind::Empty:
return 0;
case Kind::Field:
- return p1.data.field.fieldName.compare(p2.data.field.fieldName);
+ return std::get<Field>(p1.m_data).fieldName.compare(std::get<Field>(p2.m_data).fieldName);
case Kind::Index:
- if (p1.data.index.indexValue < p2.data.index.indexValue)
+ if (std::get<Index>(p1.m_data).indexValue < std::get<Index>(p2.m_data).indexValue)
return -1;
- if (p1.data.index.indexValue > p2.data.index.indexValue)
+ if (std::get<Index>(p1.m_data).indexValue > std::get<Index>(p2.m_data).indexValue)
return 1;
return 0;
case Kind::Key:
- return p1.data.key.keyValue.compare(p2.data.key.keyValue);
+ return std::get<Key>(p1.m_data).keyValue.compare(std::get<Key>(p2.m_data).keyValue);
case Kind::Root:
{
- PathRoot k1 = p1.data.root.contextKind;
- PathRoot k2 = p2.data.root.contextKind;
+ PathRoot k1 = std::get<Root>(p1.m_data).contextKind;
+ PathRoot k2 = std::get<Root>(p2.m_data).contextKind;
if (k1 == PathRoot::Env || k1 == PathRoot::Universe)
k1 = PathRoot::Top;
if (k2 == PathRoot::Env || k2 == PathRoot::Universe)
@@ -135,23 +133,26 @@ int PathComponent::cmp(const PathComponent &p1, const PathComponent &p2)
int c = int(k1) - int(k2);
if (c != 0)
return c;
- return p1.data.root.contextName.compare(p2.data.root.contextName);
+ return std::get<Root>(p1.m_data).contextName.compare(std::get<Root>(p2.m_data).contextName);
}
case Kind::Current:
{
- int c = int(p1.data.current.contextKind) - int(p2.data.current.contextKind);
+ int c = int(std::get<Current>(p1.m_data).contextKind)
+ - int(std::get<Current>(p2.m_data).contextKind);
if (c != 0)
return c;
- return p1.data.current.contextName.compare(p2.data.current.contextName);
+ return std::get<Current>(p1.m_data).contextName
+ .compare(std::get<Current>(p2.m_data).contextName);
}
case Kind::Any:
return 0;
case Kind::Filter:
{
- int c = p1.data.filter.filterDescription.compare(p2.data.filter.filterDescription);
+ int c = std::get<Filter>(p1.m_data).filterDescription
+ .compare(std::get<Filter>(p2.m_data).filterDescription);
if (c != 0)
return c;
- if (p1.data.filter.filterDescription.startsWith(u"<")) {
+ if (std::get<Filter>(p1.m_data).filterDescription.startsWith(u"<")) {
// assuming non comparable native code (target comparison is not portable)
auto pp1 = &p1;
auto pp2 = &p2;
@@ -213,7 +214,7 @@ PathIterator Path::end() const
PathRoot Path::headRoot() const
{
auto &comp = component(0);
- if (PathEls::Root const * r = comp.base()->asRoot())
+ if (PathEls::Root const * r = comp.asRoot())
return r->contextKind;
return PathRoot::Other;
}
@@ -221,7 +222,7 @@ PathRoot Path::headRoot() const
PathCurrent Path::headCurrent() const
{
auto comp = component(0);
- if (PathEls::Current const * c = comp.base()->asCurrent())
+ if (PathEls::Current const * c = comp.asCurrent())
return c->contextKind;
return PathCurrent::Other;
}
@@ -248,10 +249,10 @@ index_type Path::headIndex(index_type defaultValue) const
return component(0).index(defaultValue);
}
-function<bool (DomItem)> Path::headFilter() const
+function<bool(const DomItem &)> Path::headFilter() const
{
auto &comp = component(0);
- if (PathEls::Filter const * f = comp.base()->asFilter()) {
+ if (PathEls::Filter const * f = comp.asFilter()) {
return f->filterFunction;
}
return {};
@@ -279,7 +280,7 @@ Source Path::split() const
return Source{Path(), *this};
}
-bool inQString(QStringView el, QString base)
+bool inQString(QStringView el, const QString &base)
{
if (quintptr(base.constData()) > quintptr(el.begin())
|| quintptr(base.constData() + base.size()) < quintptr(el.begin()))
@@ -288,7 +289,7 @@ bool inQString(QStringView el, QString base)
return diff >= 0 && diff < base.size();
}
-bool inQString(QString el, QString base)
+bool inQString(const QString &el, const QString &base)
{
if (quintptr(base.constData()) > quintptr(el.constData())
|| quintptr(base.constData() + base.size()) < quintptr(el.constData()))
@@ -297,7 +298,7 @@ bool inQString(QString el, QString base)
return diff >= 0 && diff < base.size() && diff + el.size() < base.size();
}
-Path Path::fromString(QStringView s, ErrorHandler errorHandler)
+Path Path::fromString(QStringView s, const ErrorHandler &errorHandler)
{
if (s.isEmpty())
return Path();
@@ -525,7 +526,7 @@ Path Path::Root(PathRoot s)
QStringList(), QVector<Component>(1,Component(PathEls::Root(s)))));
}
-Path Path::Root(QString s)
+Path Path::Root(const QString &s)
{
return Path(0,1,std::make_shared<PathEls::PathData>(
QStringList(s), QVector<Component>(1,Component(PathEls::Root(s)))));
@@ -550,7 +551,7 @@ Path Path::Field(QStringView s)
QStringList(), QVector<Component>(1,Component(PathEls::Field(s)))));
}
-Path Path::Field(QString s)
+Path Path::Field(const QString &s)
{
return Path(0,1,std::make_shared<PathEls::PathData>(
QStringList(s), QVector<Component>(1,Component(PathEls::Field(s)))));
@@ -564,7 +565,7 @@ Path Path::Key(QStringView s)
QStringList(), QVector<Component>(1, Component(PathEls::Key(s.toString())))));
}
-Path Path::Key(QString s)
+Path Path::Key(const QString &s)
{
return Path(0, 1,
std::make_shared<PathEls::PathData>(
@@ -577,7 +578,7 @@ Path Path::Current(PathCurrent s)
QStringList(), QVector<Component>(1,Component(PathEls::Current(s)))));
}
-Path Path::Current(QString s)
+Path Path::Current(const QString &s)
{
return Path(0,1,std::make_shared<PathEls::PathData>(
QStringList(s), QVector<Component>(1,Component(PathEls::Current(s)))));
@@ -602,7 +603,7 @@ Path Path::empty() const
QStringList(), QVector<Component>(1,Component()), m_data));
}
-Path Path::field(QString name) const
+Path Path::field(const QString &name) const
{
auto res = field(QStringView(name));
res.m_data->strData.append(name);
@@ -617,7 +618,7 @@ Path Path::field(QStringView name) const
QStringList(), QVector<Component>(1,Component(PathEls::Field(name))), m_data));
}
-Path Path::key(QString name) const
+Path Path::key(const QString &name) const
{
if (m_endOffset != 0)
return noEndOffset().key(name);
@@ -646,14 +647,14 @@ Path Path::any() const
QStringList(), QVector<Component>(1,Component(PathEls::Any())), m_data));
}
-Path Path::filter(function<bool (DomItem)> filterF, QString desc) const
+Path Path::filter(const function<bool(const DomItem &)> &filterF, const QString &desc) const
{
auto res = filter(filterF, QStringView(desc));
res.m_data->strData.append(desc);
return res;
}
-Path Path::filter(function<bool (DomItem)> filter, QStringView desc) const
+Path Path::filter(const function<bool(const DomItem &)> &filter, QStringView desc) const
{
if (m_endOffset != 0)
return noEndOffset().filter(filter, desc);
@@ -667,7 +668,7 @@ Path Path::current(PathCurrent s) const
QStringList(), QVector<Component>(1,Component(PathEls::Current(s))), m_data));
}
-Path Path::current(QString s) const
+Path Path::current(const QString &s) const
{
auto res = current(QStringView(s));
res.m_data->strData.append(s);
@@ -682,7 +683,7 @@ Path Path::current(QStringView s) const
QStringList(), QVector<Component>(1,Component(PathEls::Current(s))), m_data));
}
-Path Path::path(Path toAdd, bool avoidToAddAsBase) const
+Path Path::path(const Path &toAdd, bool avoidToAddAsBase) const
{
if (toAdd.length() == 0)
return *this;
@@ -808,7 +809,7 @@ int Path::cmp(const Path &p1, const Path &p2)
return 0;
}
-Path::Path(quint16 endOffset, quint16 length, std::shared_ptr<PathEls::PathData> data)
+Path::Path(quint16 endOffset, quint16 length, const std::shared_ptr<PathEls::PathData> &data)
:m_endOffset(endOffset), m_length(length), m_data(data)
{
}
@@ -869,10 +870,10 @@ Path Path::appendComponent(const PathEls::PathComponent &c)
}
break;
case PathEls::Kind::Filter:
- if (!c.base()->asFilter()->filterDescription.isEmpty()) {
- my_data->strData.append(c.base()->asFilter()->filterDescription.toString());
+ if (!c.asFilter()->filterDescription.isEmpty()) {
+ my_data->strData.append(c.asFilter()->filterDescription.toString());
my_data->components.append(
- PathEls::Filter(c.base()->asFilter()->filterFunction, my_data->strData.last()));
+ PathEls::Filter(c.asFilter()->filterFunction, my_data->strData.last()));
} else {
my_data->components.append(c);
}
@@ -900,7 +901,7 @@ ErrorGroups Path::myErrors()
return res;
}
-void Path::dump(Sink sink) const
+void Path::dump(const Sink &sink) const
{
bool first = true;
for (int i = 0; i < m_length; ++i) {
@@ -951,7 +952,7 @@ Path Path::mid(int offset) const
return mid(offset, m_length - offset);
}
-Path Path::fromString(QString s, ErrorHandler errorHandler)
+Path Path::fromString(const QString &s, const ErrorHandler &errorHandler)
{
Path res = fromString(QStringView(s), errorHandler);
if (res.m_data)
diff --git a/src/qmldom/qqmldompath_p.h b/src/qmldom/qqmldompath_p.h
index 859e23d1b0..1a5af85e8e 100644
--- a/src/qmldom/qqmldompath_p.h
+++ b/src/qmldom/qqmldompath_p.h
@@ -69,35 +69,21 @@ class Filter;
class Base {
public:
- virtual ~Base() = default;
- virtual Kind kind() const = 0;
- virtual QString name() const = 0;
- virtual bool checkName(QStringView s) const = 0;
- virtual QStringView stringView() const { return QStringView(); }
- virtual index_type index(index_type defaultValue=-1) const { return defaultValue; }
-
- virtual void dump(Sink sink) const;
- virtual bool hasSquareBrackets() const { return false; }
-
- // casting, could use optional, but that is c++17...
- virtual const Empty *asEmpty() const { return nullptr; }
- virtual const Field *asField() const { return nullptr; }
- virtual const Index *asIndex() const { return nullptr; }
- virtual const Key *asKey() const { return nullptr; }
- virtual const Root *asRoot() const { return nullptr; }
- virtual const Current *asCurrent() const { return nullptr; }
- virtual const Any *asAny() const { return nullptr; }
- virtual const Filter *asFilter() const { return nullptr; }
+ QStringView stringView() const { return QStringView(); }
+ index_type index(index_type defaultValue = -1) const { return defaultValue; }
+ bool hasSquareBrackets() const { return false; }
+
+protected:
+ void dump(const Sink &sink, const QString &name, bool hasSquareBrackets) const;
};
class Empty final : public Base
{
public:
Empty() = default;
- Kind kind() const override { return Kind::Empty; }
- QString name() const override { return QString(); }
- bool checkName(QStringView s) const override { return s.isEmpty(); }
- const Empty * asEmpty() const override { return this; }
+ QString name() const { return QString(); }
+ bool checkName(QStringView s) const { return s.isEmpty(); }
+ void dump(const Sink &sink) const { Base::dump(sink, name(), hasSquareBrackets()); }
};
class Field final : public Base
@@ -105,12 +91,10 @@ class Field final : public Base
public:
Field() = default;
Field(QStringView n): fieldName(n) {}
- Kind kind() const override { return Kind::Field; }
- QString name() const override { return fieldName.toString(); }
- bool checkName(QStringView s) const override { return s == fieldName; }
- QStringView stringView() const override { return fieldName; }
- const Field * asField() const override { return this; }
- void dump(Sink sink) const override { sink(fieldName); }
+ QString name() const { return fieldName.toString(); }
+ bool checkName(QStringView s) const { return s == fieldName; }
+ QStringView stringView() const { return fieldName; }
+ void dump(const Sink &sink) const { sink(fieldName); }
QStringView fieldName;
};
@@ -120,12 +104,11 @@ class Index final : public Base
public:
Index() = default;
Index(index_type i): indexValue(i) {}
- Kind kind() const override { return Kind::Index; }
- QString name() const override { return QString::number(indexValue); }
- bool checkName(QStringView s) const override { return s == name(); }
- index_type index(index_type = -1) const override { return indexValue; }
- bool hasSquareBrackets() const override { return true; }
- const Index * asIndex() const override { return this; }
+ QString name() const { return QString::number(indexValue); }
+ bool checkName(QStringView s) const { return s == name(); }
+ index_type index(index_type = -1) const { return indexValue; }
+ void dump(const Sink &sink) const { Base::dump(sink, name(), hasSquareBrackets()); }
+ bool hasSquareBrackets() const { return true; }
index_type indexValue = -1;
};
@@ -134,18 +117,16 @@ class Key final : public Base
{
public:
Key() = default;
- Key(QString n) : keyValue(n) { }
- Kind kind() const override { return Kind::Key; }
- QString name() const override { return keyValue; }
- bool checkName(QStringView s) const override { return s == keyValue; }
- QStringView stringView() const override { return keyValue; }
- void dump(Sink sink) const override {
+ Key(const QString &n) : keyValue(n) { }
+ QString name() const { return keyValue; }
+ bool checkName(QStringView s) const { return s == keyValue; }
+ QStringView stringView() const { return keyValue; }
+ void dump(const Sink &sink) const {
sink(u"[");
sinkEscaped(sink, keyValue);
sink(u"]");
}
- bool hasSquareBrackets() const override { return true; }
- const Key * asKey() const override { return this; }
+ bool hasSquareBrackets() const { return true; }
QString keyValue;
};
@@ -164,8 +145,7 @@ public:
if (contextKind == PathRoot::Other)
contextName = n;
}
- Kind kind() const override { return Kind::Root; }
- QString name() const override {
+ QString name() const {
switch (contextKind) {
case PathRoot::Modules:
return QStringLiteral(u"$modules");
@@ -185,16 +165,13 @@ public:
Q_ASSERT(false && "Unexpected contextKind in name");
return QString();
}
- bool checkName(QStringView s) const override {
+ bool checkName(QStringView s) const {
if (contextKind != PathRoot::Other)
return s.compare(name(), Qt::CaseInsensitive) == 0;
return s.startsWith(QChar::fromLatin1('$')) && s.mid(1) == contextName;
}
- QStringView stringView() const override { return contextName; }
- void dump(Sink sink) const override {
- sink(name());
- }
- const Root *asRoot() const override { return this; }
+ QStringView stringView() const { return contextName; }
+ void dump(const Sink &sink) const { sink(name()); }
PathRoot contextKind = PathRoot::Other;
QStringView contextName;
@@ -214,8 +191,7 @@ public:
if (contextKind == PathCurrent::Other)
contextName = n;
}
- Kind kind() const override { return Kind::Current; }
- QString name() const override {
+ QString name() const {
switch (contextKind) {
case PathCurrent::Other:
return QString::fromUtf8("@").append(contextName.toString());
@@ -243,13 +219,13 @@ public:
Q_ASSERT(false && "Unexpected contextKind in Current::name");
return QString();
}
- bool checkName(QStringView s) const override {
+ bool checkName(QStringView s) const {
if (contextKind != PathCurrent::Other)
return s.compare(name(), Qt::CaseInsensitive) == 0;
return s.startsWith(QChar::fromLatin1('@')) && s.mid(1) == contextName;
}
- QStringView stringView() const override { return contextName; }
- const Current *asCurrent() const override { return this; }
+ QStringView stringView() const { return contextName; }
+ void dump(const Sink &sink) const { Base::dump(sink, name(), hasSquareBrackets()); }
PathCurrent contextKind = PathCurrent::Other;
QStringView contextName;
@@ -259,160 +235,110 @@ class Any final : public Base
{
public:
Any() = default;
- Kind kind() const override { return Kind::Any; }
- QString name() const override { return QLatin1String("*"); }
- bool checkName(QStringView s) const override { return s == u"*"; }
- bool hasSquareBrackets() const override { return true; }
- const Any *asAny() const override { return this; }
+ QString name() const { return QLatin1String("*"); }
+ bool checkName(QStringView s) const { return s == u"*"; }
+ void dump(const Sink &sink) const { Base::dump(sink, name(), hasSquareBrackets()); }
+ bool hasSquareBrackets() const { return true; }
};
class QMLDOM_EXPORT Filter final : public Base
{
public:
Filter() = default;
- Filter(std::function<bool(DomItem)> f, QStringView filterDescription = u"<native code filter>");
- Kind kind() const override { return Kind::Filter; }
- QString name() const override;
- bool checkName(QStringView s) const override;
- QStringView stringView() const override { return filterDescription; }
- bool hasSquareBrackets() const override { return true; }
- const Filter *asFilter() const override { return this; }
-
- std::function<bool(DomItem)> filterFunction;
+ Filter(const std::function<bool(const DomItem &)> &f,
+ QStringView filterDescription = u"<native code filter>");
+ QString name() const;
+ bool checkName(QStringView s) const;
+ QStringView stringView() const { return filterDescription; }
+ void dump(const Sink &sink) const { Base::dump(sink, name(), hasSquareBrackets()); }
+ bool hasSquareBrackets() const { return true; }
+
+ std::function<bool(const DomItem &)> filterFunction;
QStringView filterDescription;
};
class QMLDOM_EXPORT PathComponent {
public:
- PathComponent(): data() {}
- ~PathComponent();
-
- Kind kind() const { return base()->kind(); }
- QString name() const { return base()->name(); };
- bool checkName(QStringView s) const { return base()->checkName(s); }
- QStringView stringView() const { return base()->stringView(); };
- index_type index(index_type defaultValue=-1) const { return base()->index(defaultValue); }
- void dump(Sink sink) const { base()->dump(sink); }
- bool hasSquareBrackets() const { return base()->hasSquareBrackets(); }
-
- const Empty *asEmpty() const { return base()->asEmpty(); }
- const Field *asField() const { return base()->asField(); }
- const Index *asIndex() const { return base()->asIndex(); }
- const Key *asKey() const { return base()->asKey(); }
- const Root *asRoot() const { return base()->asRoot(); }
- const Current *asCurrent() const { return base()->asCurrent(); }
- const Any *asAny() const { return base()->asAny(); }
+ PathComponent() = default;
+ PathComponent(const PathComponent &) = default;
+ PathComponent(PathComponent &&) = default;
+ PathComponent &operator=(const PathComponent &) = default;
+ PathComponent &operator=(PathComponent &&) = default;
+ ~PathComponent() = default;
+
+ Kind kind() const { return Kind(m_data.index()); }
+
+ QString name() const
+ {
+ return std::visit([](auto &&d) { return d.name(); }, m_data);
+ }
+
+ bool checkName(QStringView s) const
+ {
+ return std::visit([s](auto &&d) { return d.checkName(s); }, m_data);
+ }
+
+ QStringView stringView() const
+ {
+ return std::visit([](auto &&d) { return d.stringView(); }, m_data);
+ }
+
+ index_type index(index_type defaultValue=-1) const
+ {
+ return std::visit([defaultValue](auto &&d) { return d.index(defaultValue); }, m_data);
+ }
+
+ void dump(const Sink &sink) const
+ {
+ return std::visit([sink](auto &&d) { return d.dump(sink); }, m_data);
+ }
+
+ bool hasSquareBrackets() const
+ {
+ return std::visit([](auto &&d) { return d.hasSquareBrackets(); }, m_data);
+ }
+
+ const Empty *asEmpty() const { return std::get_if<Empty>(&m_data); }
+ const Field *asField() const { return std::get_if<Field>(&m_data); }
+ const Index *asIndex() const { return std::get_if<Index>(&m_data); }
+ const Key *asKey() const { return std::get_if<Key>(&m_data); }
+ const Root *asRoot() const { return std::get_if<Root>(&m_data); }
+ const Current *asCurrent() const { return std::get_if<Current>(&m_data); }
+ const Any *asAny() const { return std::get_if<Any>(&m_data); }
+ const Filter *asFilter() const { return std::get_if<Filter>(&m_data); }
+
static int cmp(const PathComponent &p1, const PathComponent &p2);
- PathComponent(const Empty &o): data(o) {}
- PathComponent(const Field &o): data(o) {}
- PathComponent(const Index &o): data(o) {}
- PathComponent(const Key &o): data(o) {}
- PathComponent(const Root &o): data(o) {}
- PathComponent(const Current &o): data(o) {}
- PathComponent(const Any &o): data(o) {}
- PathComponent(const Filter &o): data(o) {}
+ PathComponent(Empty &&o): m_data(std::move(o)) {}
+ PathComponent(Field &&o): m_data(std::move(o)) {}
+ PathComponent(Index &&o): m_data(std::move(o)) {}
+ PathComponent(Key &&o): m_data(std::move(o)) {}
+ PathComponent(Root &&o): m_data(std::move(o)) {}
+ PathComponent(Current &&o): m_data(std::move(o)) {}
+ PathComponent(Any &&o): m_data(std::move(o)) {}
+ PathComponent(Filter &&o): m_data(std::move(o)) {}
+
private:
friend class QQmlJS::Dom::Path;
friend class QQmlJS::Dom::PathEls::TestPaths;
- Base *base() {
- return reinterpret_cast<Base*>(&data);
- }
- const Base *base() const {
- return reinterpret_cast<const Base*>(&data);
- }
- union Data {
- Data(): empty() { }
- Data(const Data &d) {
- switch (d.kind()){
- case Kind::Empty:
- Q_ASSERT(static_cast<void*>(this)==static_cast<void*>(&empty) && "non C++11 compliant compiler");
- new (&empty) Empty(d.empty);
- break;
- case Kind::Field:
- Q_ASSERT(static_cast<void*>(this)==static_cast<void*>(&field) && "non C++11 compliant compiler");
- new (&field) Field(d.field);
- break;
- case Kind::Index:
- Q_ASSERT(static_cast<void*>(this)==static_cast<void*>(&index) && "non C++11 compliant compiler");
- new (&index) Index(d.index);
- break;
- case Kind::Key:
- Q_ASSERT(static_cast<void*>(this)==static_cast<void*>(&key) && "non C++11 compliant compiler");
- new (&key) Key(d.key);
- break;
- case Kind::Root:
- Q_ASSERT(static_cast<void*>(this)==static_cast<void*>(&root) && "non C++11 compliant compiler");
- new (&root) Root(d.root);
- break;
- case Kind::Current:
- Q_ASSERT(static_cast<void*>(this)==static_cast<void*>(&current) && "non C++11 compliant compiler");
- new (&current) Current(d.current);
- break;
- case Kind::Any:
- Q_ASSERT(static_cast<void*>(this)==static_cast<void*>(&any) && "non C++11 compliant compiler");
- new (&any) Any(d.any);
- break;
- case Kind::Filter:
- Q_ASSERT(static_cast<void*>(this)==static_cast<void*>(&filter) && "non C++11 compliant compiler");
- new (&filter) Filter(d.filter);
- break;
- }
- }
- Data(const Empty &o) {
- Q_ASSERT(static_cast<void*>(this)==static_cast<void*>(&empty) && "non C++11 compliant compiler");
- new (&empty) Empty(o);
- }
- Data(const Field &o) {
- Q_ASSERT(static_cast<void*>(this)==static_cast<void*>(&field) && "non C++11 compliant compiler");
- new (&field) Field(o);
- }
- Data(const Index &o){
- Q_ASSERT(static_cast<void*>(this)==static_cast<void*>(&index) && "non C++11 compliant compiler");
- new (&index) Index(o);
- }
- Data(const Key &o) {
- Q_ASSERT(static_cast<void*>(this)==static_cast<void*>(&key) && "non C++11 compliant compiler");
- new (&key) Key(o);
- }
- Data(const Root &o) {
- Q_ASSERT(static_cast<void*>(this)==static_cast<void*>(&root) && "non C++11 compliant compiler");
- new (&root) Root(o);
- }
- Data(const Current &o) {
- Q_ASSERT(static_cast<void*>(this)==static_cast<void*>(&current) && "non C++11 compliant compiler");
- new (&current) Current(o);
- }
- Data(const Any &o) {
- Q_ASSERT(static_cast<void*>(this)==static_cast<void*>(&any) && "non C++11 compliant compiler");
- new (&any) Any(o);
- }
- Data(const Filter &o) {
- Q_ASSERT(static_cast<void*>(this)==static_cast<void*>(&filter) && "non C++11 compliant compiler");
- new (&filter) Filter(o);
- }
- Data &operator=(const Data &d) {
- Q_ASSERT(this != &d);
- this->~Data(); // destruct & construct new...
- new (this)Data(d);
- return *this;
- }
- Kind kind() const {
- return reinterpret_cast<const Base*>(this)->kind();
- }
- ~Data() {
- reinterpret_cast<const Base*>(this)->~Base();
- }
- Empty empty;
- Field field;
- Index index;
- Key key;
- Root root;
- Current current;
- Any any;
- Filter filter;
- } data;
+ using Variant = std::variant<Empty, Field, Index, Key, Root, Current, Any, Filter>;
+
+ template<typename T, Kind K>
+ static constexpr bool variantTypeMatches
+ = std::is_same_v<std::variant_alternative_t<size_t(K), Variant>, T>;
+
+ static_assert(size_t(Kind::Empty) == 0);
+ static_assert(variantTypeMatches<Empty, Kind::Empty>);
+ static_assert(variantTypeMatches<Field, Kind::Field>);
+ static_assert(variantTypeMatches<Key, Kind::Key>);
+ static_assert(variantTypeMatches<Root, Kind::Root>);
+ static_assert(variantTypeMatches<Current, Kind::Current>);
+ static_assert(variantTypeMatches<Any, Kind::Any>);
+ static_assert(variantTypeMatches<Filter, Kind::Filter>);
+ static_assert(std::variant_size_v<Variant> == size_t(Kind::Filter) + 1);
+
+ Variant m_data;
};
inline bool operator==(const PathComponent& lhs, const PathComponent& rhs){ return PathComponent::cmp(lhs,rhs) == 0; }
@@ -424,9 +350,13 @@ inline bool operator>=(const PathComponent& lhs, const PathComponent& rhs){ retu
class PathData {
public:
- PathData(QStringList strData, QVector<PathComponent> components): strData(strData), components(components) {}
- PathData(QStringList strData, QVector<PathComponent> components, std::shared_ptr<PathData> parent):
- strData(strData), components(components), parent(parent) {}
+ PathData(const QStringList &strData, const QVector<PathComponent> &components)
+ : strData(strData), components(components)
+ {}
+ PathData(const QStringList &strData, const QVector<PathComponent> &components,
+ const std::shared_ptr<PathData> &parent)
+ : strData(strData), components(components), parent(parent)
+ {}
QStringList strData;
QVector<PathComponent> components;
@@ -437,30 +367,51 @@ public:
#define QMLDOM_USTRING(s) u##s
#define QMLDOM_FIELD(name) inline constexpr const auto name = QMLDOM_USTRING(#name)
+/*!
+ \internal
+ In an ideal world, the Fields namespace would be an enum, not strings.
+ Use FieldType whenever you expect a static String from the Fields namespace instead of an
+ arbitrary QStringView.
+ */
+using FieldType = QStringView;
// namespace, so it cam be reopened to add more entries
namespace Fields{
QMLDOM_FIELD(access);
QMLDOM_FIELD(accessSemantics);
QMLDOM_FIELD(allSources);
+QMLDOM_FIELD(alternative);
QMLDOM_FIELD(annotations);
+QMLDOM_FIELD(arguments);
QMLDOM_FIELD(astComments);
QMLDOM_FIELD(astRelocatableDump);
QMLDOM_FIELD(attachedType);
QMLDOM_FIELD(attachedTypeName);
QMLDOM_FIELD(autoExports);
QMLDOM_FIELD(base);
+QMLDOM_FIELD(binaryExpression);
QMLDOM_FIELD(bindable);
+QMLDOM_FIELD(bindingElement);
+QMLDOM_FIELD(bindingIdentifiers);
QMLDOM_FIELD(bindingType);
QMLDOM_FIELD(bindings);
+QMLDOM_FIELD(block);
QMLDOM_FIELD(body);
+QMLDOM_FIELD(callee);
QMLDOM_FIELD(canonicalFilePath);
QMLDOM_FIELD(canonicalPath);
+QMLDOM_FIELD(caseBlock);
+QMLDOM_FIELD(caseClause);
+QMLDOM_FIELD(caseClauses);
+QMLDOM_FIELD(catchBlock);
+QMLDOM_FIELD(catchParameter);
QMLDOM_FIELD(children);
QMLDOM_FIELD(classNames);
QMLDOM_FIELD(code);
QMLDOM_FIELD(commentedElements);
QMLDOM_FIELD(comments);
QMLDOM_FIELD(components);
+QMLDOM_FIELD(condition);
+QMLDOM_FIELD(consequence);
QMLDOM_FIELD(contents);
QMLDOM_FIELD(contentsDate);
QMLDOM_FIELD(cppType);
@@ -468,20 +419,26 @@ QMLDOM_FIELD(currentExposedAt);
QMLDOM_FIELD(currentIsValid);
QMLDOM_FIELD(currentItem);
QMLDOM_FIELD(currentRevision);
+QMLDOM_FIELD(declarations);
+QMLDOM_FIELD(defaultClause);
QMLDOM_FIELD(defaultPropertyName);
QMLDOM_FIELD(defaultValue);
QMLDOM_FIELD(designerSupported);
QMLDOM_FIELD(elLocation);
+QMLDOM_FIELD(elements);
QMLDOM_FIELD(elementCanonicalPath);
QMLDOM_FIELD(enumerations);
QMLDOM_FIELD(errors);
QMLDOM_FIELD(exportSource);
QMLDOM_FIELD(exports);
QMLDOM_FIELD(expr);
+QMLDOM_FIELD(expression);
QMLDOM_FIELD(expressionType);
QMLDOM_FIELD(extensionTypeName);
QMLDOM_FIELD(fileLocationsTree);
QMLDOM_FIELD(fileName);
+QMLDOM_FIELD(finallyBlock);
+QMLDOM_FIELD(forStatement);
QMLDOM_FIELD(fullRegion);
QMLDOM_FIELD(get);
QMLDOM_FIELD(globalScopeName);
@@ -489,6 +446,7 @@ QMLDOM_FIELD(globalScopeWithName);
QMLDOM_FIELD(hasCallback);
QMLDOM_FIELD(hasCustomParser);
QMLDOM_FIELD(idStr);
+QMLDOM_FIELD(identifier);
QMLDOM_FIELD(ids);
QMLDOM_FIELD(implicit);
QMLDOM_FIELD(import);
@@ -500,6 +458,7 @@ QMLDOM_FIELD(imports);
QMLDOM_FIELD(inProgress);
QMLDOM_FIELD(infoItem);
QMLDOM_FIELD(inheritVersion);
+QMLDOM_FIELD(initializer);
QMLDOM_FIELD(interfaceNames);
QMLDOM_FIELD(isAlias);
QMLDOM_FIELD(isComposite);
@@ -519,7 +478,9 @@ QMLDOM_FIELD(isValid);
QMLDOM_FIELD(jsFileWithPath);
QMLDOM_FIELD(kind);
QMLDOM_FIELD(lastRevision);
+QMLDOM_FIELD(label);
QMLDOM_FIELD(lastValidRevision);
+QMLDOM_FIELD(left);
QMLDOM_FIELD(loadInfo);
QMLDOM_FIELD(loadOptions);
QMLDOM_FIELD(loadPaths);
@@ -535,17 +496,20 @@ QMLDOM_FIELD(minorVersion);
QMLDOM_FIELD(moduleIndex);
QMLDOM_FIELD(moduleIndexWithUri);
QMLDOM_FIELD(moduleScope);
+QMLDOM_FIELD(moreCaseClauses);
QMLDOM_FIELD(nAllLoadedCallbacks);
QMLDOM_FIELD(nCallbacks);
QMLDOM_FIELD(nLoaded);
QMLDOM_FIELD(nNotdone);
QMLDOM_FIELD(name);
+QMLDOM_FIELD(nameIdentifiers);
QMLDOM_FIELD(newlinesBefore);
QMLDOM_FIELD(nextComponent);
QMLDOM_FIELD(nextScope);
QMLDOM_FIELD(notify);
QMLDOM_FIELD(objects);
QMLDOM_FIELD(onAttachedObject);
+QMLDOM_FIELD(operation);
QMLDOM_FIELD(options);
QMLDOM_FIELD(parameters);
QMLDOM_FIELD(parent);
@@ -560,6 +524,7 @@ QMLDOM_FIELD(pragmas);
QMLDOM_FIELD(preCode);
QMLDOM_FIELD(preCommentLocations);
QMLDOM_FIELD(preComments);
+QMLDOM_FIELD(properties);
QMLDOM_FIELD(propertyDef);
QMLDOM_FIELD(propertyDefRef);
QMLDOM_FIELD(propertyDefs);
@@ -574,7 +539,6 @@ QMLDOM_FIELD(qmldirWithPath);
QMLDOM_FIELD(qmltypesFileWithPath);
QMLDOM_FIELD(qmltypesFiles);
QMLDOM_FIELD(qualifiedImports);
-QMLDOM_FIELD(queue);
QMLDOM_FIELD(rawComment);
QMLDOM_FIELD(read);
QMLDOM_FIELD(referredObject);
@@ -585,8 +549,13 @@ QMLDOM_FIELD(requestedAt);
QMLDOM_FIELD(requestingUniverse);
QMLDOM_FIELD(returnType);
QMLDOM_FIELD(returnTypeName);
+QMLDOM_FIELD(right);
QMLDOM_FIELD(rootComponent);
+QMLDOM_FIELD(scopeType);
+QMLDOM_FIELD(scriptElement);
QMLDOM_FIELD(sources);
+QMLDOM_FIELD(statement);
+QMLDOM_FIELD(statements);
QMLDOM_FIELD(status);
QMLDOM_FIELD(stringValue);
QMLDOM_FIELD(subComponents);
@@ -598,6 +567,8 @@ QMLDOM_FIELD(target);
QMLDOM_FIELD(targetPropertyName);
QMLDOM_FIELD(text);
QMLDOM_FIELD(type);
+QMLDOM_FIELD(typeArgument);
+QMLDOM_FIELD(typeArgumentName);
QMLDOM_FIELD(typeName);
QMLDOM_FIELD(types);
QMLDOM_FIELD(universe);
@@ -612,7 +583,7 @@ QMLDOM_FIELD(values);
QMLDOM_FIELD(version);
QMLDOM_FIELD(when);
QMLDOM_FIELD(write);
-}
+} // namespace Fields
class Source;
size_t qHash(const Path &, size_t);
@@ -646,12 +617,12 @@ public:
QString headName() const;
bool checkHeadName(QStringView name) const;
index_type headIndex(index_type defaultValue=-1) const;
- std::function<bool(DomItem)> headFilter() const;
+ std::function<bool(const DomItem &)> headFilter() const;
Path head() const;
Path last() const;
Source split() const;
- void dump(Sink sink) const;
+ void dump(const Sink &sink) const;
QString toString() const;
Path dropFront(int n = 1) const;
Path dropTail(int n = 1) const;
@@ -660,34 +631,35 @@ public:
Path appendComponent(const PathEls::PathComponent &c);
// # Path construction
- static Path fromString(QString s, ErrorHandler errorHandler=nullptr);
- static Path fromString(QStringView s, ErrorHandler errorHandler=nullptr);
+ static Path fromString(const QString &s, const ErrorHandler &errorHandler = nullptr);
+ static Path fromString(QStringView s, const ErrorHandler &errorHandler = nullptr);
static Path Root(PathRoot r);
static Path Root(QStringView s=u"");
- static Path Root(QString s);
+ static Path Root(const QString &s);
static Path Index(index_type i);
static Path Field(QStringView s=u"");
- static Path Field(QString s);
+ static Path Field(const QString &s);
static Path Key(QStringView s=u"");
- static Path Key(QString s);
+ static Path Key(const QString &s);
static Path Current(PathCurrent c);
static Path Current(QStringView s=u"");
- static Path Current(QString s);
+ static Path Current(const QString &s);
static Path Empty();
// add
Path empty() const;
- Path field(QString name) const;
+ Path field(const QString &name) const;
Path field(QStringView name) const;
- Path key(QString name) const;
+ Path key(const QString &name) const;
Path key(QStringView name) const;
Path index(index_type i) const;
Path any() const;
- Path filter(std::function<bool(DomItem)>, QString) const;
- Path filter(std::function<bool(DomItem)>, QStringView desc=u"<native code filter>") const;
+ Path filter(const std::function<bool(const DomItem &)> &, const QString &) const;
+ Path filter(const std::function<bool(const DomItem &)> &,
+ QStringView desc=u"<native code filter>") const;
Path current(PathCurrent s) const;
- Path current(QString s) const;
+ Path current(const QString &s) const;
Path current(QStringView s=u"") const;
- Path path(Path toAdd, bool avoidToAddAsBase = false) const;
+ Path path(const Path &toAdd, bool avoidToAddAsBase = false) const;
Path expandFront() const;
Path expandBack() const;
@@ -706,7 +678,8 @@ public:
private:
const Component &component(int i) const;
- explicit Path(quint16 endOffset, quint16 length, std::shared_ptr<PathEls::PathData> data);
+ explicit Path(quint16 endOffset, quint16 length,
+ const std::shared_ptr<PathEls::PathData> &data);
friend class QQmlJS::Dom::PathEls::TestPaths;
friend class FieldFilter;
friend size_t qHash(const Path &, size_t);
@@ -776,6 +749,9 @@ inline size_t qHash(const Path &path, size_t seed)
*it++ = qHash(p.component(0).stringView(), seed)^size_t(p.headRoot())^size_t(p.headCurrent());
}
}
+
+ // TODO: Get rid of the reinterpret_cast.
+ // Rather hash the path components in a more structured way.
return qHash(QByteArray::fromRawData(reinterpret_cast<char *>(&buf[0]), (it - &buf[0])*sizeof(size_t)), seed);
}
diff --git a/src/qmldom/qqmldomreformatter.cpp b/src/qmldom/qqmldomreformatter.cpp
index 9114f39c3e..3093a3d4da 100644
--- a/src/qmldom/qqmldomreformatter.cpp
+++ b/src/qmldom/qqmldomreformatter.cpp
@@ -11,6 +11,7 @@
#include <QString>
+#include <algorithm>
#include <limits>
QT_BEGIN_NAMESPACE
@@ -19,1170 +20,1116 @@ namespace Dom {
using namespace AST;
-class Rewriter : protected BaseVisitor
+bool ScriptFormatter::preVisit(Node *n)
{
- OutWriter &lw;
- std::shared_ptr<AstComments> comments;
- std::function<QStringView(SourceLocation)> loc2Str;
- QHash<Node *, QList<std::function<void()>>> postOps;
- int expressionDepth = 0;
-
- bool addSemicolons() const { return expressionDepth > 0; }
-
-public:
- Rewriter(OutWriter &lw, std::shared_ptr<AstComments> comments,
- std::function<QStringView(SourceLocation)> loc2Str, Node *node)
- : lw(lw), comments(comments), loc2Str(loc2Str)
- {
- accept(node);
+ if (CommentedElement *c = comments->commentForNode(n)) {
+ c->writePre(lw);
+ postOps[n].append([c, this]() { c->writePost(lw); });
}
-
-protected:
- bool preVisit(Node *n) override
- {
- if (CommentedElement *c = comments->commentForNode(n)) {
- c->writePre(lw);
- postOps[n].append([c, this]() { c->writePost(lw); });
- }
- return true;
- }
- void postVisit(Node *n) override
- {
- for (auto &op : postOps[n]) {
- op();
- }
- postOps.remove(n);
+ return true;
+}
+void ScriptFormatter::postVisit(Node *n)
+{
+ for (auto &op : postOps[n]) {
+ op();
}
+ postOps.remove(n);
+}
- void accept(Node *node) { Node::accept(node, this); }
+void ScriptFormatter::lnAcceptIndented(Node *node)
+{
+ int indent = lw.increaseIndent(1);
+ lw.ensureNewline();
+ accept(node);
+ lw.decreaseIndent(1, indent);
+}
- void lnAcceptIndented(Node *node)
- {
- int indent = lw.increaseIndent(1);
- lw.ensureNewline();
- accept(node);
- lw.decreaseIndent(1, indent);
+bool ScriptFormatter::acceptBlockOrIndented(Node *ast, bool finishWithSpaceOrNewline)
+{
+ if (cast<Block *>(ast)) {
+ out(" ");
+ accept(ast);
+ if (finishWithSpaceOrNewline)
+ out(" ");
+ return true;
+ } else {
+ if (finishWithSpaceOrNewline)
+ postOps[ast].append([this]() { this->newLine(); });
+ lnAcceptIndented(ast);
+ return false;
}
+}
- void out(const char *str) { lw.write(QString::fromLatin1(str)); }
-
- void out(QStringView str) { lw.write(str); }
+bool ScriptFormatter::visit(ThisExpression *ast)
+{
+ out(ast->thisToken);
+ return true;
+}
- void out(const SourceLocation &loc)
- {
- if (loc.length != 0)
- out(loc2Str(loc));
- }
+bool ScriptFormatter::visit(NullExpression *ast)
+{
+ out(ast->nullToken);
+ return true;
+}
+bool ScriptFormatter::visit(TrueLiteral *ast)
+{
+ out(ast->trueToken);
+ return true;
+}
+bool ScriptFormatter::visit(FalseLiteral *ast)
+{
+ out(ast->falseToken);
+ return true;
+}
- void newLine() { lw.ensureNewline(); }
+bool ScriptFormatter::visit(IdentifierExpression *ast)
+{
+ out(ast->identifierToken);
+ return true;
+}
+bool ScriptFormatter::visit(StringLiteral *ast)
+{
+ // correctly handle multiline literals
+ if (ast->literalToken.length == 0)
+ return true;
+ QStringView str = loc2Str(ast->literalToken);
+ if (lw.indentNextlines && str.contains(QLatin1Char('\n'))) {
+ out(str.mid(0, 1));
+ lw.indentNextlines = false;
+ out(str.mid(1));
+ lw.indentNextlines = true;
+ } else {
+ out(str);
+ }
+ return true;
+}
+bool ScriptFormatter::visit(NumericLiteral *ast)
+{
+ out(ast->literalToken);
+ return true;
+}
+bool ScriptFormatter::visit(RegExpLiteral *ast)
+{
+ out(ast->literalToken);
+ return true;
+}
- bool acceptBlockOrIndented(Node *ast, bool finishWithSpaceOrNewline = false)
- {
- if (cast<Block *>(ast)) {
- out(" ");
- accept(ast);
- if (finishWithSpaceOrNewline)
- out(" ");
- return true;
- } else {
- if (finishWithSpaceOrNewline)
- postOps[ast].append([this]() { this->newLine(); });
- lnAcceptIndented(ast);
- return false;
+bool ScriptFormatter::visit(ArrayPattern *ast)
+{
+ out(ast->lbracketToken);
+ int baseIndent = lw.increaseIndent(1);
+ if (ast->elements) {
+ accept(ast->elements);
+ out(ast->commaToken);
+ auto lastElement = lastListElement(ast->elements);
+ if (lastElement->element && cast<ObjectPattern *>(lastElement->element->initializer)) {
+ newLine();
}
+ } else {
+ out(ast->commaToken);
}
+ lw.decreaseIndent(1, baseIndent);
+ out(ast->rbracketToken);
+ return false;
+}
- // we are not supposed to handle the ui
- bool visit(UiPragma *) override
- {
- Q_ASSERT(false);
- return false;
- }
- bool visit(UiEnumDeclaration *) override
- {
- Q_ASSERT(false);
- return false;
- }
- bool visit(UiEnumMemberList *) override
- {
- Q_ASSERT(false);
- return false;
- }
- bool visit(UiImport *) override
- {
- Q_ASSERT(false);
- return false;
- }
- bool visit(UiObjectDefinition *) override
- {
- Q_ASSERT(false);
- return false;
- }
- bool visit(UiObjectInitializer *) override
- {
- Q_ASSERT(false);
- return false;
- }
- bool visit(UiParameterList *) override
- {
- Q_ASSERT(false);
- return false;
- }
- bool visit(UiPublicMember *) override
- {
- Q_ASSERT(false);
- return false;
- }
- bool visit(UiObjectBinding *) override
- {
- Q_ASSERT(false);
- return false;
- }
- bool visit(UiScriptBinding *) override
- {
- Q_ASSERT(false);
- return false;
- }
- bool visit(UiArrayBinding *) override
- {
- Q_ASSERT(false);
- return false;
- }
- bool visit(UiHeaderItemList *) override
- {
- Q_ASSERT(false);
- return false;
- }
- bool visit(UiObjectMemberList *) override
- {
- Q_ASSERT(false);
- return false;
- }
- bool visit(UiArrayMemberList *) override
- {
- Q_ASSERT(false);
- return false;
- }
- bool visit(UiQualifiedId *) override
- {
- Q_ASSERT(false);
- return false;
- }
- bool visit(UiProgram *) override
- {
- Q_ASSERT(false);
- return false;
- }
- bool visit(UiSourceElement *) override
- {
- Q_ASSERT(false);
- return false;
- }
- bool visit(UiVersionSpecifier *) override
- {
- Q_ASSERT(false);
- return false;
- }
- bool visit(UiInlineComponent *) override
- {
- Q_ASSERT(false);
- return false;
- }
- bool visit(UiAnnotation *) override
- {
- Q_ASSERT(false);
- return false;
- }
- bool visit(UiAnnotationList *) override
- {
- Q_ASSERT(false);
- return false;
- }
- bool visit(UiRequired *) override
- {
- Q_ASSERT(false);
- return false;
+bool ScriptFormatter::visit(ObjectPattern *ast)
+{
+ out(ast->lbraceToken);
+ ++expressionDepth;
+ if (ast->properties) {
+ lnAcceptIndented(ast->properties);
+ newLine();
}
+ --expressionDepth;
+ out(ast->rbraceToken);
+ return false;
+}
- bool visit(ThisExpression *ast) override
- {
- out(ast->thisToken);
- return true;
- }
- bool visit(NullExpression *ast) override
- {
- out(ast->nullToken);
- return true;
- }
- bool visit(TrueLiteral *ast) override
- {
- out(ast->trueToken);
- return true;
- }
- bool visit(FalseLiteral *ast) override
- {
- out(ast->falseToken);
- return true;
- }
- bool visit(IdentifierExpression *ast) override
- {
- out(ast->identifierToken);
- return true;
- }
- bool visit(StringLiteral *ast) override
- {
- // correctly handle multiline literals
- if (ast->literalToken.length == 0)
- return true;
- QStringView str = loc2Str(ast->literalToken);
- if (lw.indentNextlines && str.contains(QLatin1Char('\n'))) {
- out(str.mid(0, 1));
- lw.indentNextlines = false;
- out(str.mid(1));
- lw.indentNextlines = true;
- } else {
- out(str);
- }
- return true;
- }
- bool visit(NumericLiteral *ast) override
- {
- out(ast->literalToken);
- return true;
- }
- bool visit(RegExpLiteral *ast) override
- {
- out(ast->literalToken);
- return true;
- }
+bool ScriptFormatter::visit(PatternElementList *ast)
+{
+ for (PatternElementList *it = ast; it; it = it->next) {
+ const bool isObjectInitializer =
+ it->element && cast<ObjectPattern *>(it->element->initializer);
+ if (isObjectInitializer)
+ newLine();
- bool visit(ArrayPattern *ast) override
- {
- out(ast->lbracketToken);
- int baseIndent = lw.increaseIndent(1);
- if (ast->elements)
- accept(ast->elements);
- out(ast->commaToken);
- lw.decreaseIndent(1, baseIndent);
- out(ast->rbracketToken);
- return false;
+ if (it->elision)
+ accept(it->elision);
+ if (it->elision && it->element)
+ out(", ");
+ if (it->element)
+ accept(it->element);
+ if (it->next) {
+ out(", ");
+ if (isObjectInitializer)
+ newLine();
+ }
}
+ return false;
+}
- bool visit(ObjectPattern *ast) override
- {
- out(ast->lbraceToken);
- ++expressionDepth;
- if (ast->properties) {
- lnAcceptIndented(ast->properties);
+bool ScriptFormatter::visit(PatternPropertyList *ast)
+{
+ for (PatternPropertyList *it = ast; it; it = it->next) {
+ accept(it->property);
+ if (it->next) {
+ out(",");
newLine();
}
- --expressionDepth;
- out(ast->rbraceToken);
- return false;
}
+ return false;
+}
- bool visit(PatternElementList *ast) override
- {
- for (PatternElementList *it = ast; it; it = it->next) {
- if (it->elision)
- accept(it->elision);
- if (it->elision && it->element)
- out(", ");
- if (it->element)
- accept(it->element);
- if (it->next)
- out(", ");
+// https://262.ecma-international.org/7.0/#prod-PropertyDefinition
+bool ScriptFormatter::visit(AST::PatternProperty *property)
+{
+ if (property->type == PatternElement::Getter || property->type == PatternElement::Setter
+ || property->type == PatternElement::Method) {
+ // note that MethodDefinitions and FunctionDeclarations have different syntax
+ // https://262.ecma-international.org/7.0/#prod-MethodDefinition
+ // https://262.ecma-international.org/7.0/#prod-FunctionDeclaration
+ // hence visit(FunctionDeclaration*) is not quite appropriate here
+ if (property->type == PatternProperty::Getter)
+ out("get ");
+ else if (property->type == PatternProperty::Setter)
+ out("set ");
+ FunctionExpression *f = AST::cast<FunctionExpression *>(property->initializer);
+ if (f->isGenerator) {
+ out("*");
}
- return false;
- }
-
- bool visit(PatternPropertyList *ast) override
- {
- for (PatternPropertyList *it = ast; it; it = it->next) {
- PatternProperty *assignment = AST::cast<PatternProperty *>(it->property);
- if (assignment) {
- preVisit(assignment);
- bool isStringLike = AST::cast<StringLiteralPropertyName *>(assignment->name)
- || cast<IdentifierPropertyName *>(assignment->name);
- if (isStringLike)
- out("\"");
- accept(assignment->name);
- if (isStringLike)
- out("\"");
- out(": "); // assignment->colonToken
- if (it->next)
- postOps[assignment->initializer].append([this] {
- out(","); // always invalid?
- });
- accept(assignment->initializer);
- if (it->next)
- newLine();
- postVisit(assignment);
- continue;
- }
- PatternPropertyList *getterSetter = AST::cast<PatternPropertyList *>(it->next);
- if (getterSetter->property) {
- switch (getterSetter->property->type) {
- case PatternElement::Getter:
- out("get");
- break;
- case PatternElement::Setter:
- out("set");
- break;
- default:
- break;
- }
-
- accept(getterSetter->property->name);
- out("(");
- // accept(getterSetter->formals); // TODO
- out(")");
- out(" {");
- // accept(getterSetter->functionBody); // TODO
- out(" }");
+ accept(property->name);
+ out(f->lparenToken);
+ accept(f->formals);
+ out(f->rparenToken);
+ out(f->lbraceToken);
+ const bool scoped = f->lbraceToken.isValid();
+ if (scoped)
+ ++expressionDepth;
+ if (f->body) {
+ if (f->body->next || scoped) {
+ lnAcceptIndented(f->body);
+ lw.newline();
+ } else {
+ auto baseIndent = lw.increaseIndent(1);
+ accept(f->body);
+ lw.decreaseIndent(1, baseIndent);
}
}
+ if (scoped)
+ --expressionDepth;
+ out(f->rbraceToken);
return false;
}
- bool visit(NestedExpression *ast) override
- {
- out(ast->lparenToken);
- int baseIndent = lw.increaseIndent(1);
- accept(ast->expression);
- lw.decreaseIndent(1, baseIndent);
- out(ast->rparenToken);
- return false;
+ // IdentifierReference[?Yield]
+ accept(property->name);
+ bool useInitializer = false;
+ const bool bindingIdentifierExist = !property->bindingIdentifier.isEmpty();
+ if (property->colonToken.isValid()) {
+ // PropertyName[?Yield] : AssignmentExpression[In, ?Yield]
+ out(": ");
+ useInitializer = true;
+ if (bindingIdentifierExist)
+ out(property->bindingIdentifier);
+ if (property->bindingTarget)
+ accept(property->bindingTarget);
}
- bool visit(IdentifierPropertyName *ast) override
- {
- out(ast->id.toString());
- return true;
- }
- bool visit(StringLiteralPropertyName *ast) override
- {
- out(ast->id.toString());
- return true;
- }
- bool visit(NumericLiteralPropertyName *ast) override
- {
- out(QString::number(ast->id));
- return true;
+ if (property->initializer) {
+ // CoverInitializedName[?Yield]
+ if (bindingIdentifierExist) {
+ out(" = ");
+ useInitializer = true;
+ }
+ if (useInitializer)
+ accept(property->initializer);
}
+ return false;
+}
- bool visit(TemplateLiteral *ast) override
- {
- // correctly handle multiline literals
- if (ast->literalToken.length != 0) {
- QStringView str = loc2Str(ast->literalToken);
- if (lw.indentNextlines && str.contains(QLatin1Char('\n'))) {
- out(str.mid(0, 1));
- lw.indentNextlines = false;
- out(str.mid(1));
- lw.indentNextlines = true;
- } else {
- out(str);
- }
+bool ScriptFormatter::visit(NestedExpression *ast)
+{
+ out(ast->lparenToken);
+ int baseIndent = lw.increaseIndent(1);
+ accept(ast->expression);
+ lw.decreaseIndent(1, baseIndent);
+ out(ast->rparenToken);
+ return false;
+}
+
+bool ScriptFormatter::visit(IdentifierPropertyName *ast)
+{
+ out(ast->id.toString());
+ return true;
+}
+bool ScriptFormatter::visit(StringLiteralPropertyName *ast)
+{
+ out(ast->propertyNameToken);
+ return true;
+}
+bool ScriptFormatter::visit(NumericLiteralPropertyName *ast)
+{
+ out(QString::number(ast->id));
+ return true;
+}
+
+bool ScriptFormatter::visit(TemplateLiteral *ast)
+{
+ // correctly handle multiline literals
+ if (ast->literalToken.length != 0) {
+ QStringView str = loc2Str(ast->literalToken);
+ if (lw.indentNextlines && str.contains(QLatin1Char('\n'))) {
+ out(str.mid(0, 1));
+ lw.indentNextlines = false;
+ out(str.mid(1));
+ lw.indentNextlines = true;
+ } else {
+ out(str);
}
- accept(ast->expression);
- return true;
}
+ accept(ast->expression);
+ return true;
+}
- bool visit(ArrayMemberExpression *ast) override
- {
- accept(ast->base);
- out(ast->lbracketToken);
- int indent = lw.increaseIndent(1);
- accept(ast->expression);
- lw.decreaseIndent(1, indent);
- out(ast->rbracketToken);
- return false;
- }
+bool ScriptFormatter::visit(ArrayMemberExpression *ast)
+{
+ accept(ast->base);
+ out(ast->lbracketToken);
+ int indent = lw.increaseIndent(1);
+ accept(ast->expression);
+ lw.decreaseIndent(1, indent);
+ out(ast->rbracketToken);
+ return false;
+}
- bool visit(FieldMemberExpression *ast) override
- {
- accept(ast->base);
- out(ast->dotToken);
- out(ast->identifierToken);
- return false;
- }
+bool ScriptFormatter::visit(FieldMemberExpression *ast)
+{
+ accept(ast->base);
+ out(ast->dotToken);
+ out(ast->identifierToken);
+ return false;
+}
- bool visit(NewMemberExpression *ast) override
- {
- out("new "); // ast->newToken
- accept(ast->base);
- out(ast->lparenToken);
- accept(ast->arguments);
- out(ast->rparenToken);
- return false;
- }
+bool ScriptFormatter::visit(NewMemberExpression *ast)
+{
+ out("new "); // ast->newToken
+ accept(ast->base);
+ out(ast->lparenToken);
+ accept(ast->arguments);
+ out(ast->rparenToken);
+ return false;
+}
- bool visit(NewExpression *ast) override
- {
- out("new "); // ast->newToken
- accept(ast->expression);
- return false;
- }
+bool ScriptFormatter::visit(NewExpression *ast)
+{
+ out("new "); // ast->newToken
+ accept(ast->expression);
+ return false;
+}
- bool visit(CallExpression *ast) override
- {
- accept(ast->base);
- out(ast->lparenToken);
- int baseIndent = lw.increaseIndent(1);
- accept(ast->arguments);
- lw.decreaseIndent(1, baseIndent);
- out(ast->rparenToken);
- return false;
- }
+bool ScriptFormatter::visit(CallExpression *ast)
+{
+ accept(ast->base);
+ out(ast->lparenToken);
+ accept(ast->arguments);
+ out(ast->rparenToken);
+ return false;
+}
- bool visit(PostIncrementExpression *ast) override
- {
- accept(ast->base);
- out(ast->incrementToken);
- return false;
- }
+bool ScriptFormatter::visit(PostIncrementExpression *ast)
+{
+ accept(ast->base);
+ out(ast->incrementToken);
+ return false;
+}
- bool visit(PostDecrementExpression *ast) override
- {
- accept(ast->base);
- out(ast->decrementToken);
- return false;
- }
+bool ScriptFormatter::visit(PostDecrementExpression *ast)
+{
+ accept(ast->base);
+ out(ast->decrementToken);
+ return false;
+}
- bool visit(PreIncrementExpression *ast) override
- {
- out(ast->incrementToken);
- accept(ast->expression);
- return false;
- }
+bool ScriptFormatter::visit(PreIncrementExpression *ast)
+{
+ out(ast->incrementToken);
+ accept(ast->expression);
+ return false;
+}
- bool visit(PreDecrementExpression *ast) override
- {
- out(ast->decrementToken);
- accept(ast->expression);
- return false;
- }
+bool ScriptFormatter::visit(PreDecrementExpression *ast)
+{
+ out(ast->decrementToken);
+ accept(ast->expression);
+ return false;
+}
- bool visit(DeleteExpression *ast) override
- {
- out("delete "); // ast->deleteToken
- accept(ast->expression);
- return false;
- }
+bool ScriptFormatter::visit(DeleteExpression *ast)
+{
+ out("delete "); // ast->deleteToken
+ accept(ast->expression);
+ return false;
+}
- bool visit(VoidExpression *ast) override
- {
- out("void "); // ast->voidToken
- accept(ast->expression);
- return false;
- }
+bool ScriptFormatter::visit(VoidExpression *ast)
+{
+ out("void "); // ast->voidToken
+ accept(ast->expression);
+ return false;
+}
- bool visit(TypeOfExpression *ast) override
- {
- out("typeof "); // ast->typeofToken
- accept(ast->expression);
- return false;
- }
+bool ScriptFormatter::visit(TypeOfExpression *ast)
+{
+ out("typeof "); // ast->typeofToken
+ accept(ast->expression);
+ return false;
+}
- bool visit(UnaryPlusExpression *ast) override
- {
- out(ast->plusToken);
- accept(ast->expression);
- return false;
- }
+bool ScriptFormatter::visit(UnaryPlusExpression *ast)
+{
+ out(ast->plusToken);
+ accept(ast->expression);
+ return false;
+}
- bool visit(UnaryMinusExpression *ast) override
- {
- out(ast->minusToken);
- accept(ast->expression);
- return false;
- }
+bool ScriptFormatter::visit(UnaryMinusExpression *ast)
+{
+ out(ast->minusToken);
+ accept(ast->expression);
+ return false;
+}
- bool visit(TildeExpression *ast) override
- {
- out(ast->tildeToken);
- accept(ast->expression);
- return false;
- }
+bool ScriptFormatter::visit(TildeExpression *ast)
+{
+ out(ast->tildeToken);
+ accept(ast->expression);
+ return false;
+}
- bool visit(NotExpression *ast) override
- {
- out(ast->notToken);
- accept(ast->expression);
- return false;
- }
+bool ScriptFormatter::visit(NotExpression *ast)
+{
+ out(ast->notToken);
+ accept(ast->expression);
+ return false;
+}
- bool visit(BinaryExpression *ast) override
- {
- accept(ast->left);
- out(" ");
- out(ast->operatorToken);
- out(" ");
- accept(ast->right);
- return false;
- }
+bool ScriptFormatter::visit(BinaryExpression *ast)
+{
+ accept(ast->left);
+ out(" ");
+ out(ast->operatorToken);
+ out(" ");
+ accept(ast->right);
+ return false;
+}
- bool visit(ConditionalExpression *ast) override
- {
- accept(ast->expression);
- out(" ? "); // ast->questionToken
- accept(ast->ok);
- out(" : "); // ast->colonToken
- accept(ast->ko);
- return false;
- }
+bool ScriptFormatter::visit(ConditionalExpression *ast)
+{
+ accept(ast->expression);
+ out(" ? "); // ast->questionToken
+ accept(ast->ok);
+ out(" : "); // ast->colonToken
+ accept(ast->ko);
+ return false;
+}
- bool visit(Block *ast) override
- {
- out(ast->lbraceToken);
+bool ScriptFormatter::visit(Block *ast)
+{
+ out(ast->lbraceToken);
+ if (ast->statements) {
++expressionDepth;
lnAcceptIndented(ast->statements);
newLine();
--expressionDepth;
- out(ast->rbraceToken);
- return false;
}
+ out(ast->rbraceToken);
+ return false;
+}
- bool visit(VariableStatement *ast) override
- {
- out(ast->declarationKindToken);
- out(" ");
- accept(ast->declarations);
- if (addSemicolons())
- out(";");
- return false;
+bool ScriptFormatter::visit(VariableStatement *ast)
+{
+ out(ast->declarationKindToken);
+ out(" ");
+ accept(ast->declarations);
+ if (addSemicolons())
+ out(";");
+ return false;
+}
+
+bool ScriptFormatter::visit(PatternElement *ast)
+{
+ switch (ast->type) {
+ case PatternElement::Literal:
+ case PatternElement::Method:
+ case PatternElement::Binding:
+ break;
+ case PatternElement::Getter:
+ out("get ");
+ break;
+ case PatternElement::Setter:
+ out("set ");
+ break;
+ case PatternElement::SpreadElement:
+ out("...");
+ break;
+ }
+
+ accept(ast->bindingTarget);
+ if (!ast->destructuringPattern())
+ out(ast->identifierToken);
+ if (ast->initializer) {
+ if (ast->isVariableDeclaration() || ast->type == AST::PatternElement::Binding)
+ out(" = ");
+ accept(ast->initializer);
}
+ return false;
+}
+bool ScriptFormatter::visit(EmptyStatement *ast)
+{
+ out(ast->semicolonToken);
+ return false;
+}
- void outputScope(VariableScope scope) {
- switch (scope) {
- case VariableScope::Const:
- out("const ");
- break;
- case VariableScope::Let:
- out("let ");
- break;
- case VariableScope::Var:
- out("var ");
- break;
- default:
- break;
+bool ScriptFormatter::visit(IfStatement *ast)
+{
+ out(ast->ifToken);
+ out(" ");
+ out(ast->lparenToken);
+ preVisit(ast->expression);
+ ast->expression->accept0(this);
+ out(ast->rparenToken);
+ postVisit(ast->expression);
+ acceptBlockOrIndented(ast->ok, ast->ko);
+ if (ast->ko) {
+ out(ast->elseToken);
+ if (cast<Block *>(ast->ko) || cast<IfStatement *>(ast->ko)) {
+ out(" ");
+ accept(ast->ko);
+ } else {
+ lnAcceptIndented(ast->ko);
}
}
+ return false;
+}
- bool visit(PatternElement *ast) override
- {
- if (ast->isForDeclaration) {
- outputScope(ast->scope);
- }
- accept(ast->bindingTarget);
- switch (ast->type) {
- case PatternElement::Literal:
- case PatternElement::Method:
- case PatternElement::Binding:
- break;
- case PatternElement::Getter:
- out("get ");
- break;
- case PatternElement::Setter:
- out("set ");
- break;
- case PatternElement::SpreadElement:
- out("...");
- break;
+bool ScriptFormatter::visit(DoWhileStatement *ast)
+{
+ out(ast->doToken);
+ acceptBlockOrIndented(ast->statement, true);
+ out(ast->whileToken);
+ out(" ");
+ out(ast->lparenToken);
+ accept(ast->expression);
+ out(ast->rparenToken);
+ return false;
+}
+
+bool ScriptFormatter::visit(WhileStatement *ast)
+{
+ out(ast->whileToken);
+ out(" ");
+ out(ast->lparenToken);
+ accept(ast->expression);
+ out(ast->rparenToken);
+ acceptBlockOrIndented(ast->statement);
+ return false;
+}
+
+bool ScriptFormatter::visit(ForStatement *ast)
+{
+ out(ast->forToken);
+ out(" ");
+ out(ast->lparenToken);
+ if (ast->initialiser) {
+ accept(ast->initialiser);
+ } else if (ast->declarations) {
+ if (auto pe = ast->declarations->declaration) {
+ out(pe->declarationKindToken);
+ out(" ");
}
- out(ast->identifierToken);
- if (ast->initializer) {
- if (ast->isVariableDeclaration())
- out(" = ");
- accept(ast->initializer);
+ for (VariableDeclarationList *it = ast->declarations; it; it = it->next) {
+ accept(it->declaration);
}
- return false;
}
+ out("; "); // ast->firstSemicolonToken
+ accept(ast->condition);
+ out("; "); // ast->secondSemicolonToken
+ accept(ast->expression);
+ out(ast->rparenToken);
+ acceptBlockOrIndented(ast->statement);
+ return false;
+}
- bool visit(EmptyStatement *ast) override
- {
- out(ast->semicolonToken);
- return false;
+bool ScriptFormatter::visit(ForEachStatement *ast)
+{
+ out(ast->forToken);
+ out(" ");
+ out(ast->lparenToken);
+ if (auto pe = AST::cast<PatternElement *>(ast->lhs)) {
+ out(pe->declarationKindToken);
+ out(" ");
}
+ accept(ast->lhs);
+ out(" ");
+ out(ast->inOfToken);
+ out(" ");
+ accept(ast->expression);
+ out(ast->rparenToken);
+ acceptBlockOrIndented(ast->statement);
+ return false;
+}
- bool visit(IfStatement *ast) override
- {
- out(ast->ifToken);
+bool ScriptFormatter::visit(ContinueStatement *ast)
+{
+ out(ast->continueToken);
+ if (!ast->label.isNull()) {
out(" ");
- out(ast->lparenToken);
- preVisit(ast->expression);
- ast->expression->accept0(this);
- out(ast->rparenToken);
- postVisit(ast->expression);
- acceptBlockOrIndented(ast->ok, ast->ko);
- if (ast->ko) {
- out(ast->elseToken);
- if (cast<Block *>(ast->ko) || cast<IfStatement *>(ast->ko)) {
- out(" ");
- accept(ast->ko);
- } else {
- lnAcceptIndented(ast->ko);
- }
- }
- return false;
+ out(ast->identifierToken);
}
+ if (addSemicolons())
+ out(";");
+ return false;
+}
- bool visit(DoWhileStatement *ast) override
- {
- out(ast->doToken);
- acceptBlockOrIndented(ast->statement, true);
- out(ast->whileToken);
+bool ScriptFormatter::visit(BreakStatement *ast)
+{
+ out(ast->breakToken);
+ if (!ast->label.isNull()) {
out(" ");
- out(ast->lparenToken);
+ out(ast->identifierToken);
+ }
+ if (addSemicolons())
+ out(";");
+ return false;
+}
+
+bool ScriptFormatter::visit(ReturnStatement *ast)
+{
+ out(ast->returnToken);
+ if (ast->expression) {
+ if (ast->returnToken.length != 0)
+ out(" ");
accept(ast->expression);
- out(ast->rparenToken);
- return false;
}
+ if (ast->returnToken.length > 0 && addSemicolons())
+ out(";");
+ return false;
+}
- bool visit(WhileStatement *ast) override
- {
- out(ast->whileToken);
- out(" ");
- out(ast->lparenToken);
+bool ScriptFormatter::visit(YieldExpression *ast)
+{
+ out(ast->yieldToken);
+ if (ast->isYieldStar)
+ out("*");
+ if (ast->expression) {
+ if (ast->yieldToken.isValid())
+ out(" ");
accept(ast->expression);
- out(ast->rparenToken);
- acceptBlockOrIndented(ast->statement);
- return false;
}
+ return false;
+}
- bool visit(ForStatement *ast) override
- {
- out(ast->forToken);
+bool ScriptFormatter::visit(ThrowStatement *ast)
+{
+ out(ast->throwToken);
+ if (ast->expression) {
out(" ");
- out(ast->lparenToken);
- if (ast->initialiser) {
- accept(ast->initialiser);
- } else if (ast->declarations) {
- outputScope(ast->declarations->declaration->scope);
- accept(ast->declarations);
- }
- out("; "); // ast->firstSemicolonToken
- accept(ast->condition);
- out("; "); // ast->secondSemicolonToken
accept(ast->expression);
- out(ast->rparenToken);
- acceptBlockOrIndented(ast->statement);
- return false;
}
+ if (addSemicolons())
+ out(";");
+ return false;
+}
- bool visit(ForEachStatement *ast) override
- {
- out(ast->forToken);
- out(" ");
- out(ast->lparenToken);
- accept(ast->lhs);
+bool ScriptFormatter::visit(WithStatement *ast)
+{
+ out(ast->withToken);
+ out(" ");
+ out(ast->lparenToken);
+ accept(ast->expression);
+ out(ast->rparenToken);
+ acceptBlockOrIndented(ast->statement);
+ return false;
+}
+
+bool ScriptFormatter::visit(SwitchStatement *ast)
+{
+ out(ast->switchToken);
+ out(" ");
+ out(ast->lparenToken);
+ accept(ast->expression);
+ out(ast->rparenToken);
+ out(" ");
+ accept(ast->block);
+ return false;
+}
+
+bool ScriptFormatter::visit(CaseBlock *ast)
+{
+ out(ast->lbraceToken);
+ ++expressionDepth;
+ newLine();
+ accept(ast->clauses);
+ if (ast->clauses && ast->defaultClause)
+ newLine();
+ accept(ast->defaultClause);
+ if (ast->moreClauses)
+ newLine();
+ accept(ast->moreClauses);
+ newLine();
+ --expressionDepth;
+ out(ast->rbraceToken);
+ return false;
+}
+
+bool ScriptFormatter::visit(CaseClause *ast)
+{
+ out("case "); // ast->caseToken
+ accept(ast->expression);
+ out(ast->colonToken);
+ if (ast->statements)
+ lnAcceptIndented(ast->statements);
+ return false;
+}
+
+bool ScriptFormatter::visit(DefaultClause *ast)
+{
+ out(ast->defaultToken);
+ out(ast->colonToken);
+ lnAcceptIndented(ast->statements);
+ return false;
+}
+
+bool ScriptFormatter::visit(LabelledStatement *ast)
+{
+ out(ast->identifierToken);
+ out(": "); // ast->colonToken
+ accept(ast->statement);
+ return false;
+}
+
+bool ScriptFormatter::visit(TryStatement *ast)
+{
+ out("try "); // ast->tryToken
+ accept(ast->statement);
+ if (ast->catchExpression) {
out(" ");
- out(ast->inOfToken);
+ accept(ast->catchExpression);
+ }
+ if (ast->finallyExpression) {
out(" ");
- accept(ast->expression);
- out(ast->rparenToken);
- acceptBlockOrIndented(ast->statement);
- return false;
+ accept(ast->finallyExpression);
}
+ return false;
+}
- bool visit(ContinueStatement *ast) override
- {
- out(ast->continueToken);
- if (!ast->label.isNull()) {
- out(" ");
+bool ScriptFormatter::visit(Catch *ast)
+{
+ out(ast->catchToken);
+ out(" ");
+ out(ast->lparenToken);
+ out(ast->identifierToken);
+ out(") "); // ast->rparenToken
+ accept(ast->statement);
+ return false;
+}
+
+bool ScriptFormatter::visit(Finally *ast)
+{
+ out("finally "); // ast->finallyToken
+ accept(ast->statement);
+ return false;
+}
+
+bool ScriptFormatter::visit(FunctionDeclaration *ast)
+{
+ return ScriptFormatter::visit(static_cast<FunctionExpression *>(ast));
+}
+
+bool ScriptFormatter::visit(FunctionExpression *ast)
+{
+ if (!ast->isArrowFunction) {
+ if (ast->isGenerator) {
+ out("function* ");
+ } else {
+ out("function ");
+ }
+ if (!ast->name.isNull())
out(ast->identifierToken);
+ }
+ out(ast->lparenToken);
+ const bool needParentheses = ast->formals
+ && (ast->formals->next
+ || (ast->formals->element && ast->formals->element->bindingTarget));
+ if (ast->isArrowFunction && needParentheses)
+ out("(");
+ int baseIndent = lw.increaseIndent(1);
+ accept(ast->formals);
+ lw.decreaseIndent(1, baseIndent);
+ if (ast->isArrowFunction && needParentheses)
+ out(")");
+ out(ast->rparenToken);
+ if (ast->isArrowFunction && !ast->formals)
+ out("()");
+ out(" ");
+ if (ast->isArrowFunction)
+ out("=> ");
+ out(ast->lbraceToken);
+ if (ast->lbraceToken.length != 0)
+ ++expressionDepth;
+ if (ast->body) {
+ if (ast->body->next || ast->lbraceToken.length != 0) {
+ lnAcceptIndented(ast->body);
+ newLine();
+ } else {
+ // print a single statement in one line. E.g. x => x * 2
+ baseIndent = lw.increaseIndent(1);
+ accept(ast->body);
+ lw.decreaseIndent(1, baseIndent);
}
- if (addSemicolons())
- out(";");
- return false;
}
+ if (ast->lbraceToken.length != 0)
+ --expressionDepth;
+ out(ast->rbraceToken);
+ return false;
+}
- bool visit(BreakStatement *ast) override
- {
- out(ast->breakToken);
- if (!ast->label.isNull()) {
- out(" ");
- out(ast->identifierToken);
- }
- if (addSemicolons())
- out(";");
- return false;
+bool ScriptFormatter::visit(Elision *ast)
+{
+ for (Elision *it = ast; it; it = it->next) {
+ if (it->next)
+ out(", "); // ast->commaToken
}
+ return false;
+}
- bool visit(ReturnStatement *ast) override
- {
- out(ast->returnToken);
- if (ast->expression) {
- if (ast->returnToken.length != 0)
- out(" ");
- accept(ast->expression);
+bool ScriptFormatter::visit(ArgumentList *ast)
+{
+ for (ArgumentList *it = ast; it; it = it->next) {
+ if (it->isSpreadElement)
+ out("...");
+ accept(it->expression);
+ if (it->next) {
+ out(", "); // it->commaToken
}
- if (ast->returnToken.length > 0 && addSemicolons())
- out(";");
- return false;
}
+ return false;
+}
- bool visit(ThrowStatement *ast) override
- {
- out(ast->throwToken);
- if (ast->expression) {
- out(" ");
- accept(ast->expression);
+bool ScriptFormatter::visit(StatementList *ast)
+{
+ ++expressionDepth;
+ for (StatementList *it = ast; it; it = it->next) {
+ // ### work around parser bug: skip empty statements with wrong tokens
+ if (EmptyStatement *emptyStatement = cast<EmptyStatement *>(it->statement)) {
+ if (loc2Str(emptyStatement->semicolonToken) != QLatin1String(";"))
+ continue;
}
- if (addSemicolons())
- out(";");
- return false;
- }
- bool visit(WithStatement *ast) override
- {
- out(ast->withToken);
- out(" ");
- out(ast->lparenToken);
- accept(ast->expression);
- out(ast->rparenToken);
- acceptBlockOrIndented(ast->statement);
- return false;
+ accept(it->statement);
+ if (it->next) {
+ // There might be a post-comment attached to the current
+ // statement or a pre-comment attached to the next
+ // statmente or both.
+ // If any of those are present they will take care of
+ // handling the spacing between the statements so we
+ // don't need to push any newline.
+ auto *commentForCurrentStatement = comments->commentForNode(it->statement);
+ auto *commentForNextStatement = comments->commentForNode(it->next->statement);
+
+ if (
+ (commentForCurrentStatement && !commentForCurrentStatement->postComments().empty())
+ || (commentForNextStatement && !commentForNextStatement->preComments().empty())
+ ) continue;
+
+ quint32 lineDelta = it->next->firstSourceLocation().startLine
+ - it->statement->lastSourceLocation().startLine;
+ lineDelta = std::clamp(lineDelta, quint32{ 1 }, quint32{ 2 });
+
+ newLine(lineDelta);
+ }
}
+ --expressionDepth;
+ return false;
+}
- bool visit(SwitchStatement *ast) override
- {
- out(ast->switchToken);
- out(" ");
- out(ast->lparenToken);
- accept(ast->expression);
- out(ast->rparenToken);
- out(" ");
- accept(ast->block);
- return false;
+bool ScriptFormatter::visit(VariableDeclarationList *ast)
+{
+ for (VariableDeclarationList *it = ast; it; it = it->next) {
+ accept(it->declaration);
+ if (it->next)
+ out(", "); // it->commaToken
}
+ return false;
+}
- bool visit(CaseBlock *ast) override
- {
- out(ast->lbraceToken);
- ++expressionDepth;
- newLine();
- accept(ast->clauses);
- if (ast->clauses && ast->defaultClause)
- newLine();
- accept(ast->defaultClause);
- if (ast->moreClauses)
+bool ScriptFormatter::visit(CaseClauses *ast)
+{
+ for (CaseClauses *it = ast; it; it = it->next) {
+ accept(it->clause);
+ if (it->next)
newLine();
- accept(ast->moreClauses);
- newLine();
- --expressionDepth;
- out(ast->rbraceToken);
- return false;
}
+ return false;
+}
- bool visit(CaseClause *ast) override
- {
- out("case "); // ast->caseToken
- accept(ast->expression);
- out(ast->colonToken);
- if (ast->statements)
- lnAcceptIndented(ast->statements);
- return false;
- }
+bool ScriptFormatter::visit(FormalParameterList *ast)
+{
+ for (FormalParameterList *it = ast; it; it = it->next) {
+ // compare FormalParameterList::finish
+ if (auto id = it->element->bindingIdentifier.toString(); !id.isEmpty())
+ out(id);
+ if (it->element->bindingTarget)
+ accept(it->element->bindingTarget);
+ if (it->next)
+ out(", ");
+ }
+ return false;
+}
- bool visit(DefaultClause *ast) override
- {
- out(ast->defaultToken);
- out(ast->colonToken);
- lnAcceptIndented(ast->statements);
- return false;
- }
+// to check
+bool ScriptFormatter::visit(SuperLiteral *)
+{
+ out("super");
+ return true;
+}
+bool ScriptFormatter::visit(ComputedPropertyName *)
+{
+ out("[");
+ return true;
+}
+bool ScriptFormatter::visit(Expression *el)
+{
+ accept(el->left);
+ out(", ");
+ accept(el->right);
+ return false;
+}
+bool ScriptFormatter::visit(ExpressionStatement *el)
+{
+ if (addSemicolons())
+ postOps[el->expression].append([this]() { out(";"); });
+ return true;
+}
- bool visit(LabelledStatement *ast) override
- {
- out(ast->identifierToken);
- out(": "); // ast->colonToken
- accept(ast->statement);
- return false;
- }
+// Return false because we want to omit default function calls in accept0 implementation.
+bool ScriptFormatter::visit(ClassDeclaration *ast)
+{
+ preVisit(ast);
+ out(ast->classToken);
+ out(" ");
+ out(ast->name);
+ if (ast->heritage) {
+ out(" extends ");
+ accept(ast->heritage);
+ }
+ out(" {");
+ int baseIndent = lw.increaseIndent();
+ for (ClassElementList *it = ast->elements; it; it = it->next) {
+ lw.newline();
+ if (it->isStatic)
+ out("static ");
+ accept(it->property);
+ lw.newline();
+ }
+ lw.decreaseIndent(1, baseIndent);
+ out("}");
+ postVisit(ast);
+ return false;
+}
- bool visit(TryStatement *ast) override
- {
- out("try "); // ast->tryToken
- accept(ast->statement);
- if (ast->catchExpression) {
- out(" ");
- accept(ast->catchExpression);
- }
- if (ast->finallyExpression) {
- out(" ");
- accept(ast->finallyExpression);
- }
- return false;
+bool ScriptFormatter::visit(AST::ImportDeclaration *ast)
+{
+ out(ast->importToken);
+ lw.space();
+ if (!ast->moduleSpecifier.isNull()) {
+ out(ast->moduleSpecifierToken);
}
+ return true;
+}
- bool visit(Catch *ast) override
- {
- out(ast->catchToken);
- out(" ");
- out(ast->lparenToken);
+bool ScriptFormatter::visit(AST::ImportSpecifier *ast)
+{
+ if (!ast->identifier.isNull()) {
out(ast->identifierToken);
- out(") "); // ast->rparenToken
- accept(ast->statement);
- return false;
+ lw.space();
+ out("as");
+ lw.space();
}
+ out(ast->importedBindingToken);
+ return true;
+}
- bool visit(Finally *ast) override
- {
- out("finally "); // ast->finallyToken
- accept(ast->statement);
- return false;
- }
+bool ScriptFormatter::visit(AST::NameSpaceImport *ast)
+{
+ out(ast->starToken);
+ lw.space();
+ out("as");
+ lw.space();
+ out(ast->importedBindingToken);
+ return true;
+}
- bool visit(FunctionDeclaration *ast) override
- {
- return visit(static_cast<FunctionExpression *>(ast));
+bool ScriptFormatter::visit(AST::ImportsList *ast)
+{
+ for (ImportsList *it = ast; it; it = it->next) {
+ accept(it->importSpecifier);
+ if (it->next) {
+ out(",");
+ lw.space();
+ }
+ }
+ return false;
+}
+bool ScriptFormatter::visit(AST::NamedImports *ast)
+{
+ out(ast->leftBraceToken);
+ if (ast->importsList) {
+ lw.space();
}
+ return true;
+}
- bool visit(FunctionExpression *ast) override
- {
- if (!ast->isArrowFunction) {
- out("function "); // ast->functionToken
- if (!ast->name.isNull())
- out(ast->identifierToken);
- }
- out(ast->lparenToken);
- if (ast->isArrowFunction && ast->formals && ast->formals->next)
- out("(");
- int baseIndent = lw.increaseIndent(1);
- accept(ast->formals);
- lw.decreaseIndent(1, baseIndent);
- if (ast->isArrowFunction && ast->formals && ast->formals->next)
- out(")");
- out(ast->rparenToken);
- if (ast->isArrowFunction && !ast->formals)
- out("()");
- out(" ");
- if (ast->isArrowFunction)
- out("=> ");
- out(ast->lbraceToken);
- if (ast->lbraceToken.length != 0)
- ++expressionDepth;
- if (ast->body) {
- if (ast->body->next || ast->lbraceToken.length != 0) {
- lnAcceptIndented(ast->body);
- newLine();
- } else {
- // print a single statement in one line. E.g. x => x * 2
- baseIndent = lw.increaseIndent(1);
- accept(ast->body);
- lw.decreaseIndent(1, baseIndent);
- }
+bool ScriptFormatter::visit(AST::ImportClause *ast)
+{
+ if (!ast->importedDefaultBinding.isNull()) {
+ out(ast->importedDefaultBindingToken);
+ if (ast->nameSpaceImport || ast->namedImports) {
+ out(",");
+ lw.space();
}
- if (ast->lbraceToken.length != 0)
- --expressionDepth;
- out(ast->rbraceToken);
- return false;
}
+ return true;
+}
- bool visit(Elision *ast) override
- {
- for (Elision *it = ast; it; it = it->next) {
- if (it->next)
- out(", "); // ast->commaToken
- }
- return false;
+bool ScriptFormatter::visit(AST::ExportDeclaration *ast)
+{
+ out(ast->exportToken);
+ lw.space();
+ if (ast->exportDefault) {
+ out("default");
+ lw.space();
+ }
+ if (ast->exportsAll()) {
+ out("*");
}
+ return true;
+}
- bool visit(ArgumentList *ast) override
- {
- for (ArgumentList *it = ast; it; it = it->next) {
- if (it->isSpreadElement)
- out("...");
- accept(it->expression);
- if (it->next) {
- out(", "); // it->commaToken
- }
- }
- return false;
+bool ScriptFormatter::visit(AST::ExportClause *ast)
+{
+ out(ast->leftBraceToken);
+ if (ast->exportsList) {
+ lw.space();
}
+ return true;
+}
- bool visit(StatementList *ast) override
- {
- ++expressionDepth;
- for (StatementList *it = ast; it; it = it->next) {
- // ### work around parser bug: skip empty statements with wrong tokens
- if (EmptyStatement *emptyStatement = cast<EmptyStatement *>(it->statement)) {
- if (loc2Str(emptyStatement->semicolonToken) != QLatin1String(";"))
- continue;
- }
+bool ScriptFormatter::visit(AST::ExportSpecifier *ast)
+{
+ out(ast->identifier);
+ if (ast->exportedIdentifierToken.isValid()) {
+ lw.space();
+ out("as");
+ lw.space();
+ out(ast->exportedIdentifier);
+ }
+ return true;
+}
- accept(it->statement);
- if (it->next)
- newLine();
+bool ScriptFormatter::visit(AST::ExportsList *ast)
+{
+ for (ExportsList *it = ast; it; it = it->next) {
+ accept(it->exportSpecifier);
+ if (it->next) {
+ out(",");
+ lw.space();
}
- --expressionDepth;
- return false;
}
+ return false;
+}
- bool visit(VariableDeclarationList *ast) override
- {
- for (VariableDeclarationList *it = ast; it; it = it->next) {
- accept(it->declaration);
- if (it->next)
- out(", "); // it->commaToken
- }
- return false;
- }
+bool ScriptFormatter::visit(AST::FromClause *ast)
+{
+ lw.space();
+ out(ast->fromToken);
+ lw.space();
+ out(ast->moduleSpecifierToken);
+ return true;
+}
- bool visit(CaseClauses *ast) override
- {
- for (CaseClauses *it = ast; it; it = it->next) {
- accept(it->clause);
- if (it->next)
- newLine();
- }
- return false;
- }
+void ScriptFormatter::endVisit(ComputedPropertyName *)
+{
+ out("]");
+}
- bool visit(FormalParameterList *ast) override
- {
- for (FormalParameterList *it = ast; it; it = it->next) {
- out(it->element->bindingIdentifier.toString()); // TODO
- if (it->next)
- out(", ");
- }
- return false;
+void ScriptFormatter::endVisit(AST::ExportDeclaration *ast)
+{
+ // add a semicolon at the end of the following expressions
+ // export * FromClause ;
+ // export ExportClause FromClause ;
+ if (ast->fromClause) {
+ out(";");
}
- // to check
- bool visit(TypeExpression *) override { return true; }
- bool visit(SuperLiteral *) override
- {
- out("super");
- return true;
- }
- bool visit(PatternProperty *) override { return true; }
- bool visit(ComputedPropertyName *) override
- {
- out("[");
- return true;
- }
- bool visit(TaggedTemplate *) override { return true; }
- bool visit(Expression *el) override
- {
- accept(el->left);
- out(", ");
- accept(el->right);
- return false;
- }
- bool visit(ExpressionStatement *el) override
- {
- if (addSemicolons())
- postOps[el->expression].append([this]() { out(";"); });
- return true;
+ // add a semicolon at the end of the following expressions
+ // export ExportClause ;
+ if (ast->exportClause && !ast->fromClause) {
+ out(";");
}
- bool visit(YieldExpression *) override { return true; }
- bool visit(ClassExpression *) override { return true; }
-
- // Return false because we want to omit default function calls in accept0 implementation.
- bool visit(ClassDeclaration *ast) override
- {
- preVisit(ast);
- out(ast->classToken);
- out(" ");
- out(ast->name);
- if (ast->heritage) {
- out(" extends ");
- accept(ast->heritage);
+
+ // add a semicolon at the end of the following expressions
+ // export default [lookahead ∉ { function, class }] AssignmentExpression;
+ if (ast->exportDefault && ast->variableStatementOrDeclaration) {
+ // lookahead ∉ { function, class }
+ if (!(ast->variableStatementOrDeclaration->kind == Node::Kind_FunctionDeclaration
+ || ast->variableStatementOrDeclaration->kind == Node::Kind_ClassDeclaration)) {
+ out(";");
}
- out(" {");
- int baseIndent = lw.increaseIndent();
- for (ClassElementList *it = ast->elements; it; it = it->next) {
- PatternProperty *property = it->property;
- lw.newline();
- preVisit(property);
- if (it->isStatic)
- out("static ");
- if (property->type == PatternProperty::Getter)
- out("get ");
- else if (property->type == PatternProperty::Setter)
- out("set ");
- FunctionExpression *f = AST::cast<FunctionExpression *>(property->initializer);
- const bool scoped = f->lbraceToken.length != 0;
- out(f->functionToken);
- out(f->lparenToken);
- accept(f->formals);
- out(f->rparenToken);
- out(f->lbraceToken);
- if (scoped)
- ++expressionDepth;
- if (f->body) {
- if (f->body->next || scoped) {
- lnAcceptIndented(f->body);
- lw.newline();
- } else {
- baseIndent = lw.increaseIndent(1);
- accept(f->body);
- lw.decreaseIndent(1, baseIndent);
- }
- }
- if (scoped)
- --expressionDepth;
- out(f->rbraceToken);
- lw.newline();
- postVisit(property);
+ // ArrowFunction in QQmlJS::AST is handled with the help of FunctionDeclaration
+ // and not as part of AssignmentExpression (as per ECMA
+ // https://262.ecma-international.org/7.0/#prod-AssignmentExpression)
+ if (ast->variableStatementOrDeclaration->kind == Node::Kind_FunctionDeclaration
+ && static_cast<AST::FunctionDeclaration *>(ast->variableStatementOrDeclaration)
+ ->isArrowFunction) {
+ out(";");
}
- lw.decreaseIndent(1, baseIndent);
- out("}");
- postVisit(ast);
- return false;
}
+}
+
+void ScriptFormatter::endVisit(AST::ExportClause *ast)
+{
+ if (ast->exportsList) {
+ lw.space();
+ }
+ out(ast->rightBraceToken);
+}
- bool visit(ClassElementList *) override { return true; }
- bool visit(Program *) override { return true; }
- bool visit(NameSpaceImport *) override { return true; }
- bool visit(ImportSpecifier *) override { return true; }
- bool visit(ImportsList *) override { return true; }
- bool visit(NamedImports *) override { return true; }
- bool visit(FromClause *) override { return true; }
- bool visit(ImportClause *) override { return true; }
- bool visit(ImportDeclaration *) override { return true; }
- bool visit(ExportSpecifier *) override { return true; }
- bool visit(ExportsList *) override { return true; }
- bool visit(ExportClause *) override { return true; }
- bool visit(ExportDeclaration *) override { return true; }
- bool visit(ESModule *) override { return true; }
- bool visit(DebuggerStatement *) override { return true; }
- bool visit(Type *) override { return true; }
- bool visit(TypeArgument *) override { return true; }
- bool visit(TypeAnnotation *) override { return true; }
-
- // overridden to use BasicVisitor (and ensure warnings about new added AST)
- void endVisit(UiProgram *) override { }
- void endVisit(UiImport *) override { }
- void endVisit(UiHeaderItemList *) override { }
- void endVisit(UiPragma *) override { }
- void endVisit(UiPublicMember *) override { }
- void endVisit(UiSourceElement *) override { }
- void endVisit(UiObjectDefinition *) override { }
- void endVisit(UiObjectInitializer *) override { }
- void endVisit(UiObjectBinding *) override { }
- void endVisit(UiScriptBinding *) override { }
- void endVisit(UiArrayBinding *) override { }
- void endVisit(UiParameterList *) override { }
- void endVisit(UiObjectMemberList *) override { }
- void endVisit(UiArrayMemberList *) override { }
- void endVisit(UiQualifiedId *) override { }
- void endVisit(UiEnumDeclaration *) override { }
- void endVisit(UiEnumMemberList *) override { }
- void endVisit(UiVersionSpecifier *) override { }
- void endVisit(UiInlineComponent *) override { }
- void endVisit(UiAnnotation *) override { }
- void endVisit(UiAnnotationList *) override { }
- void endVisit(UiRequired *) override { }
- void endVisit(TypeExpression *) override { }
- void endVisit(ThisExpression *) override { }
- void endVisit(IdentifierExpression *) override { }
- void endVisit(NullExpression *) override { }
- void endVisit(TrueLiteral *) override { }
- void endVisit(FalseLiteral *) override { }
- void endVisit(SuperLiteral *) override { }
- void endVisit(StringLiteral *) override { }
- void endVisit(TemplateLiteral *) override { }
- void endVisit(NumericLiteral *) override { }
- void endVisit(RegExpLiteral *) override { }
- void endVisit(ArrayPattern *) override { }
- void endVisit(ObjectPattern *) override { }
- void endVisit(PatternElementList *) override { }
- void endVisit(PatternPropertyList *) override { }
- void endVisit(PatternElement *) override { }
- void endVisit(PatternProperty *) override { }
- void endVisit(Elision *) override { }
- void endVisit(NestedExpression *) override { }
- void endVisit(IdentifierPropertyName *) override { }
- void endVisit(StringLiteralPropertyName *) override { }
- void endVisit(NumericLiteralPropertyName *) override { }
- void endVisit(ComputedPropertyName *) override { out("]"); }
- void endVisit(ArrayMemberExpression *) override { }
- void endVisit(FieldMemberExpression *) override { }
- void endVisit(TaggedTemplate *) override { }
- void endVisit(NewMemberExpression *) override { }
- void endVisit(NewExpression *) override { }
- void endVisit(CallExpression *) override { }
- void endVisit(ArgumentList *) override { }
- void endVisit(PostIncrementExpression *) override { }
- void endVisit(PostDecrementExpression *) override { }
- void endVisit(DeleteExpression *) override { }
- void endVisit(VoidExpression *) override { }
- void endVisit(TypeOfExpression *) override { }
- void endVisit(PreIncrementExpression *) override { }
- void endVisit(PreDecrementExpression *) override { }
- void endVisit(UnaryPlusExpression *) override { }
- void endVisit(UnaryMinusExpression *) override { }
- void endVisit(TildeExpression *) override { }
- void endVisit(NotExpression *) override { }
- void endVisit(BinaryExpression *) override { }
- void endVisit(ConditionalExpression *) override { }
- void endVisit(Expression *) override { }
- void endVisit(Block *) override { }
- void endVisit(StatementList *) override { }
- void endVisit(VariableStatement *) override { }
- void endVisit(VariableDeclarationList *) override { }
- void endVisit(EmptyStatement *) override { }
- void endVisit(ExpressionStatement *) override { }
- void endVisit(IfStatement *) override { }
- void endVisit(DoWhileStatement *) override { }
- void endVisit(WhileStatement *) override { }
- void endVisit(ForStatement *) override { }
- void endVisit(ForEachStatement *) override { }
- void endVisit(ContinueStatement *) override { }
- void endVisit(BreakStatement *) override { }
- void endVisit(ReturnStatement *) override { }
- void endVisit(YieldExpression *) override { }
- void endVisit(WithStatement *) override { }
- void endVisit(SwitchStatement *) override { }
- void endVisit(CaseBlock *) override { }
- void endVisit(CaseClauses *) override { }
- void endVisit(CaseClause *) override { }
- void endVisit(DefaultClause *) override { }
- void endVisit(LabelledStatement *) override { }
- void endVisit(ThrowStatement *) override { }
- void endVisit(TryStatement *) override { }
- void endVisit(Catch *) override { }
- void endVisit(Finally *) override { }
- void endVisit(FunctionDeclaration *) override { }
- void endVisit(FunctionExpression *) override { }
- void endVisit(FormalParameterList *) override { }
- void endVisit(ClassExpression *) override { }
- void endVisit(ClassDeclaration *) override { }
- void endVisit(ClassElementList *) override { }
- void endVisit(Program *) override { }
- void endVisit(NameSpaceImport *) override { }
- void endVisit(ImportSpecifier *) override { }
- void endVisit(ImportsList *) override { }
- void endVisit(NamedImports *) override { }
- void endVisit(FromClause *) override { }
- void endVisit(ImportClause *) override { }
- void endVisit(ImportDeclaration *) override { }
- void endVisit(ExportSpecifier *) override { }
- void endVisit(ExportsList *) override { }
- void endVisit(ExportClause *) override { }
- void endVisit(ExportDeclaration *) override { }
- void endVisit(ESModule *) override { }
- void endVisit(DebuggerStatement *) override { }
- void endVisit(Type *) override { }
- void endVisit(TypeArgument *) override { }
- void endVisit(TypeAnnotation *) override { }
-
- void throwRecursionDepthError() override
- {
- out("/* ERROR: Hit recursion limit visiting AST, rewrite failed */");
+void ScriptFormatter::endVisit(AST::NamedImports *ast)
+{
+ if (ast->importsList) {
+ lw.space();
}
-};
+ out(ast->rightBraceToken);
+}
+
+void ScriptFormatter::endVisit(AST::ImportDeclaration *)
+{
+ out(";");
+}
+
+void ScriptFormatter::throwRecursionDepthError()
+{
+ out("/* ERROR: Hit recursion limit ScriptFormatter::visiting AST, rewrite failed */");
+}
-void reformatAst(OutWriter &lw, std::shared_ptr<AstComments> comments,
- const std::function<QStringView(SourceLocation)> loc2Str, AST::Node *n)
+void reformatAst(OutWriter &lw, const std::shared_ptr<AstComments> &comments,
+ const std::function<QStringView(SourceLocation)> &loc2Str, AST::Node *n)
{
if (n) {
- Rewriter rewriter(lw, comments, loc2Str, n);
+ ScriptFormatter formatter(lw, comments, loc2Str, n);
}
}
diff --git a/src/qmldom/qqmldomreformatter_p.h b/src/qmldom/qqmldomreformatter_p.h
index 4ff0d39ee0..48e2c63881 100644
--- a/src/qmldom/qqmldomreformatter_p.h
+++ b/src/qmldom/qqmldomreformatter_p.h
@@ -27,9 +27,193 @@ QT_BEGIN_NAMESPACE
namespace QQmlJS {
namespace Dom {
-QMLDOM_EXPORT void reformatAst(OutWriter &lw, std::shared_ptr<AstComments> comments,
- const std::function<QStringView(SourceLocation)> loc2Str,
- AST::Node *n);
+class ScriptFormatter final : protected AST::JSVisitor
+{
+public:
+ // TODO QTBUG-121988
+ ScriptFormatter(OutWriter &lw, const std::shared_ptr<AstComments> &comments,
+ const std::function<QStringView(SourceLocation)> &loc2Str, AST::Node *node)
+ : lw(lw), comments(comments), loc2Str(loc2Str)
+ {
+ accept(node);
+ }
+
+protected:
+ inline void out(const char *str) { lw.write(QString::fromLatin1(str)); }
+ inline void out(QStringView str) { lw.write(str); }
+ inline void out(const SourceLocation &loc)
+ {
+ if (loc.length != 0)
+ out(loc2Str(loc));
+ }
+ inline void newLine(quint32 count = 1) { lw.ensureNewline(count); }
+
+ inline void accept(AST::Node *node) { AST::Node::accept(node, this); }
+ void lnAcceptIndented(AST::Node *node);
+ bool acceptBlockOrIndented(AST::Node *ast, bool finishWithSpaceOrNewline = false);
+
+ bool preVisit(AST::Node *n) override;
+ void postVisit(AST::Node *n) override;
+
+ bool visit(AST::ThisExpression *ast) override;
+ bool visit(AST::NullExpression *ast) override;
+ bool visit(AST::TrueLiteral *ast) override;
+ bool visit(AST::FalseLiteral *ast) override;
+ bool visit(AST::IdentifierExpression *ast) override;
+ bool visit(AST::StringLiteral *ast) override;
+ bool visit(AST::NumericLiteral *ast) override;
+ bool visit(AST::RegExpLiteral *ast) override;
+
+ bool visit(AST::ArrayPattern *ast) override;
+
+ bool visit(AST::ObjectPattern *ast) override;
+
+ bool visit(AST::PatternElementList *ast) override;
+
+ bool visit(AST::PatternPropertyList *ast) override;
+ bool visit(AST::PatternProperty *property) override;
+
+ bool visit(AST::NestedExpression *ast) override;
+ bool visit(AST::IdentifierPropertyName *ast) override;
+ bool visit(AST::StringLiteralPropertyName *ast) override;
+ bool visit(AST::NumericLiteralPropertyName *ast) override;
+
+ bool visit(AST::TemplateLiteral *ast) override;
+ bool visit(AST::ArrayMemberExpression *ast) override;
+
+ bool visit(AST::FieldMemberExpression *ast) override;
+
+ bool visit(AST::NewMemberExpression *ast) override;
+
+ bool visit(AST::NewExpression *ast) override;
+
+ bool visit(AST::CallExpression *ast) override;
+
+ bool visit(AST::PostIncrementExpression *ast) override;
+
+ bool visit(AST::PostDecrementExpression *ast) override;
+ bool visit(AST::PreIncrementExpression *ast) override;
+
+ bool visit(AST::PreDecrementExpression *ast) override;
+
+ bool visit(AST::DeleteExpression *ast) override;
+
+ bool visit(AST::VoidExpression *ast) override;
+ bool visit(AST::TypeOfExpression *ast) override;
+
+ bool visit(AST::UnaryPlusExpression *ast) override;
+
+ bool visit(AST::UnaryMinusExpression *ast) override;
+
+ bool visit(AST::TildeExpression *ast) override;
+
+ bool visit(AST::NotExpression *ast) override;
+
+ bool visit(AST::BinaryExpression *ast) override;
+
+ bool visit(AST::ConditionalExpression *ast) override;
+
+ bool visit(AST::Block *ast) override;
+
+ bool visit(AST::VariableStatement *ast) override;
+
+ bool visit(AST::PatternElement *ast) override;
+
+ bool visit(AST::EmptyStatement *ast) override;
+
+ bool visit(AST::IfStatement *ast) override;
+ bool visit(AST::DoWhileStatement *ast) override;
+
+ bool visit(AST::WhileStatement *ast) override;
+
+ bool visit(AST::ForStatement *ast) override;
+
+ bool visit(AST::ForEachStatement *ast) override;
+
+ bool visit(AST::ContinueStatement *ast) override;
+ bool visit(AST::BreakStatement *ast) override;
+
+ bool visit(AST::ReturnStatement *ast) override;
+ bool visit(AST::YieldExpression *ast) override;
+ bool visit(AST::ThrowStatement *ast) override;
+ bool visit(AST::WithStatement *ast) override;
+
+ bool visit(AST::SwitchStatement *ast) override;
+
+ bool visit(AST::CaseBlock *ast) override;
+
+ bool visit(AST::CaseClause *ast) override;
+
+ bool visit(AST::DefaultClause *ast) override;
+
+ bool visit(AST::LabelledStatement *ast) override;
+
+ bool visit(AST::TryStatement *ast) override;
+
+ bool visit(AST::Catch *ast) override;
+
+ bool visit(AST::Finally *ast) override;
+
+ bool visit(AST::FunctionDeclaration *ast) override;
+
+ bool visit(AST::FunctionExpression *ast) override;
+
+ bool visit(AST::Elision *ast) override;
+
+ bool visit(AST::ArgumentList *ast) override;
+
+ bool visit(AST::StatementList *ast) override;
+
+ bool visit(AST::VariableDeclarationList *ast) override;
+
+ bool visit(AST::CaseClauses *ast) override;
+
+ bool visit(AST::FormalParameterList *ast) override;
+
+ bool visit(AST::SuperLiteral *) override;
+ bool visit(AST::ComputedPropertyName *) override;
+ bool visit(AST::Expression *el) override;
+ bool visit(AST::ExpressionStatement *el) override;
+
+ bool visit(AST::ClassDeclaration *ast) override;
+
+ bool visit(AST::ImportDeclaration *ast) override;
+ bool visit(AST::ImportSpecifier *ast) override;
+ bool visit(AST::NameSpaceImport *ast) override;
+ bool visit(AST::ImportsList *ast) override;
+ bool visit(AST::NamedImports *ast) override;
+ bool visit(AST::ImportClause *ast) override;
+
+ bool visit(AST::ExportDeclaration *ast) override;
+ bool visit(AST::ExportClause *ast) override;
+ bool visit(AST::ExportSpecifier *ast) override;
+ bool visit(AST::ExportsList *ast) override;
+
+ bool visit(AST::FromClause *ast) override;
+
+ void endVisit(AST::ComputedPropertyName *) override;
+
+ void endVisit(AST::ExportDeclaration *ast) override;
+ void endVisit(AST::ExportClause *ast) override;
+
+ void endVisit(AST::ImportDeclaration *ast) override;
+ void endVisit(AST::NamedImports *ast) override;
+
+ void throwRecursionDepthError() override;
+
+private:
+ bool addSemicolons() const { return expressionDepth > 0; }
+
+ OutWriter &lw;
+ std::shared_ptr<AstComments> comments;
+ std::function<QStringView(SourceLocation)> loc2Str;
+ QHash<AST::Node *, QList<std::function<void()>>> postOps;
+ int expressionDepth = 0;
+};
+
+QMLDOM_EXPORT void reformatAst(
+ OutWriter &lw, const std::shared_ptr<AstComments> &comments,
+ const std::function<QStringView(SourceLocation)> &loc2Str, AST::Node *n);
} // namespace Dom
} // namespace QQmlJS
diff --git a/src/qmldom/qqmldomscanner.cpp b/src/qmldom/qqmldomscanner.cpp
index f73a1b1a5a..84cd591fb0 100644
--- a/src/qmldom/qqmldomscanner.cpp
+++ b/src/qmldom/qqmldomscanner.cpp
@@ -375,7 +375,7 @@ bool Token::lexKindIsInvalid(int kind)
return false;
}
-void Token::dump(Sink s, QStringView line) const
+void Token::dump(const Sink &s, QStringView line) const
{
s(u"{");
sinkInt(s, offset);
diff --git a/src/qmldom/qqmldomscanner_p.h b/src/qmldom/qqmldomscanner_p.h
index 45141033b4..5ff1c5b767 100644
--- a/src/qmldom/qqmldomscanner_p.h
+++ b/src/qmldom/qqmldomscanner_p.h
@@ -44,10 +44,10 @@ public:
inline Token(int o, int l, int lexKind) : offset(o), length(l), lexKind(lexKind) { }
inline int begin() const { return offset; }
inline int end() const { return offset + length; }
- void dump(Sink s, QStringView line = QStringView()) const;
+ void dump(const Sink &s, QStringView line = QStringView()) const;
QString toString(QStringView line = QStringView()) const
{
- return dumperToString([line, this](Sink s) { this->dump(s, line); });
+ return dumperToString([line, this](const Sink &s) { this->dump(s, line); });
}
static int compare(const Token &t1, const Token &t2)
diff --git a/src/qmldom/qqmldomscriptelements.cpp b/src/qmldom/qqmldomscriptelements.cpp
new file mode 100644
index 0000000000..c0a48e0ce3
--- /dev/null
+++ b/src/qmldom/qqmldomscriptelements.cpp
@@ -0,0 +1,358 @@
+// 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);
+ }
+ for (auto it = m_values.begin(); it != m_values.end(); ++it) {
+ cont &= self.dvValueField(visitor, it->first, 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);
+ }
+ }
+ }
+}
diff --git a/src/qmldom/qqmldomscriptelements_p.h b/src/qmldom/qqmldomscriptelements_p.h
new file mode 100644
index 0000000000..98d863f14e
--- /dev/null
+++ b/src/qmldom/qqmldomscriptelements_p.h
@@ -0,0 +1,423 @@
+// 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
+
+#ifndef QQMLDOMSCRIPTELEMENTS_P_H
+#define QQMLDOMSCRIPTELEMENTS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qqmldomitem_p.h"
+#include "qqmldomelements_p.h"
+#include "qqmldomattachedinfo_p.h"
+#include "qqmldompath_p.h"
+#include <algorithm>
+#include <limits>
+#include <type_traits>
+#include <utility>
+#include <variant>
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+namespace Dom {
+
+namespace ScriptElements {
+
+template<DomType type>
+class ScriptElementBase : public ScriptElement
+{
+public:
+ using BaseT = ScriptElementBase<type>;
+ static constexpr DomType kindValue = type;
+ static constexpr DomKind domKindValue = DomKind::ScriptElement;
+
+ ScriptElementBase(QQmlJS::SourceLocation combinedLocation = QQmlJS::SourceLocation{})
+ : ScriptElement(), m_locations({ { FileLocationRegion::MainRegion, combinedLocation } })
+ {
+ }
+ ScriptElementBase(QQmlJS::SourceLocation first, QQmlJS::SourceLocation last)
+ : ScriptElementBase(combine(first, last))
+ {
+ }
+ DomType kind() const override { return type; }
+ DomKind domKind() const override { return domKindValue; }
+
+ void createFileLocations(const FileLocations::Tree &base) override
+ {
+ FileLocations::Tree res =
+ FileLocations::ensure(base, pathFromOwner(), AttachedInfo::PathType::Relative);
+ for (auto location: m_locations) {
+ FileLocations::addRegion(res, location.first, location.second);
+ }
+ }
+
+ /*
+ Pretty prints the current DomItem. Currently, for script elements, this is done entirely on
+ the parser representation (via the AST classes), but it could be moved here if needed.
+ */
+ // void writeOut(const DomItem &self, OutWriter &lw) const override;
+
+ /*!
+ All of the following overloads are only required for optimization purposes.
+ The base implementation will work fine, but might be slightly slower.
+ You can override dump(), fields(), field(), indexes(), index(), keys() or key() if the
+ performance of the base class becomes problematic.
+ */
+
+ // // needed for debug
+ // void dump(const DomItem &, const Sink &sink, int indent, FilterT filter) const override;
+
+ // // just required for optimization if iterateDirectSubpaths is slow
+ // QList<QString> fields(const DomItem &self) const override;
+ // DomItem field(const DomItem &self, QStringView name) const override;
+
+ // index_type indexes(const DomItem &self) const override;
+ // DomItem index(const DomItem &self, index_type index) const override;
+
+ // QSet<QString> const keys(const DomItem &self) const override;
+ // DomItem key(const DomItem &self, const QString &name) const override;
+
+ QQmlJS::SourceLocation mainRegionLocation() const
+ {
+ Q_ASSERT(m_locations.size() > 0);
+ Q_ASSERT(m_locations.front().first == FileLocationRegion::MainRegion);
+
+ auto current = m_locations.front();
+ return current.second;
+ }
+ void setMainRegionLocation(const QQmlJS::SourceLocation &location)
+ {
+ Q_ASSERT(m_locations.size() > 0);
+ Q_ASSERT(m_locations.front().first == FileLocationRegion::MainRegion);
+
+ m_locations.front().second = location;
+ }
+ void addLocation(FileLocationRegion region, QQmlJS::SourceLocation location)
+ {
+ Q_ASSERT_X(region != FileLocationRegion::MainRegion, "ScriptElementBase::addLocation",
+ "use the setCombinedLocation instead!");
+ m_locations.emplace_back(region, location);
+ }
+
+protected:
+ std::vector<std::pair<FileLocationRegion, QQmlJS::SourceLocation>> m_locations;
+};
+
+class ScriptList : public ScriptElementBase<DomType::List>
+{
+public:
+ using typename ScriptElementBase<DomType::List>::BaseT;
+
+ using BaseT::BaseT;
+
+ // minimal required overload for this to be wrapped as DomItem:
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override
+ {
+ bool cont =
+ asList(self.pathFromOwner().key(QString())).iterateDirectSubpaths(self, visitor);
+ return cont;
+ }
+ void updatePathFromOwner(const Path &p) override
+ {
+ BaseT::updatePathFromOwner(p);
+ for (int i = 0; i < m_list.size(); ++i) {
+ Q_ASSERT(m_list[i].base());
+ m_list[i].base()->updatePathFromOwner(p.index(i));
+ }
+ }
+ void createFileLocations(const FileLocations::Tree &base) override
+ {
+ BaseT::createFileLocations(base);
+
+ for (int i = 0; i < m_list.size(); ++i) {
+ Q_ASSERT(m_list[i].base());
+ m_list[i].base()->createFileLocations(base);
+ }
+ }
+
+ List asList(const Path &path) const
+ {
+ auto asList = List::fromQList<ScriptElementVariant>(
+ path, m_list,
+ [](const DomItem &list, const PathEls::PathComponent &, const ScriptElementVariant &wrapped)
+ -> DomItem { return list.subScriptElementWrapperItem(wrapped); });
+
+ return asList;
+ }
+
+ void append(const ScriptElementVariant &statement) { m_list.push_back(statement); }
+ void append(const ScriptList &list) { m_list.append(list.m_list); }
+ void reverse() { std::reverse(m_list.begin(), m_list.end()); }
+ void replaceKindForGenericChildren(DomType oldType, DomType newType);
+ const QList<ScriptElementVariant> &qList() { return std::as_const(m_list); };
+
+private:
+ QList<ScriptElementVariant> m_list;
+};
+
+class GenericScriptElement : public ScriptElementBase<DomType::ScriptGenericElement>
+{
+public:
+ using BaseT::BaseT;
+ using VariantT = std::variant<ScriptElementVariant, ScriptList>;
+
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override;
+ void updatePathFromOwner(const Path &p) override;
+ void createFileLocations(const FileLocations::Tree &base) override;
+
+ DomType kind() const override { return m_kind; }
+ void setKind(DomType kind) { m_kind = kind; }
+
+ decltype(auto) insertChild(QStringView name, VariantT v)
+ {
+ return m_children.insert(std::make_pair(name, v));
+ }
+
+ ScriptElementVariant elementChild(const QQmlJS::Dom::FieldType &field)
+ {
+ auto it = m_children.find(field);
+ if (it == m_children.end())
+ return {};
+ if (!std::holds_alternative<ScriptElementVariant>(it->second))
+ return {};
+ return std::get<ScriptElementVariant>(it->second);
+ }
+
+ void insertValue(QStringView name, const QCborValue &v)
+ {
+ m_values.insert(std::make_pair(name, v));
+ }
+
+private:
+ /*!
+ \internal
+ The DomItem interface will use iterateDirectSubpaths for all kinds of operations on the
+ GenericScriptElement. Therefore, to avoid bad surprises when using the DomItem interface, use
+ a sorted map to always iterate the children in the same order.
+ */
+ std::map<QQmlJS::Dom::FieldType, VariantT> m_children;
+ // value fields
+ std::map<QQmlJS::Dom::FieldType, QCborValue> m_values;
+ DomType m_kind = DomType::Empty;
+};
+
+class BlockStatement : public ScriptElementBase<DomType::ScriptBlockStatement>
+{
+public:
+ using BaseT::BaseT;
+
+ // minimal required overload for this to be wrapped as DomItem:
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override;
+ void updatePathFromOwner(const Path &p) override;
+ void createFileLocations(const FileLocations::Tree &base) override;
+
+ ScriptList statements() const { return m_statements; }
+ void setStatements(const ScriptList &statements) { m_statements = statements; }
+
+private:
+ ScriptList m_statements;
+};
+
+class IdentifierExpression : public ScriptElementBase<DomType::ScriptIdentifierExpression>
+{
+public:
+ using BaseT::BaseT;
+ void setName(QStringView name) { m_name = name.toString(); }
+ QString name() { return m_name; }
+
+ // minimal required overload for this to be wrapped as DomItem:
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override;
+
+ QCborValue value() const override { return QCborValue(m_name); }
+
+private:
+ QString m_name;
+};
+
+class Literal : public ScriptElementBase<DomType::ScriptLiteral>
+{
+public:
+ using BaseT::BaseT;
+
+ using VariantT = std::variant<QString, double, bool, std::nullptr_t>;
+
+ void setLiteralValue(VariantT value) { m_value = value; }
+ VariantT literalValue() const { return m_value; }
+
+ // minimal required overload for this to be wrapped as DomItem:
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override;
+
+ QCborValue value() const override
+ {
+ return std::visit([](auto &&e) -> QCborValue { return e; }, m_value);
+ }
+
+private:
+ VariantT m_value;
+};
+
+// TODO: test this method + implement foreach etc
+class ForStatement : public ScriptElementBase<DomType::ScriptForStatement>
+{
+public:
+ using BaseT::BaseT;
+
+ // minimal required overload for this to be wrapped as DomItem:
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override;
+ void updatePathFromOwner(const Path &p) override;
+ void createFileLocations(const FileLocations::Tree &base) override;
+
+ ScriptElementVariant initializer() const { return m_initializer; }
+ void setInitializer(const ScriptElementVariant &newInitializer)
+ {
+ m_initializer = newInitializer;
+ }
+
+ ScriptElementVariant declarations() const { return m_declarations; }
+ void setDeclarations(const ScriptElementVariant &newDeclaration)
+ {
+ m_declarations = newDeclaration;
+ }
+ ScriptElementVariant condition() const { return m_condition; }
+ void setCondition(const ScriptElementVariant &newCondition) { m_condition = newCondition; }
+ ScriptElementVariant expression() const { return m_expression; }
+ void setExpression(const ScriptElementVariant &newExpression) { m_expression = newExpression; }
+ ScriptElementVariant body() const { return m_body; }
+ void setBody(const ScriptElementVariant &newBody) { m_body = newBody; }
+
+private:
+ ScriptElementVariant m_initializer;
+ ScriptElementVariant m_declarations;
+ ScriptElementVariant m_condition;
+ ScriptElementVariant m_expression;
+ ScriptElementVariant m_body;
+};
+
+class IfStatement : public ScriptElementBase<DomType::ScriptIfStatement>
+{
+public:
+ using BaseT::BaseT;
+
+ // minimal required overload for this to be wrapped as DomItem:
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override;
+ void updatePathFromOwner(const Path &p) override;
+ void createFileLocations(const FileLocations::Tree &base) override;
+
+ ScriptElementVariant condition() const { return m_condition; }
+ void setCondition(const ScriptElementVariant &condition) { m_condition = condition; }
+ ScriptElementVariant consequence() { return m_consequence; }
+ void setConsequence(const ScriptElementVariant &consequence) { m_consequence = consequence; }
+ ScriptElementVariant alternative() { return m_alternative; }
+ void setAlternative(const ScriptElementVariant &alternative) { m_alternative = alternative; }
+
+private:
+ ScriptElementVariant m_condition;
+ ScriptElementVariant m_consequence;
+ ScriptElementVariant m_alternative;
+};
+
+class ReturnStatement : public ScriptElementBase<DomType::ScriptReturnStatement>
+{
+public:
+ using BaseT::BaseT;
+
+ // minimal required overload for this to be wrapped as DomItem:
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override;
+ void updatePathFromOwner(const Path &p) override;
+ void createFileLocations(const FileLocations::Tree &base) override;
+
+ ScriptElementVariant expression() const { return m_expression; }
+ void setExpression(ScriptElementVariant expression) { m_expression = expression; }
+
+private:
+ ScriptElementVariant m_expression;
+};
+
+class BinaryExpression : public ScriptElementBase<DomType::ScriptBinaryExpression>
+{
+public:
+ using BaseT::BaseT;
+
+ enum Operator : char {
+ FieldMemberAccess,
+ ArrayMemberAccess,
+ TO_BE_IMPLEMENTED = std::numeric_limits<char>::max(), // not required by qmlls
+ };
+
+ // minimal required overload for this to be wrapped as DomItem:
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override;
+ void updatePathFromOwner(const Path &p) override;
+ void createFileLocations(const FileLocations::Tree &base) override;
+
+ ScriptElementVariant left() const { return m_left; }
+ void setLeft(const ScriptElementVariant &newLeft) { m_left = newLeft; }
+ ScriptElementVariant right() const { return m_right; }
+ void setRight(const ScriptElementVariant &newRight) { m_right = newRight; }
+ int op() const { return m_operator; }
+ void setOp(Operator op) { m_operator = op; }
+
+private:
+ ScriptElementVariant m_left;
+ ScriptElementVariant m_right;
+ Operator m_operator = TO_BE_IMPLEMENTED;
+};
+
+class VariableDeclarationEntry : public ScriptElementBase<DomType::ScriptVariableDeclarationEntry>
+{
+public:
+ using BaseT::BaseT;
+
+ enum ScopeType { Var, Let, Const };
+
+ ScopeType scopeType() const { return m_scopeType; }
+ void setScopeType(ScopeType scopeType) { m_scopeType = scopeType; }
+
+ ScriptElementVariant identifier() const { return m_identifier; }
+ void setIdentifier(const ScriptElementVariant &identifier) { m_identifier = identifier; }
+
+ ScriptElementVariant initializer() const { return m_initializer; }
+ void setInitializer(const ScriptElementVariant &initializer) { m_initializer = initializer; }
+
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override;
+ void updatePathFromOwner(const Path &p) override;
+ void createFileLocations(const FileLocations::Tree &base) override;
+
+private:
+ ScopeType m_scopeType;
+ ScriptElementVariant m_identifier;
+ ScriptElementVariant m_initializer;
+};
+
+class VariableDeclaration : public ScriptElementBase<DomType::ScriptVariableDeclaration>
+{
+public:
+ using BaseT::BaseT;
+
+ // minimal required overload for this to be wrapped as DomItem:
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override;
+ void updatePathFromOwner(const Path &p) override;
+ void createFileLocations(const FileLocations::Tree &base) override;
+
+ void setDeclarations(const ScriptList &list) { m_declarations = list; }
+ ScriptList declarations() { return m_declarations; }
+
+private:
+ ScriptList m_declarations;
+};
+
+} // namespace ScriptElements
+} // end namespace Dom
+} // end namespace QQmlJS
+
+QT_END_NAMESPACE
+
+#endif // QQMLDOMSCRIPTELEMENTS_P_H
diff --git a/src/qmldom/qqmldomstringdumper.cpp b/src/qmldom/qqmldomstringdumper.cpp
index 081a6abf81..4859614f77 100644
--- a/src/qmldom/qqmldomstringdumper.cpp
+++ b/src/qmldom/qqmldomstringdumper.cpp
@@ -43,7 +43,7 @@ namespace Dom {
* \brief Converts a dumper to a string
* \param writer The dumper convert to a string
*/
-QString dumperToString(Dumper writer)
+QString dumperToString(const Dumper &writer)
{
QString s;
QTextStream d(&s);
@@ -59,7 +59,7 @@ QString dumperToString(Dumper writer)
* \param s The string to sink
* \param options If quotes should be outputted around the string (defaults to yes)
*/
-void sinkEscaped(Sink sink, QStringView s, EscapeOptions options) {
+void sinkEscaped(const Sink &sink, QStringView s, EscapeOptions options) {
if (options == EscapeOptions::OuterQuotes)
sink(u"\"");
int it0=0;
@@ -95,7 +95,7 @@ void sinkEscaped(Sink sink, QStringView s, EscapeOptions options) {
* \param s the sink to write to
* \param level the level to describe
*/
-void dumpErrorLevel(Sink s, ErrorLevel level)
+void dumpErrorLevel(const Sink &s, ErrorLevel level)
{
switch (level) {
case ErrorLevel::Debug:
@@ -117,7 +117,7 @@ void dumpErrorLevel(Sink s, ErrorLevel level)
}
-void dumperToQDebug(Dumper dumper, QDebug debug)
+void dumperToQDebug(const Dumper &dumper, QDebug debug)
{
QDebug & d = debug.noquote().nospace();
dumper([&d](QStringView s){
@@ -131,7 +131,7 @@ void dumperToQDebug(Dumper dumper, QDebug debug)
* \param level the error level of the message
* \param dumper the dumper that writes a message
*/
-void dumperToQDebug(Dumper dumper, ErrorLevel level)
+void dumperToQDebug(const Dumper &dumper, ErrorLevel level)
{
QDebug d = qDebug().noquote().nospace();
switch (level) {
@@ -157,7 +157,7 @@ void dumperToQDebug(Dumper dumper, ErrorLevel level)
* \internal
* \brief sinks the requested amount of spaces
*/
-void sinkIndent(Sink s, int indent)
+void sinkIndent(const Sink &s, int indent)
{
if (indent > 0) {
QStringView spaces = u" ";
@@ -173,7 +173,7 @@ void sinkIndent(Sink s, int indent)
* \internal
* \brief sinks a neline and indents by the given amount
*/
-void sinkNewline(Sink s, int indent)
+void sinkNewline(const Sink &s, int indent)
{
s(u"\n");
if (indent > 0)
@@ -186,7 +186,7 @@ void sinkNewline(Sink s, int indent)
* \brief A sink that ignores whatever it receives
*/
-QDebug operator<<(QDebug d, Dumper dumper)
+QDebug operator<<(QDebug d, const Dumper &dumper)
{
QDebug dd = d.noquote().nospace();
dumper([&dd](QStringView s) { dd << s; });
diff --git a/src/qmldom/qqmldomstringdumper_p.h b/src/qmldom/qqmldomstringdumper_p.h
index 5f1a633809..cf5c8e6483 100644
--- a/src/qmldom/qqmldomstringdumper_p.h
+++ b/src/qmldom/qqmldomstringdumper_p.h
@@ -32,7 +32,7 @@ namespace Dom {
using Sink = function_ref<void(QStringView)>;
using SinkF = std::function<void(QStringView)>;
-using DumperFunction = std::function<void(Sink)>;
+using DumperFunction = std::function<void(const Sink &)>;
class Dumper{
public:
@@ -43,7 +43,7 @@ private:
// would be the second user defined conversion.
// For a similar reason we have a template to accept function_ref<void(Sink)> .
// The end result is that void f(Dumper) can be called nicely, and avoid overloads:
- // f(u"bla"), f(QLatin1String("bla")), f(QString()), f([](Sink s){...}),...
+ // f(u"bla"), f(QLatin1String("bla")), f(QString()), f([](const Sink &s){...}),...
template <typename T>
using if_compatible_dumper = typename
std::enable_if<std::is_convertible<T, DumperFunction>::value, bool>::type;
@@ -54,7 +54,7 @@ private:
public:
Dumper(QStringView s):
- dumper([s](Sink sink){ sink(s); }) {}
+ dumper([s](const Sink &sink){ sink(s); }) {}
Dumper(std::nullptr_t): Dumper(QStringView(nullptr)) {}
@@ -63,13 +63,13 @@ public:
Dumper(QStringView(string)) {}
template <typename U, if_compatible_dumper<U> = true>
- Dumper(U f): dumper(f) {}
+ Dumper(U f): dumper(std::move(f)) {}
- void operator()(Sink s) { dumper(s); }
+ void operator()(const Sink &s) const { dumper(s); }
};
template <typename T>
-void sinkInt(Sink s, T i) {
+void sinkInt(const Sink &s, T i) {
const int BUFSIZE = 42; // safe up to 128 bits
QChar buf[BUFSIZE];
int ibuf = BUFSIZE;
@@ -96,24 +96,24 @@ void sinkInt(Sink s, T i) {
s(QStringView(&buf[ibuf], BUFSIZE - ibuf -1));
}
-QMLDOM_EXPORT QString dumperToString(Dumper writer);
+QMLDOM_EXPORT QString dumperToString(const Dumper &writer);
-QMLDOM_EXPORT void sinkEscaped(Sink sink, QStringView s,
+QMLDOM_EXPORT void sinkEscaped(const Sink &sink, QStringView s,
EscapeOptions options = EscapeOptions::OuterQuotes);
inline void devNull(QStringView) {}
-QMLDOM_EXPORT void sinkIndent(Sink s, int indent);
+QMLDOM_EXPORT void sinkIndent(const Sink &s, int indent);
-QMLDOM_EXPORT void sinkNewline(Sink s, int indent = 0);
+QMLDOM_EXPORT void sinkNewline(const Sink &s, int indent = 0);
-QMLDOM_EXPORT void dumpErrorLevel(Sink s, ErrorLevel level);
+QMLDOM_EXPORT void dumpErrorLevel(const Sink &s, ErrorLevel level);
-QMLDOM_EXPORT void dumperToQDebug(Dumper dumper, QDebug debug);
+QMLDOM_EXPORT void dumperToQDebug(const Dumper &dumper, QDebug debug);
-QMLDOM_EXPORT void dumperToQDebug(Dumper dumper, ErrorLevel level = ErrorLevel::Debug);
+QMLDOM_EXPORT void dumperToQDebug(const Dumper &dumper, ErrorLevel level = ErrorLevel::Debug);
-QMLDOM_EXPORT QDebug operator<<(QDebug d, Dumper dumper);
+QMLDOM_EXPORT QDebug operator<<(QDebug d, const Dumper &dumper);
} // end namespace Dom
} // end namespace QQmlJS
diff --git a/src/qmldom/qqmldomtop.cpp b/src/qmldom/qqmldomtop.cpp
index 4e82a01933..cfc20d50ef 100644
--- a/src/qmldom/qqmldomtop.cpp
+++ b/src/qmldom/qqmldomtop.cpp
@@ -1,6 +1,7 @@
// 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 "qqmldomitem_p.h"
#include "qqmldomtop_p.h"
#include "qqmldomexternalitems_p.h"
#include "qqmldommock_p.h"
@@ -8,6 +9,7 @@
#include "qqmldomastcreator_p.h"
#include "qqmldommoduleindex_p.h"
#include "qqmldomtypesreader_p.h"
+#include "qqmldom_utils_p.h"
#include <QtQml/private/qqmljslexer_p.h>
#include <QtQml/private/qqmljsparser_p.h>
@@ -53,21 +55,21 @@ using std::shared_ptr;
if force is true the file is always read
*/
-Path DomTop::canonicalPath(DomItem &) const
+Path DomTop::canonicalPath(const DomItem &) const
{
return canonicalPath();
}
-DomItem DomTop::containingObject(DomItem &) const
+DomItem DomTop::containingObject(const DomItem &) const
{
return DomItem();
}
-bool DomTop::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool DomTop::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
static QHash<QString, QString> knownFields;
static QBasicMutex m;
- auto toField = [](QString f) mutable -> QStringView {
+ auto toField = [](const QString &f) mutable -> QStringView {
QMutexLocker l(&m);
if (!knownFields.contains(f))
knownFields[f] = f;
@@ -119,11 +121,10 @@ ErrorGroups DomUniverse::myErrors()
return groups;
}
-DomUniverse::DomUniverse(QString universeName, Options options):
- m_name(universeName), m_options(options)
-{}
+DomUniverse::DomUniverse(const QString &universeName) : m_name(universeName) { }
-std::shared_ptr<DomUniverse> DomUniverse::guaranteeUniverse(std::shared_ptr<DomUniverse> univ)
+std::shared_ptr<DomUniverse> DomUniverse::guaranteeUniverse(
+ const std::shared_ptr<DomUniverse> &univ)
{
const auto next = [] {
Q_CONSTINIT static std::atomic<int> counter(0);
@@ -136,9 +137,9 @@ std::shared_ptr<DomUniverse> DomUniverse::guaranteeUniverse(std::shared_ptr<DomU
QLatin1String("universe") + QString::number(next()));
}
-DomItem DomUniverse::create(QString universeName, Options options)
+DomItem DomUniverse::create(const QString &universeName)
{
- auto res = std::make_shared<DomUniverse>(universeName, options);
+ auto res = std::make_shared<DomUniverse>(universeName);
return DomItem(res);
}
@@ -147,66 +148,51 @@ Path DomUniverse::canonicalPath() const
return Path::Root(u"universe");
}
-bool DomUniverse::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool DomUniverse::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = true;
cont = cont && DomTop::iterateDirectSubpaths(self, visitor);
cont = cont && self.dvValueField(visitor, Fields::name, name());
- cont = cont && self.dvValueField(visitor, Fields::options, int(options()));
cont = cont && self.dvItemField(visitor, Fields::globalScopeWithName, [this, &self]() {
return self.subMapItem(Map(
Path::Field(Fields::globalScopeWithName),
- [this](DomItem &map, QString key) { return map.copy(globalScopeWithName(key)); },
- [this](DomItem &) { return globalScopeNames(); }, QLatin1String("GlobalScope")));
+ [this](const DomItem &map, const QString &key) { return map.copy(globalScopeWithName(key)); },
+ [this](const DomItem &) { return globalScopeNames(); }, QLatin1String("GlobalScope")));
});
cont = cont && self.dvItemField(visitor, Fields::qmlDirectoryWithPath, [this, &self]() {
return self.subMapItem(Map(
Path::Field(Fields::qmlDirectoryWithPath),
- [this](DomItem &map, QString key) { return map.copy(qmlDirectoryWithPath(key)); },
- [this](DomItem &) { return qmlDirectoryPaths(); }, QLatin1String("QmlDirectory")));
+ [this](const DomItem &map, const QString &key) { return map.copy(qmlDirectoryWithPath(key)); },
+ [this](const DomItem &) { return qmlDirectoryPaths(); }, QLatin1String("QmlDirectory")));
});
cont = cont && self.dvItemField(visitor, Fields::qmldirFileWithPath, [this, &self]() {
return self.subMapItem(Map(
Path::Field(Fields::qmldirFileWithPath),
- [this](DomItem &map, QString key) { return map.copy(qmldirFileWithPath(key)); },
- [this](DomItem &) { return qmldirFilePaths(); }, QLatin1String("QmldirFile")));
+ [this](const DomItem &map, const QString &key) { return map.copy(qmldirFileWithPath(key)); },
+ [this](const DomItem &) { return qmldirFilePaths(); }, QLatin1String("QmldirFile")));
});
cont = cont && self.dvItemField(visitor, Fields::qmlFileWithPath, [this, &self]() {
return self.subMapItem(Map(
Path::Field(Fields::qmlFileWithPath),
- [this](DomItem &map, QString key) { return map.copy(qmlFileWithPath(key)); },
- [this](DomItem &) { return qmlFilePaths(); }, QLatin1String("QmlFile")));
+ [this](const DomItem &map, const QString &key) { return map.copy(qmlFileWithPath(key)); },
+ [this](const DomItem &) { return qmlFilePaths(); }, QLatin1String("QmlFile")));
});
cont = cont && self.dvItemField(visitor, Fields::jsFileWithPath, [this, &self]() {
return self.subMapItem(Map(
Path::Field(Fields::jsFileWithPath),
- [this](DomItem &map, QString key) { return map.copy(jsFileWithPath(key)); },
- [this](DomItem &) { return jsFilePaths(); }, QLatin1String("JsFile")));
+ [this](const DomItem &map, const QString &key) { return map.copy(jsFileWithPath(key)); },
+ [this](const DomItem &) { return jsFilePaths(); }, QLatin1String("JsFile")));
});
cont = cont && self.dvItemField(visitor, Fields::jsFileWithPath, [this, &self]() {
return self.subMapItem(Map(
Path::Field(Fields::qmltypesFileWithPath),
- [this](DomItem &map, QString key) { return map.copy(qmltypesFileWithPath(key)); },
- [this](DomItem &) { return qmltypesFilePaths(); }, QLatin1String("QmltypesFile")));
- });
- cont = cont && self.dvItemField(visitor, Fields::queue, [this, &self]() {
- QQueue<ParsingTask> q = queue();
- return self.subListItem(List(
- Path::Field(Fields::queue),
- [q](DomItem &list, index_type i) {
- if (i >= 0 && i < q.size())
- return list.subDataItem(PathEls::Index(i), q.at(i).toCbor(),
- ConstantData::Options::FirstMapIsFields);
- else
- return DomItem();
- },
- [q](DomItem &) { return index_type(q.size()); }, nullptr,
- QLatin1String("ParsingTask")));
+ [this](const DomItem &map, const QString &key) { return map.copy(qmltypesFileWithPath(key)); },
+ [this](const DomItem &) { return qmltypesFilePaths(); }, QLatin1String("QmltypesFile")));
});
return cont;
}
-std::shared_ptr<OwningItem> DomUniverse::doCopy(DomItem &) const
+std::shared_ptr<OwningItem> DomUniverse::doCopy(const DomItem &) const
{
QRegularExpression r(QRegularExpression::anchoredPattern(QLatin1String(R"(.*Copy([0-9]*)$)")));
auto m = r.match(m_name);
@@ -219,14 +205,7 @@ std::shared_ptr<OwningItem> DomUniverse::doCopy(DomItem &) const
return res;
}
-void DomUniverse::loadFile(DomItem &self, QString filePath, QString logicalPath, Callback callback,
- LoadOptions loadOptions, std::optional<DomType> fileType)
-{
- loadFile(self, filePath, logicalPath, QString(), QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
- callback, loadOptions, fileType);
-}
-
-static DomType fileTypeForPath(DomItem &self, QString canonicalFilePath)
+static DomType fileTypeForPath(const DomItem &self, const QString &canonicalFilePath)
{
if (canonicalFilePath.endsWith(u".qml", Qt::CaseInsensitive)
|| canonicalFilePath.endsWith(u".qmlannotation", Qt::CaseInsensitive)) {
@@ -236,12 +215,16 @@ static DomType fileTypeForPath(DomItem &self, QString canonicalFilePath)
} else if (QStringView(u"qmldir").compare(QFileInfo(canonicalFilePath).fileName(),
Qt::CaseInsensitive)
== 0) {
- return DomType::QmltypesFile;
+ return DomType::QmldirFile;
} else if (QFileInfo(canonicalFilePath).isDir()) {
return DomType::QmlDirectory;
- } else {
+ } else if (canonicalFilePath.endsWith(u".js", Qt::CaseInsensitive)
+ || canonicalFilePath.endsWith(u".mjs", Qt::CaseInsensitive)) {
+ return DomType::JsFile;
+ }
+ else {
self.addError(DomUniverse::myErrors()
- .error(QCoreApplication::translate("Dom::filteTypeForPath",
+ .error(QCoreApplication::translate("Dom::fileTypeForPath",
"Could not detect type of file %1")
.arg(canonicalFilePath))
.handle());
@@ -249,245 +232,120 @@ static DomType fileTypeForPath(DomItem &self, QString canonicalFilePath)
return DomType::Empty;
}
-void DomUniverse::loadFile(DomItem &self, QString canonicalFilePath, QString logicalPath,
- QString code, QDateTime codeDate, Callback callback,
- LoadOptions loadOptions, std::optional<DomType> fileType)
+DomUniverse::LoadResult DomUniverse::loadFile(const FileToLoad &file, DomType fileType,
+ DomCreationOptions creationOptions)
{
- DomType fType = (bool(fileType) ? (*fileType) : fileTypeForPath(self, canonicalFilePath));
- switch (fType) {
+ DomItem univ(shared_from_this());
+ switch (fileType) {
case DomType::QmlFile:
case DomType::QmltypesFile:
case DomType::QmldirFile:
- case DomType::QmlDirectory: {
- // Protect the queue from concurrent access.
- QMutexLocker l(mutex());
- m_queue.enqueue(ParsingTask{ QDateTime::currentDateTimeUtc(), loadOptions, fType,
- canonicalFilePath, logicalPath, code, codeDate,
- self.ownerAs<DomUniverse>(), callback });
- break;
+ case DomType::QmlDirectory:
+ case DomType::JsFile: {
+ LoadResult loadRes;
+ const auto &preLoadResult = preload(univ, file, fileType);
+ if (std::holds_alternative<LoadResult>(preLoadResult)) {
+ // universe already has the most recent version of the file
+ return std::get<LoadResult>(preLoadResult);
+ } else {
+ // content of the file needs to be parsed and value inside Universe needs to be updated
+ return load(std::get<ContentWithDate>(preLoadResult), file, fileType, creationOptions);
+ }
}
default:
- self.addError(myErrors()
+ univ.addError(myErrors()
.error(tr("Ignoring request to load file %1 of unexpected type %2, "
"calling callback immediately")
- .arg(canonicalFilePath, domTypeToString(fType)))
+ .arg(file.canonicalPath(), domTypeToString(fileType)))
.handle());
Q_ASSERT(false && "loading non supported file type");
- callback(Path(), DomItem::empty, DomItem::empty);
- return;
+ return {};
}
- if (m_options & Option::SingleThreaded)
- execQueue(); // immediate execution in the same thread
}
-template<typename T>
-QPair<std::shared_ptr<ExternalItemPair<T>>, std::shared_ptr<ExternalItemPair<T>>>
-updateEntry(DomItem &univ, std::shared_ptr<T> newItem,
- QMap<QString, std::shared_ptr<ExternalItemPair<T>>> &map, QBasicMutex *mutex)
-{
- std::shared_ptr<ExternalItemPair<T>> oldValue;
- std::shared_ptr<ExternalItemPair<T>> newValue;
- QString canonicalPath = newItem->canonicalFilePath();
- QDateTime now = QDateTime::currentDateTimeUtc();
- {
- QMutexLocker l(mutex);
- auto it = map.find(canonicalPath);
- if (it != map.cend() && (*it) && (*it)->current) {
- oldValue = *it;
- QString oldCode = oldValue->current->code();
- QString newCode = newItem->code();
- if (!oldCode.isNull() && !newCode.isNull() && oldCode == newCode) {
- newValue = oldValue;
- if (newValue->current->lastDataUpdateAt() < newItem->lastDataUpdateAt())
- newValue->current->refreshedDataAt(newItem->lastDataUpdateAt());
- } else if (oldValue->current->lastDataUpdateAt() > newItem->lastDataUpdateAt()) {
- newValue = oldValue;
- } else {
- DomItem oldValueObj = univ.copy(oldValue);
- newValue = oldValue->makeCopy(oldValueObj);
- newValue->current = newItem;
- newValue->currentExposedAt = now;
- if (newItem->isValid()) {
- newValue->valid = newItem;
- newValue->validExposedAt = now;
- }
- it = map.insert(it, canonicalPath, newValue);
- }
- } else {
- newValue = std::make_shared<ExternalItemPair<T>>(
- (newItem->isValid() ? newItem : std::shared_ptr<T>()), newItem, now, now);
- map.insert(canonicalPath, newValue);
- }
+DomUniverse::LoadResult DomUniverse::load(const ContentWithDate &codeWithDate,
+ const FileToLoad &file, DomType fType,
+ DomCreationOptions creationOptions)
+{
+ QString canonicalPath = file.canonicalPath();
+
+ DomItem oldValue; // old ExternalItemPair (might be empty, or equal to newValue)
+ DomItem newValue; // current ExternalItemPair
+ DomItem univ = DomItem(shared_from_this());
+
+ if (fType == DomType::QmlFile) {
+ auto qmlFile = parseQmlFile(codeWithDate.content, file, codeWithDate.date, creationOptions);
+ return insertOrUpdateExternalItem(std::move(qmlFile));
+ } else if (fType == DomType::QmltypesFile) {
+ auto qmltypesFile = std::make_shared<QmltypesFile>(canonicalPath, codeWithDate.content,
+ codeWithDate.date);
+ QmltypesReader reader(univ.copy(qmltypesFile));
+ reader.parse();
+ return insertOrUpdateExternalItem(std::move(qmltypesFile));
+ } else if (fType == DomType::QmldirFile) {
+ shared_ptr<QmldirFile> qmldirFile =
+ QmldirFile::fromPathAndCode(canonicalPath, codeWithDate.content);
+ return insertOrUpdateExternalItem(std::move(qmldirFile));
+ } else if (fType == DomType::QmlDirectory) {
+ auto qmlDirectory = std::make_shared<QmlDirectory>(
+ canonicalPath, codeWithDate.content.split(QLatin1Char('\n')), codeWithDate.date);
+ return insertOrUpdateExternalItem(std::move(qmlDirectory));
+ } else if (fType == DomType::JsFile) {
+ auto jsFile = parseJsFile(codeWithDate.content, file, codeWithDate.date);
+ return insertOrUpdateExternalItem(std::move(jsFile));
+ } else {
+ Q_ASSERT(false);
}
- return qMakePair(oldValue, newValue);
+ return { std::move(oldValue), std::move(newValue) };
}
-void DomUniverse::execQueue()
+/*!
+ \internal
+ This function is somewhat coupled and does the following:
+ 1. If a content of the file is provided it checks whether the item with the same content
+ already exists inside the Universe. If so, returns it as a result of the load
+ 2. If a content is not provided, it first tries to check whether Universe has the most
+ recent item. If yes, it returns it as a result of the load. Otherwise does step 1.
+ */
+DomUniverse::PreloadResult DomUniverse::preload(const DomItem &univ, const FileToLoad &file,
+ DomType fType) const
{
- ParsingTask t;
- {
- // Protect the queue from concurrent access.
- QMutexLocker l(mutex());
- if (m_queue.isEmpty())
- return;
- t = m_queue.dequeue();
- }
- shared_ptr<DomUniverse> topPtr = t.requestingUniverse.lock();
- if (!topPtr) {
- myErrors().error(tr("Ignoring callback for loading of %1: universe is not valid anymore").arg(t.canonicalPath)).handle();
- }
- QString canonicalPath = t.canonicalPath;
- QString code = t.contents;
- QDateTime contentDate = t.contentsDate;
- bool skipParse = false;
- DomItem oldValue; // old ExternalItemPair (might be empty, or equal to newValue)
- DomItem newValue; // current ExternalItemPair
- DomItem univ = DomItem(topPtr);
- QFileInfo path(canonicalPath);
- QVector<ErrorMessage> messages;
-
- if (t.kind == DomType::QmlFile || t.kind == DomType::QmltypesFile
- || t.kind == DomType::QmldirFile || t.kind == DomType::QmlDirectory) {
- auto getValue = [&t, this, &canonicalPath]() -> std::shared_ptr<ExternalItemPairBase> {
- if (t.kind == DomType::QmlFile)
- return m_qmlFileWithPath.value(canonicalPath);
- else if (t.kind == DomType::QmltypesFile)
- return m_qmlFileWithPath.value(canonicalPath);
- else if (t.kind == DomType::QmldirFile)
- return m_qmlFileWithPath.value(canonicalPath);
- else if (t.kind == DomType::QmlDirectory)
- return m_qmlDirectoryWithPath.value(canonicalPath);
- else
- Q_ASSERT(false);
- return {};
- };
- if (code.isEmpty()) {
- QFile file(canonicalPath);
- canonicalPath = path.canonicalFilePath();
- if (canonicalPath.isEmpty()) {
- messages.append(myErrors().error(tr("Non existing path %1").arg(t.canonicalPath)));
- canonicalPath = t.canonicalPath;
- }
- {
- QMutexLocker l(mutex());
- auto value = getValue();
- if (!(t.loadOptions & LoadOption::ForceLoad) && value) {
- if (value && value->currentItem()
- && path.lastModified() < value->currentItem()->lastDataUpdateAt()) {
- oldValue = newValue = univ.copy(value);
- skipParse = true;
- }
- }
- }
- if (!skipParse) {
- contentDate = QDateTime::currentDateTimeUtc();
- if (QFileInfo(canonicalPath).isDir()) {
- code = QDir(canonicalPath)
- .entryList(QDir::NoDotAndDotDot | QDir::Files, QDir::Name)
- .join(QLatin1Char('\n'));
- } else if (!file.open(QIODevice::ReadOnly)) {
- code = QStringLiteral(u"");
- messages.append(myErrors().error(tr("Error opening path %1: %2 %3")
- .arg(canonicalPath,
- QString::number(file.error()),
- file.errorString())));
- } else {
- code = QString::fromUtf8(file.readAll());
- file.close();
- }
- }
- }
- if (!skipParse) {
- QMutexLocker l(mutex());
- if (auto value = getValue()) {
- QString oldCode = value->currentItem()->code();
- if (value && value->currentItem() && !oldCode.isNull() && oldCode == code) {
- skipParse = true;
- newValue = oldValue = univ.copy(value);
- if (value->currentItem()->lastDataUpdateAt() < contentDate)
- value->currentItem()->refreshedDataAt(contentDate);
- }
- }
- }
- if (!skipParse) {
- QDateTime now(QDateTime::currentDateTimeUtc());
- if (t.kind == DomType::QmlFile) {
- auto qmlFile = std::make_shared<QmlFile>(canonicalPath, code, contentDate);
- auto envPtr = std::make_shared<DomEnvironment>(
- QStringList(), DomEnvironment::Option::NoDependencies, topPtr);
- envPtr->addQmlFile(qmlFile);
- DomItem env(envPtr);
- if (qmlFile->isValid()) {
- MutableDomItem qmlFileObj(env.copy(qmlFile));
- createDom(qmlFileObj);
- } else {
- QString errs;
- DomItem qmlFileObj = env.copy(qmlFile);
- qmlFile->iterateErrors(qmlFileObj, [&errs](DomItem, ErrorMessage m) {
- errs += m.toString();
- errs += u"\n";
- return true;
- });
- qCWarning(domLog).noquote().nospace()
- << "Parsed invalid file " << canonicalPath << errs;
- }
- auto change = updateEntry<QmlFile>(univ, qmlFile, m_qmlFileWithPath, mutex());
- oldValue = univ.copy(change.first);
- newValue = univ.copy(change.second);
- } else if (t.kind == DomType::QmltypesFile) {
- auto qmltypesFile = std::make_shared<QmltypesFile>(
- canonicalPath, code, contentDate);
- QmltypesReader reader(univ.copy(qmltypesFile));
- reader.parse();
- auto change = updateEntry<QmltypesFile>(univ, qmltypesFile, m_qmltypesFileWithPath,
- mutex());
- oldValue = univ.copy(change.first);
- newValue = univ.copy(change.second);
- } else if (t.kind == DomType::QmldirFile) {
- shared_ptr<QmldirFile> qmldirFile =
- QmldirFile::fromPathAndCode(canonicalPath, code);
- auto change =
- updateEntry<QmldirFile>(univ, qmldirFile, m_qmldirFileWithPath, mutex());
- oldValue = univ.copy(change.first);
- newValue = univ.copy(change.second);
- } else if (t.kind == DomType::QmlDirectory) {
- auto qmlDirectory = std::make_shared<QmlDirectory>(
- canonicalPath, code.split(QLatin1Char('\n')), contentDate);
- auto change = updateEntry<QmlDirectory>(univ, qmlDirectory, m_qmlDirectoryWithPath,
- mutex());
- oldValue = univ.copy(change.first);
- newValue = univ.copy(change.second);
- } else {
- Q_ASSERT(false);
- }
+ QString canonicalPath = file.canonicalPath();
+ ContentWithDate codeWithDate;
+
+ if (file.content().has_value()) {
+ codeWithDate = { file.content()->data, file.content()->date };
+ } else {
+ // When content is empty, Universe attempts to read it from the File.
+ // However if it already has the most recent version of that File it just returns it
+ const auto &curValueItem = getItemIfMostRecent(univ, fType, canonicalPath);
+ if (curValueItem.has_value()) {
+ return LoadResult{ curValueItem.value(), curValueItem.value() };
}
- for (const ErrorMessage &m : messages)
- newValue.addError(m);
- // to do: tell observers?
- // execute callback
- if (t.callback) {
- Path p;
- if (t.kind == DomType::QmlFile)
- p = Paths::qmlFileInfoPath(canonicalPath);
- else if (t.kind == DomType::QmltypesFile)
- p = Paths::qmltypesFileInfoPath(canonicalPath);
- else if (t.kind == DomType::QmldirFile)
- p = Paths::qmldirFileInfoPath(canonicalPath);
- else if (t.kind == DomType::QmlDirectory)
- p = Paths::qmlDirectoryInfoPath(canonicalPath);
- else
- Q_ASSERT(false);
- t.callback(p, oldValue, newValue);
+ // otherwise tries to read the content from the path
+ auto readResult = readFileContent(canonicalPath);
+ if (std::holds_alternative<ErrorMessage>(readResult)) {
+ DomItem newValue;
+ newValue.addError(std::move(std::get<ErrorMessage>(readResult)));
+ return LoadResult{ DomItem(), std::move(newValue) }; // read failed, nothing to parse
+ } else {
+ codeWithDate = std::get<ContentWithDate>(readResult);
}
- } else {
- Q_ASSERT(false && "Unhandled kind in queue");
}
+
+ // Once the code is provided Universe verifies if it already has an up-to-date code
+ const auto &curValueItem = getItemIfHasSameCode(univ, fType, canonicalPath, codeWithDate);
+ if (curValueItem.has_value()) {
+ return LoadResult{ curValueItem.value(), curValueItem.value() };
+ }
+ // otherwise code needs to be parsed
+ return codeWithDate;
}
void DomUniverse::removePath(const QString &path)
{
QMutexLocker l(mutex());
- auto toDelete = [path](auto it) {
+ const auto toDelete = [path](const auto &it) {
QString p = it.key();
return p.startsWith(path) && (p.size() == path.size() || p.at(path.size()) == u'/');
};
@@ -498,7 +356,191 @@ void DomUniverse::removePath(const QString &path)
m_qmltypesFileWithPath.removeIf(toDelete);
}
-std::shared_ptr<OwningItem> LoadInfo::doCopy(DomItem &self) const
+DomUniverse::ReadResult DomUniverse::readFileContent(const QString &canonicalPath) const
+{
+ if (canonicalPath.isEmpty()) {
+ return myErrors().error(tr("Non existing path %1").arg(canonicalPath));
+ }
+ QFile file(canonicalPath);
+ QFileInfo fileInfo(canonicalPath);
+ if (fileInfo.isDir()) {
+ return ContentWithDate{ QDir(canonicalPath)
+ .entryList(QDir::NoDotAndDotDot | QDir::Files, QDir::Name)
+ .join(QLatin1Char('\n')),
+ QDateTime::currentDateTimeUtc() };
+ }
+ if (!file.open(QIODevice::ReadOnly)) {
+ return myErrors().error(
+ tr("Error opening path %1: %2 %3")
+ .arg(canonicalPath, QString::number(file.error()), file.errorString()));
+ }
+ auto content = QString::fromUtf8(file.readAll());
+ file.close();
+ return ContentWithDate{ std::move(content), QDateTime::currentDateTimeUtc() };
+}
+
+std::shared_ptr<QmlFile> DomUniverse::parseQmlFile(const QString &code, const FileToLoad &file,
+ const QDateTime &contentDate,
+ DomCreationOptions creationOptions)
+{
+ auto qmlFile = std::make_shared<QmlFile>(file.canonicalPath(), code, contentDate, 0,
+ creationOptions.testFlag(WithRecovery)
+ ? QmlFile::EnableParserRecovery
+ : QmlFile::DisableParserRecovery);
+ std::shared_ptr<DomEnvironment> envPtr;
+ if (auto ptr = file.environment().lock())
+ envPtr = std::move(ptr);
+ else
+ envPtr = std::make_shared<DomEnvironment>(QStringList(),
+ DomEnvironment::Option::NoDependencies,
+ creationOptions, shared_from_this());
+ envPtr->addQmlFile(qmlFile);
+ DomItem env(envPtr);
+ if (qmlFile->isValid()) {
+ // do not call populateQmlFile twice on lazy qml files if the importer already does it!
+ if (!creationOptions.testFlag(DomCreationOption::WithSemanticAnalysis))
+ envPtr->populateFromQmlFile(MutableDomItem(env.copy(qmlFile)));
+ } else {
+ QString errs;
+ DomItem qmlFileObj = env.copy(qmlFile);
+ qmlFile->iterateErrors(qmlFileObj, [&errs](const DomItem &, const ErrorMessage &m) {
+ errs += m.toString();
+ errs += u"\n";
+ return true;
+ });
+ qCWarning(domLog).noquote().nospace()
+ << "Parsed invalid file " << file.canonicalPath() << errs;
+ }
+ return qmlFile;
+}
+
+std::shared_ptr<JsFile> DomUniverse::parseJsFile(const QString &code, const FileToLoad &file,
+ const QDateTime &contentDate)
+{
+ // WATCH OUT!
+ // DOM construction for plain JS files is not yet supported
+ // Only parsing of the file
+ // and adding ExternalItem to the Environment will happen here
+ auto jsFile = std::make_shared<JsFile>(file.canonicalPath(), code, contentDate);
+ std::shared_ptr<DomEnvironment> envPtr;
+ if (auto ptr = file.environment().lock())
+ envPtr = std::move(ptr);
+ else
+ envPtr = std::make_shared<DomEnvironment>(QStringList(),
+ DomEnvironment::Option::NoDependencies,
+ DomCreationOption::None, shared_from_this());
+ envPtr->addJsFile(jsFile);
+ DomItem env(envPtr);
+ if (!jsFile->isValid()) {
+ QString errs;
+ DomItem qmlFileObj = env.copy(jsFile);
+ jsFile->iterateErrors(qmlFileObj, [&errs](const DomItem &, const ErrorMessage &m) {
+ errs += m.toString();
+ errs += u"\n";
+ return true;
+ });
+ qCWarning(domLog).noquote().nospace()
+ << "Parsed invalid file " << file.canonicalPath() << errs;
+ }
+ return jsFile;
+}
+
+/*!
+ \internal
+ Queries the corresponding path map attempting to get the value
+ *WARNING* Usage of this function should be protected by the read lock
+ */
+std::shared_ptr<ExternalItemPairBase> DomUniverse::getPathValueOrNull(DomType fType,
+ const QString &path) const
+{
+ switch (fType) {
+ case DomType::QmlFile:
+ return m_qmlFileWithPath.value(path);
+ case DomType::QmltypesFile:
+ return m_qmltypesFileWithPath.value(path);
+ case DomType::QmldirFile:
+ return m_qmldirFileWithPath.value(path);
+ case DomType::QmlDirectory:
+ return m_qmlDirectoryWithPath.value(path);
+ case DomType::JsFile:
+ return m_jsFileWithPath.value(path);
+ default:
+ Q_ASSERT(false);
+ }
+ return nullptr;
+}
+
+std::optional<DomItem> DomUniverse::getItemIfMostRecent(const DomItem &univ, DomType fType,
+ const QString &canonicalPath) const
+{
+ QFileInfo fInfo(canonicalPath);
+ bool valueItemIsMostRecent = false;
+ std::shared_ptr<ExternalItemPairBase> value = nullptr;
+ {
+ // Mutex is to sync access to the Value and Value->CurrentItem, which can be modified
+ // through updateEnty method and currentItem->refreshedDataAt
+ QMutexLocker l(mutex());
+ value = getPathValueOrNull(fType, canonicalPath);
+ valueItemIsMostRecent = valueHasMostRecentItem(value.get(), fInfo.lastModified());
+ }
+ if (valueItemIsMostRecent) {
+ return univ.copy(value);
+ }
+ return std::nullopt;
+}
+
+std::optional<DomItem> DomUniverse::getItemIfHasSameCode(const DomItem &univ, DomType fType,
+ const QString &canonicalPath,
+ const ContentWithDate &codeWithDate) const
+{
+ std::shared_ptr<ExternalItemPairBase> value = nullptr;
+ bool valueItemHasSameCode = false;
+ {
+ // Mutex is to sync access to the Value and Value->CurrentItem, which can be modified
+ // through updateEnty method and currentItem->refreshedDataAt
+ QMutexLocker l(mutex());
+ value = getPathValueOrNull(fType, canonicalPath);
+ if (valueHasSameContent(value.get(), codeWithDate.content)) {
+ valueItemHasSameCode = true;
+ if (value->currentItem()->lastDataUpdateAt() < codeWithDate.date)
+ value->currentItem()->refreshedDataAt(codeWithDate.date);
+ }
+ }
+ if (valueItemHasSameCode) {
+ return univ.copy(value);
+ }
+ return std::nullopt;
+}
+
+/*!
+ \internal
+ Checks if value has current Item and if it was not modified since last seen
+ *WARNING* Usage of this function should be protected by the read lock
+ */
+bool DomUniverse::valueHasMostRecentItem(const ExternalItemPairBase *value,
+ const QDateTime &lastModified)
+{
+ if (!value || !value->currentItem()) {
+ return false;
+ }
+ return lastModified < value->currentItem()->lastDataUpdateAt();
+}
+
+/*!
+ \internal
+ Checks if value has current Item and if it has same content
+ *WARNING* Usage of this function should be protected by the read lock
+ */
+bool DomUniverse::valueHasSameContent(const ExternalItemPairBase *value, const QString &content)
+{
+ if (!value || !value->currentItem()) {
+ return false;
+ }
+ QString curContent = value->currentItem()->code();
+ return !curContent.isNull() && curContent == content;
+}
+
+std::shared_ptr<OwningItem> LoadInfo::doCopy(const DomItem &self) const
{
auto res = std::make_shared<LoadInfo>(*this);
if (res->status() != Status::Done) {
@@ -506,7 +548,7 @@ std::shared_ptr<OwningItem> LoadInfo::doCopy(DomItem &self) const
u"This is a copy of a LoadInfo still in progress, artificially ending it, if you "
u"use this you will *not* resume loading"));
DomEnvironment::myErrors()
- .warning([&self](Sink sink) {
+ .warning([&self](const Sink &sink) {
sink(u"Copying an in progress LoadInfo, which is most likely an error (");
self.dump(sink);
sink(u")");
@@ -521,12 +563,12 @@ std::shared_ptr<OwningItem> LoadInfo::doCopy(DomItem &self) const
return res;
}
-Path LoadInfo::canonicalPath(DomItem &) const
+Path LoadInfo::canonicalPath(const DomItem &) const
{
return Path::Root(PathRoot::Env).field(Fields::loadInfo).key(elementCanonicalPath().toString());
}
-bool LoadInfo::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool LoadInfo::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = OwningItem::iterateDirectSubpaths(self, visitor);
cont = cont && self.dvValueField(visitor, Fields::status, int(status()));
@@ -539,8 +581,8 @@ bool LoadInfo::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
return cont;
}
-void LoadInfo::addEndCallback(DomItem &self,
- std::function<void(Path, DomItem &, DomItem &)> callback)
+void LoadInfo::addEndCallback(const DomItem &self,
+ std::function<void(Path, const DomItem &, const DomItem &)> callback)
{
if (!callback)
return;
@@ -562,7 +604,7 @@ void LoadInfo::addEndCallback(DomItem &self,
callback(p, el, el);
}
-void LoadInfo::advanceLoad(DomItem &self)
+void LoadInfo::advanceLoad(const DomItem &self)
{
Status myStatus;
Dependency dep;
@@ -607,26 +649,27 @@ void LoadInfo::advanceLoad(DomItem &self)
case Status::InProgress:
if (depValid) {
refreshedDataAt(QDateTime::currentDateTimeUtc());
+ auto envPtr = self.environment().ownerAs<DomEnvironment>();
+ Q_ASSERT(envPtr && "missing environment");
if (!dep.uri.isEmpty()) {
- self.loadModuleDependency(
+ envPtr->loadModuleDependency(
dep.uri, dep.version,
- [this, self, dep](Path, DomItem &, DomItem &) mutable {
- finishedLoadingDep(self, dep);
+ [this, copiedSelf = self, dep](Path, const DomItem &, const DomItem &) {
+ // Need to explicitly copy self here since we might store this and
+ // call it later.
+ finishedLoadingDep(copiedSelf, dep);
},
self.errorHandler());
Q_ASSERT(dep.filePath.isEmpty() && "dependency with both uri and file");
} else if (!dep.filePath.isEmpty()) {
- DomItem env = self.environment();
- if (std::shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>())
- envPtr->loadFile(
- env, dep.filePath, QString(),
- [this, self, dep](Path, DomItem &, DomItem &) mutable {
- finishedLoadingDep(self, dep);
- },
- nullptr, nullptr, LoadOption::DefaultLoad, dep.fileType,
- self.errorHandler());
- else
- Q_ASSERT(false && "missing environment");
+ envPtr->loadFile(
+ FileToLoad::fromFileSystem(envPtr, dep.filePath),
+ [this, copiedSelf = self, dep](Path, const DomItem &, const DomItem &) {
+ // Need to explicitly copy self here since we might store this and
+ // call it later.
+ finishedLoadingDep(copiedSelf, dep);
+ },
+ dep.fileType, self.errorHandler());
} else {
Q_ASSERT(false && "dependency without uri and filePath");
}
@@ -643,7 +686,7 @@ void LoadInfo::advanceLoad(DomItem &self)
}
}
-void LoadInfo::finishedLoadingDep(DomItem &self, const Dependency &d)
+void LoadInfo::finishedLoadingDep(const DomItem &self, const Dependency &d)
{
bool didRemove = false;
bool unexpectedState = false;
@@ -668,7 +711,7 @@ void LoadInfo::finishedLoadingDep(DomItem &self, const Dependency &d)
}
}
if (!didRemove) {
- addErrorLocal(DomEnvironment::myErrors().error([&self](Sink sink) {
+ addErrorLocal(DomEnvironment::myErrors().error([&self](const Sink &sink) {
sink(u"LoadInfo::finishedLoadingDep did not find its dependency in those inProgress "
u"()");
self.dump(sink);
@@ -678,7 +721,7 @@ void LoadInfo::finishedLoadingDep(DomItem &self, const Dependency &d)
&& "LoadInfo::finishedLoadingDep did not find its dependency in those inProgress");
}
if (unexpectedState) {
- addErrorLocal(DomEnvironment::myErrors().error([&self](Sink sink) {
+ addErrorLocal(DomEnvironment::myErrors().error([&self](const Sink &sink) {
sink(u"LoadInfo::finishedLoadingDep found an unexpected state (");
self.dump(sink);
sink(u")");
@@ -689,9 +732,9 @@ void LoadInfo::finishedLoadingDep(DomItem &self, const Dependency &d)
execEnd(self);
}
-void LoadInfo::execEnd(DomItem &self)
+void LoadInfo::execEnd(const DomItem &self)
{
- QList<std::function<void(Path, DomItem &, DomItem &)>> endCallbacks;
+ QList<std::function<void(Path, const DomItem &, const DomItem &)>> endCallbacks;
bool unexpectedState = false;
{
QMutexLocker l(mutex());
@@ -704,7 +747,7 @@ void LoadInfo::execEnd(DomItem &self)
DomItem el = self.path(p);
{
auto cleanup = qScopeGuard([this, p, &el] {
- QList<std::function<void(Path, DomItem &, DomItem &)>> otherCallbacks;
+ QList<std::function<void(Path, const DomItem &, const DomItem &)>> otherCallbacks;
bool unexpectedState2 = false;
{
QMutexLocker l(mutex());
@@ -726,7 +769,7 @@ void LoadInfo::execEnd(DomItem &self)
}
}
-void LoadInfo::doAddDependencies(DomItem &self)
+void LoadInfo::doAddDependencies(const DomItem &self)
{
if (!elementCanonicalPath()) {
DomEnvironment::myErrors()
@@ -739,55 +782,36 @@ void LoadInfo::doAddDependencies(DomItem &self)
DomItem el = self.path(elementCanonicalPath());
if (el.internalKind() == DomType::ExternalItemInfo) {
DomItem currentFile = el.field(Fields::currentItem);
- DomItem currentImports = currentFile.field(Fields::imports);
QString currentFilePath = currentFile.canonicalFilePath();
- int iEnd = currentImports.indexes();
- for (int i = 0; i < iEnd; ++i) {
- DomItem import = currentImports.index(i);
- if (const Import *importPtr = import.as<Import>()) {
- if (importPtr->uri.isDirectory()) {
- QString path = importPtr->uri.absoluteLocalPath(currentFilePath);
- if (!path.isEmpty()) {
- addDependency(self,
- Dependency { QString(), importPtr->version, path,
- DomType::QmlDirectory });
- } else {
- self.addError(DomEnvironment::myErrors().error(
- tr("Ignoring dependencies for non resolved path import %1")
- .arg(importPtr->uri.toString())));
- }
- } else {
- addDependency(self,
- Dependency { importPtr->uri.moduleUri(), importPtr->version,
- QString(), DomType::ModuleIndex });
- }
- }
- }
- DomItem currentQmltypesFiles = currentFile.field(Fields::qmltypesFiles);
- int qEnd = currentQmltypesFiles.indexes();
- for (int i = 0; i < qEnd; ++i) {
- DomItem qmltypesRef = currentQmltypesFiles.index(i);
- if (const Reference *ref = qmltypesRef.as<Reference>()) {
- Path canonicalPath = ref->referredObjectPath[2];
- if (canonicalPath && !canonicalPath.headName().isEmpty())
- addDependency(self,
- Dependency { QString(), Version(), canonicalPath.headName(),
- DomType::QmltypesFile });
- }
- }
- DomItem currentQmlFiles = currentFile.field(Fields::qmlFiles);
- currentQmlFiles.visitKeys([this, &self](QString, DomItem &els) {
- return els.visitIndexes([this, &self](DomItem &el) {
- if (const Reference *ref = el.as<Reference>()) {
+ // do not mess with QmlFile's lazy-loading
+ if (currentFile.internalKind() != DomType::QmlFile) {
+ DomItem currentQmltypesFiles = currentFile.field(Fields::qmltypesFiles);
+ int qEnd = currentQmltypesFiles.indexes();
+ for (int i = 0; i < qEnd; ++i) {
+ DomItem qmltypesRef = currentQmltypesFiles.index(i);
+ if (const Reference *ref = qmltypesRef.as<Reference>()) {
Path canonicalPath = ref->referredObjectPath[2];
if (canonicalPath && !canonicalPath.headName().isEmpty())
- addDependency(self,
- Dependency { QString(), Version(), canonicalPath.headName(),
- DomType::QmlFile });
+ addDependency(
+ self,
+ Dependency{ QString(), Version(), canonicalPath.headName(),
+ DomType::QmltypesFile });
}
- return true;
+ }
+ DomItem currentQmlFiles = currentFile.field(Fields::qmlFiles);
+ currentQmlFiles.visitKeys([this, &self](const QString &, const DomItem &els) {
+ return els.visitIndexes([this, &self](const DomItem &el) {
+ if (const Reference *ref = el.as<Reference>()) {
+ Path canonicalPath = ref->referredObjectPath[2];
+ if (canonicalPath && !canonicalPath.headName().isEmpty())
+ addDependency(self,
+ Dependency{ QString(), Version(),
+ canonicalPath.headName(), DomType::QmlFile });
+ }
+ return true;
+ });
});
- });
+ }
} else if (shared_ptr<ModuleIndex> elPtr = el.ownerAs<ModuleIndex>()) {
const auto qmldirs = elPtr->qmldirsToLoad(el);
for (const Path &qmldirPath : qmldirs) {
@@ -798,7 +822,7 @@ void LoadInfo::doAddDependencies(DomItem &self)
DomType::QmldirFile });
}
QString uri = elPtr->uri();
- addEndCallback(self, [uri, qmldirs](Path, DomItem &, DomItem &newV) {
+ addEndCallback(self, [uri, qmldirs](Path, const DomItem &, const DomItem &newV) {
for (const Path &p : qmldirs) {
DomItem qmldir = newV.path(p);
if (std::shared_ptr<QmldirFile> qmldirFilePtr = qmldir.ownerAs<QmldirFile>()) {
@@ -818,7 +842,7 @@ void LoadInfo::doAddDependencies(DomItem &self)
}
}
-void LoadInfo::addDependency(DomItem &self, const Dependency &dep)
+void LoadInfo::addDependency(const DomItem &self, const Dependency &dep)
{
bool unexpectedState = false;
{
@@ -835,105 +859,14 @@ void LoadInfo::addDependency(DomItem &self, const Dependency &dep)
\class QQmlJS::Dom::DomEnvironment
\brief Represents a consistent set of types organized in modules, it is the top level of the DOM
- */
-template<typename T>
-DomTop::Callback envCallbackForFile(
- DomItem &self, QMap<QString, std::shared_ptr<ExternalItemInfo<T>>> DomEnvironment::*map,
- std::shared_ptr<ExternalItemInfo<T>> (DomEnvironment::*lookupF)(DomItem &, QString,
- EnvLookup) const,
- DomTop::Callback loadCallback, DomTop::Callback allDirectDepsCallback,
- DomTop::Callback endCallback)
-{
- std::shared_ptr<DomEnvironment> ePtr = self.ownerAs<DomEnvironment>();
- std::weak_ptr<DomEnvironment> selfPtr = ePtr;
- std::shared_ptr<DomEnvironment> basePtr = ePtr->base();
- return [selfPtr, basePtr, map, lookupF, loadCallback, allDirectDepsCallback,
- endCallback](Path, DomItem &, DomItem &newItem) {
- shared_ptr<DomEnvironment> envPtr = selfPtr.lock();
- if (!envPtr)
- return;
- DomItem env = DomItem(envPtr);
- shared_ptr<ExternalItemInfo<T>> oldValue;
- shared_ptr<ExternalItemInfo<T>> newValue;
- shared_ptr<T> newItemPtr;
- if (envPtr->options() & DomEnvironment::Option::KeepValid)
- newItemPtr = newItem.field(Fields::validItem).ownerAs<T>();
- if (!newItemPtr)
- newItemPtr = newItem.field(Fields::currentItem).ownerAs<T>();
- Q_ASSERT(newItemPtr && "callbackForQmlFile reached without current qmlFile");
- {
- QMutexLocker l(envPtr->mutex());
- oldValue = ((*envPtr).*map).value(newItem.canonicalFilePath());
- }
- if (oldValue) {
- // we do not change locally loaded files (avoid loading a file more than once)
- newValue = oldValue;
- } else {
- if (basePtr) {
- DomItem baseObj(basePtr);
- oldValue = ((*basePtr).*lookupF)(baseObj, newItem.canonicalFilePath(),
- EnvLookup::BaseOnly);
- }
- if (oldValue) {
- DomItem oldValueObj = env.copy(oldValue);
- newValue = oldValue->makeCopy(oldValueObj);
- if (newValue->current != newItemPtr) {
- newValue->current = newItemPtr;
- newValue->setCurrentExposedAt(QDateTime::currentDateTimeUtc());
- }
- } else {
- newValue = std::make_shared<ExternalItemInfo<T>>(
- newItemPtr, QDateTime::currentDateTimeUtc());
- }
- {
- QMutexLocker l(envPtr->mutex());
- auto value = ((*envPtr).*map).value(newItem.canonicalFilePath());
- if (value) {
- oldValue = newValue = value;
- } else {
- ((*envPtr).*map).insert(newItem.canonicalFilePath(), newValue);
- }
- }
- }
- Path p = env.copy(newValue).canonicalPath();
- {
- auto depLoad = qScopeGuard([p, &env, envPtr, allDirectDepsCallback, endCallback] {
- if (!(envPtr->options() & DomEnvironment::Option::NoDependencies)) {
- auto loadInfo = std::make_shared<LoadInfo>(p);
- if (!p)
- Q_ASSERT(false);
- DomItem loadInfoObj = env.copy(loadInfo);
- loadInfo->addEndCallback(loadInfoObj, allDirectDepsCallback);
- envPtr->addLoadInfo(env, loadInfo);
- }
- if (endCallback)
- envPtr->addAllLoadedCallback(env,
- [p, endCallback](Path, DomItem &, DomItem &env) {
- DomItem el = env.path(p);
- endCallback(p, el, el);
- });
- });
- if (loadCallback) {
- DomItem oldValueObj = env.copy(oldValue);
- DomItem newValueObj = env.copy(newValue);
- loadCallback(p, oldValueObj, newValueObj);
- }
- if ((envPtr->options() & DomEnvironment::Option::NoDependencies)
- && allDirectDepsCallback) {
- DomItem oldValueObj = env.copy(oldValue);
- DomItem newValueObj = env.copy(newValue);
- env.addError(DomEnvironment::myErrors().warning(
- QLatin1String("calling allDirectDepsCallback immediately for load with "
- "NoDependencies of %1")
- .arg(newItem.canonicalFilePath())));
- allDirectDepsCallback(p, oldValueObj, newValueObj);
- }
- }
- };
-}
+The DomEnvironment keeps a pointer m_lastValidBase to the last used valid DomEnvironment in the
+commitToBase() method. This allows the qqmldomastcreator to commit lazily loaded dependencies to the
+valid environment used by qmlls.
+ */
-ErrorGroups DomEnvironment::myErrors() {
+ErrorGroups DomEnvironment::myErrors()
+{
static ErrorGroups res = {{NewErrorGroup("Dom")}};
return res;
}
@@ -948,7 +881,7 @@ Path DomEnvironment::canonicalPath() const
return Path::Root(u"env");
}
-bool DomEnvironment::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool DomEnvironment::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
bool cont = true;
cont = cont && DomTop::iterateDirectSubpaths(self, visitor);
@@ -962,54 +895,54 @@ bool DomEnvironment::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
cont = cont && self.dvItemField(visitor, Fields::globalScopeWithName, [this, &self]() {
return self.subMapItem(Map(
Path::Field(Fields::globalScopeWithName),
- [&self, this](DomItem &map, QString key) {
+ [&self, this](const DomItem &map, const QString &key) {
return map.copy(globalScopeWithName(self, key));
},
- [&self, this](DomItem &) { return globalScopeNames(self); },
+ [&self, this](const DomItem &) { return globalScopeNames(self); },
QLatin1String("GlobalScope")));
});
cont = cont && self.dvItemField(visitor, Fields::qmlDirectoryWithPath, [this, &self]() {
return self.subMapItem(Map(
Path::Field(Fields::qmlDirectoryWithPath),
- [&self, this](DomItem &map, QString key) {
+ [&self, this](const DomItem &map, const QString &key) {
return map.copy(qmlDirectoryWithPath(self, key));
},
- [&self, this](DomItem &) { return qmlDirectoryPaths(self); },
+ [&self, this](const DomItem &) { return qmlDirectoryPaths(self); },
QLatin1String("QmlDirectory")));
});
cont = cont && self.dvItemField(visitor, Fields::qmldirFileWithPath, [this, &self]() {
return self.subMapItem(Map(
Path::Field(Fields::qmldirFileWithPath),
- [&self, this](DomItem &map, QString key) {
+ [&self, this](const DomItem &map, const QString &key) {
return map.copy(qmldirFileWithPath(self, key));
},
- [&self, this](DomItem &) { return qmldirFilePaths(self); },
+ [&self, this](const DomItem &) { return qmldirFilePaths(self); },
QLatin1String("QmldirFile")));
});
cont = cont && self.dvItemField(visitor, Fields::qmldirWithPath, [this, &self]() {
return self.subMapItem(Map(
Path::Field(Fields::qmldirWithPath),
- [&self, this](DomItem &map, QString key) {
+ [&self, this](const DomItem &map, const QString &key) {
return map.copy(qmlDirWithPath(self, key));
},
- [&self, this](DomItem &) { return qmlDirPaths(self); }, QLatin1String("Qmldir")));
+ [&self, this](const DomItem &) { return qmlDirPaths(self); }, QLatin1String("Qmldir")));
});
cont = cont && self.dvItemField(visitor, Fields::qmlFileWithPath, [this, &self]() {
return self.subMapItem(Map(
Path::Field(Fields::qmlFileWithPath),
- [&self, this](DomItem &map, QString key) {
+ [&self, this](const DomItem &map, const QString &key) {
return map.copy(qmlFileWithPath(self, key));
},
- [&self, this](DomItem &) { return qmlFilePaths(self); }, QLatin1String("QmlFile")));
+ [&self, this](const DomItem &) { return qmlFilePaths(self); }, QLatin1String("QmlFile")));
});
cont = cont && self.dvItemField(visitor, Fields::jsFileWithPath, [this, &self]() {
return self.subMapItem(Map(
Path::Field(Fields::jsFileWithPath),
- [this](DomItem &map, QString key) {
+ [this](const DomItem &map, const QString &key) {
DomItem mapOw(map.owner());
return map.copy(jsFileWithPath(mapOw, key));
},
- [this](DomItem &map) {
+ [this](const DomItem &map) {
DomItem mapOw = map.owner();
return jsFilePaths(mapOw);
},
@@ -1018,11 +951,11 @@ bool DomEnvironment::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
cont = cont && self.dvItemField(visitor, Fields::qmltypesFileWithPath, [this, &self]() {
return self.subMapItem(Map(
Path::Field(Fields::qmltypesFileWithPath),
- [this](DomItem &map, QString key) {
+ [this](const DomItem &map, const QString &key) {
DomItem mapOw = map.owner();
return map.copy(qmltypesFileWithPath(mapOw, key));
},
- [this](DomItem &map) {
+ [this](const DomItem &map) {
DomItem mapOw = map.owner();
return qmltypesFilePaths(mapOw);
},
@@ -1031,10 +964,10 @@ bool DomEnvironment::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
cont = cont && self.dvItemField(visitor, Fields::moduleIndexWithUri, [this, &self]() {
return self.subMapItem(Map(
Path::Field(Fields::moduleIndexWithUri),
- [this](DomItem &map, QString key) {
+ [this](const DomItem &map, const QString &key) {
return map.subMapItem(Map(
map.pathFromOwner().key(key),
- [this, key](DomItem &submap, QString subKey) {
+ [this, key](const DomItem &submap, const QString &subKey) {
bool ok;
int i = subKey.toInt(&ok);
if (!ok) {
@@ -1050,7 +983,7 @@ bool DomEnvironment::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
moduleIndexWithUri(subMapOw, key, i);
return submap.copy(mIndex);
},
- [this, key](DomItem &subMap) {
+ [this, key](const DomItem &subMap) {
QSet<QString> res;
DomItem subMapOw = subMap.owner();
for (int mVersion :
@@ -1065,7 +998,7 @@ bool DomEnvironment::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
},
QLatin1String("ModuleIndex")));
},
- [this](DomItem &map) {
+ [this](const DomItem &map) {
DomItem mapOw = map.owner();
return moduleIndexUris(mapOw);
},
@@ -1090,14 +1023,14 @@ bool DomEnvironment::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
ensureInfo();
return self.subListItem(List(
Path::Field(Fields::loadsWithWork),
- [loadsWithWork](DomItem &list, index_type i) {
+ [loadsWithWork](const DomItem &list, index_type i) {
if (i >= 0 && i < loadsWithWork.size())
return list.subDataItem(PathEls::Index(i),
loadsWithWork.at(i).toString());
else
return DomItem();
},
- [loadsWithWork](DomItem &) {
+ [loadsWithWork](const DomItem &) {
return index_type(loadsWithWork.size());
},
nullptr, QLatin1String("Path")));
@@ -1107,22 +1040,22 @@ bool DomEnvironment::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
ensureInfo();
return self.subListItem(List(
Path::Field(Fields::inProgress),
- [inProgress](DomItem &list, index_type i) {
+ [inProgress](const DomItem &list, index_type i) {
if (i >= 0 && i < inProgress.size())
return list.subDataItem(PathEls::Index(i),
inProgress.at(i).toString());
else
return DomItem();
},
- [inProgress](DomItem &) { return index_type(inProgress.size()); },
+ [inProgress](const DomItem &) { return index_type(inProgress.size()); },
nullptr, QLatin1String("Path")));
});
cont = cont && self.dvItemField(visitor, Fields::loadInfo, [&self, this]() {
return self.subMapItem(Map(
Path::Field(Fields::loadInfo),
- [this](DomItem &map, QString pStr) {
+ [this](const DomItem &map, const QString &pStr) {
bool hasErrors = false;
- Path p = Path::fromString(pStr, [&hasErrors](ErrorMessage m) {
+ Path p = Path::fromString(pStr, [&hasErrors](const ErrorMessage &m) {
switch (m.level) {
case ErrorLevel::Debug:
case ErrorLevel::Info:
@@ -1138,7 +1071,7 @@ bool DomEnvironment::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
return map.copy(loadInfo(p));
return DomItem();
},
- [this](DomItem &) {
+ [this](const DomItem &) {
QSet<QString> res;
const auto infoPaths = loadInfoPaths();
for (const Path &p : infoPaths)
@@ -1157,189 +1090,136 @@ bool DomEnvironment::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
return cont;
}
-DomItem DomEnvironment::field(DomItem &self, QStringView name) const
+DomItem DomEnvironment::field(const DomItem &self, QStringView name) const
{
return DomTop::field(self, name);
}
-std::shared_ptr<DomEnvironment> DomEnvironment::makeCopy(DomItem &self) const
+std::shared_ptr<DomEnvironment> DomEnvironment::makeCopy(const DomItem &self) const
{
return std::static_pointer_cast<DomEnvironment>(doCopy(self));
}
-void DomEnvironment::loadFile(DomItem &self, QString filePath, QString logicalPath,
- DomTop::Callback loadCallback, DomTop::Callback directDepsCallback,
- DomTop::Callback endCallback, LoadOptions loadOptions,
- std::optional<DomType> fileType, ErrorHandler h)
-{
- loadFile(self, filePath, logicalPath, QString(), QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
- loadCallback, directDepsCallback, endCallback, loadOptions, fileType, h);
-}
-
-std::shared_ptr<OwningItem> DomEnvironment::doCopy(DomItem &) const
+std::shared_ptr<OwningItem> DomEnvironment::doCopy(const DomItem &) const
{
shared_ptr<DomEnvironment> res;
if (m_base)
- res = std::make_shared<DomEnvironment>(m_base, m_loadPaths, m_options);
+ res = std::make_shared<DomEnvironment>(m_base, m_loadPaths, m_options,
+ m_domCreationOptions);
else
- res = std::make_shared<DomEnvironment>(
- m_loadPaths, m_options, m_universe);
+ res = std::make_shared<DomEnvironment>(m_loadPaths, m_options, m_domCreationOptions,
+ m_universe);
return res;
}
-void DomEnvironment::loadFile(DomItem &self, QString filePath, QString logicalPath, QString code,
- QDateTime codeDate, Callback loadCallback,
- Callback directDepsCallback, Callback endCallback,
- LoadOptions loadOptions, std::optional<DomType> fileType,
- ErrorHandler h)
+void DomEnvironment::loadFile(const FileToLoad &file, const Callback &callback,
+ std::optional<DomType> fileType, const ErrorHandler &h)
{
- QFileInfo fileInfo(filePath);
- QString canonicalFilePath = fileInfo.canonicalFilePath();
- if (canonicalFilePath.isEmpty()) {
- if (code.isNull()) {
- myErrors().error(tr("Non existing path to load: '%1'").arg(filePath)).handle(h);
+ if (options() & DomEnvironment::Option::NoDependencies)
+ loadFile(file, callback, DomTop::Callback(), fileType, h);
+ else {
+ // When the file is required to be loaded with dependencies, those dependencies
+ // will be added to the "pending" queue through envCallbackForFile
+ // then those should not be forgotten to be loaded.
+ loadFile(file, DomTop::Callback(), callback, fileType, h);
+ }
+}
+
+/*!
+ \internal
+ Depending on the options, the function will be called either with loadCallback OR endCallback
+
+ Before loading the file, envCallbackForFile will be created and passed as an argument to
+ universe().loadFile(...).
+ This is a callback which will be called after the load of the file is finished. More
+ specifically when File is required to be loaded without Dependencies only loadCallback is being
+ used. Otherwise, the callback is passed as endCallback. What endCallback means is that this
+ callback will be called only at the very end, once all necessary dependencies are being loaded.
+ Management and handing of this is happening through the m_loadsWithWork.
+*/
+// TODO(QTBUG-119550) refactor this
+void DomEnvironment::loadFile(const FileToLoad &file, const Callback &loadCallback,
+ const Callback &endCallback, std::optional<DomType> fileType,
+ const ErrorHandler &h)
+{
+ DomItem self(shared_from_this());
+ if (file.canonicalPath().isEmpty()) {
+ if (!file.content() || file.content()->data.isNull()) {
+ // file's content inavailable and no path to retrieve it
+ myErrors()
+ .error(tr("Non existing path to load: '%1'").arg(file.logicalPath()))
+ .handle(h);
if (loadCallback)
loadCallback(Path(), DomItem::empty, DomItem::empty);
- if (directDepsCallback)
- directDepsCallback(Path(), DomItem::empty, DomItem::empty);
if (endCallback)
- addAllLoadedCallback(self, [endCallback](Path, DomItem &, DomItem &) {
+ addAllLoadedCallback(self, [endCallback](Path, const DomItem &, const DomItem &) {
endCallback(Path(), DomItem::empty, DomItem::empty);
});
return;
} else {
- canonicalFilePath = filePath;
+ // fallback: path invalid but file's content is already available.
+ file.canonicalPath() = file.logicalPath();
}
}
+
shared_ptr<ExternalItemInfoBase> oldValue, newValue;
- DomType fType = (bool(fileType) ? (*fileType) : fileTypeForPath(self, canonicalFilePath));
+ const DomType fType =
+ (bool(fileType) ? (*fileType) : fileTypeForPath(self, file.canonicalPath()));
switch (fType) {
case DomType::QmlDirectory: {
- {
- QMutexLocker l(mutex());
- auto it = m_qmlDirectoryWithPath.find(canonicalFilePath);
- if (it != m_qmlDirectoryWithPath.end())
- oldValue = newValue = *it;
- }
- if (!newValue && (options() & Option::NoReload) && m_base) {
- if (auto v = m_base->qmlDirectoryWithPath(self, canonicalFilePath, EnvLookup::Normal)) {
- oldValue = v;
- QDateTime now = QDateTime::currentDateTimeUtc();
- auto newV = std::make_shared<ExternalItemInfo<QmlDirectory>>(
- v->current, now, v->revision(), v->lastDataUpdateAt());
- newValue = newV;
- QMutexLocker l(mutex());
- auto it = m_qmlDirectoryWithPath.find(canonicalFilePath);
- if (it != m_qmlDirectoryWithPath.end())
- oldValue = newValue = *it;
- else
- m_qmlDirectoryWithPath.insert(canonicalFilePath, newV);
- }
- }
+ const auto &fetchResult = fetchFileFromEnvs<QmlDirectory>(file);
+ oldValue = fetchResult.first;
+ newValue = fetchResult.second;
if (!newValue) {
- self.universe().loadFile(
- canonicalFilePath, logicalPath, code, codeDate,
- callbackForQmlDirectory(self, loadCallback, directDepsCallback, endCallback),
- loadOptions, fType);
+ const auto &loadRes = universe()->loadFile(file, fType, m_domCreationOptions);
+ addExternalItemInfo<QmlDirectory>(loadRes.currentItem,
+ getLoadCallbackFor(fType, loadCallback), endCallback);
return;
}
} break;
case DomType::QmlFile: {
- {
- QMutexLocker l(mutex());
- auto it = m_qmlFileWithPath.find(canonicalFilePath);
- if (it != m_qmlFileWithPath.end())
- oldValue = newValue = *it;
- }
- if (!newValue && (options() & Option::NoReload) && m_base) {
- if (auto v = m_base->qmlFileWithPath(self, canonicalFilePath, EnvLookup::Normal)) {
- oldValue = v;
- QDateTime now = QDateTime::currentDateTimeUtc();
- auto newV = std::make_shared<ExternalItemInfo<QmlFile>>(
- v->current, now, v->revision(), v->lastDataUpdateAt());
- newValue = newV;
- QMutexLocker l(mutex());
- auto it = m_qmlFileWithPath.find(canonicalFilePath);
- if (it != m_qmlFileWithPath.end())
- oldValue = newValue = *it;
- else
- m_qmlFileWithPath.insert(canonicalFilePath, newV);
- }
- }
+ const auto &fetchResult = fetchFileFromEnvs<QmlFile>(file);
+ oldValue = fetchResult.first;
+ newValue = fetchResult.second;
if (!newValue) {
- self.universe().loadFile(
- canonicalFilePath, logicalPath, code, codeDate,
- callbackForQmlFile(self, loadCallback, directDepsCallback, endCallback),
- loadOptions, fType);
+ const auto &loadRes = universe()->loadFile(file, fType, m_domCreationOptions);
+ addExternalItemInfo<QmlFile>(loadRes.currentItem,
+ getLoadCallbackFor(fType, loadCallback), endCallback);
return;
}
} break;
case DomType::QmltypesFile: {
- {
- QMutexLocker l(mutex());
- auto it = m_qmltypesFileWithPath.find(canonicalFilePath);
- if (it != m_qmltypesFileWithPath.end())
- oldValue = newValue = *it;
- }
- if (!newValue && (options() & Option::NoReload) && m_base) {
- if (auto v = m_base->qmltypesFileWithPath(self, canonicalFilePath, EnvLookup::Normal)) {
- oldValue = v;
- QDateTime now = QDateTime::currentDateTimeUtc();
- auto newV = std::make_shared<ExternalItemInfo<QmltypesFile>>(
- v->current, now, v->revision(), v->lastDataUpdateAt());
- newValue = newV;
- QMutexLocker l(mutex());
- auto it = m_qmltypesFileWithPath.find(canonicalFilePath);
- if (it != m_qmltypesFileWithPath.end())
- oldValue = newValue = *it;
- else
- m_qmltypesFileWithPath.insert(canonicalFilePath, newV);
- }
- }
+ const auto &fetchResult = fetchFileFromEnvs<QmltypesFile>(file);
+ oldValue = fetchResult.first;
+ newValue = fetchResult.second;
if (!newValue) {
- self.universe().loadFile(
- canonicalFilePath, logicalPath, code, codeDate,
- callbackForQmltypesFile(self, loadCallback, directDepsCallback, endCallback),
- loadOptions, fType);
+ const auto &loadRes = universe()->loadFile(file, fType, m_domCreationOptions);
+ addExternalItemInfo<QmltypesFile>(loadRes.currentItem,
+ getLoadCallbackFor(fType, loadCallback), endCallback);
return;
}
} break;
case DomType::QmldirFile: {
- {
- QMutexLocker l(mutex());
- auto it = m_qmldirFileWithPath.find(canonicalFilePath);
- if (it != m_qmldirFileWithPath.end())
- oldValue = newValue = *it;
- }
- if (!newValue && (options() & Option::NoReload) && m_base) {
- if (auto v = m_base->qmldirFileWithPath(self, canonicalFilePath, EnvLookup::Normal)) {
- oldValue = v;
- QDateTime now = QDateTime::currentDateTimeUtc();
- auto newV = std::make_shared<ExternalItemInfo<QmldirFile>>(
- v->current, now, v->revision(), v->lastDataUpdateAt());
- newValue = newV;
- QMutexLocker l(mutex());
- auto it = m_qmldirFileWithPath.find(canonicalFilePath);
- if (it != m_qmldirFileWithPath.end())
- oldValue = newValue = *it;
- else
- m_qmldirFileWithPath.insert(canonicalFilePath, newV);
- }
- }
+ const auto &fetchResult = fetchFileFromEnvs<QmldirFile>(file);
+ oldValue = fetchResult.first;
+ newValue = fetchResult.second;
if (!newValue) {
- self.universe().loadFile(
- canonicalFilePath, logicalPath, code, codeDate,
- callbackForQmldirFile(self, loadCallback, directDepsCallback, endCallback),
- loadOptions, fType);
+ const auto &loadRes = universe()->loadFile(file, fType, m_domCreationOptions);
+ addExternalItemInfo<QmldirFile>(loadRes.currentItem,
+ getLoadCallbackFor(fType, loadCallback), endCallback);
return;
}
} break;
+ case DomType::JsFile: {
+ const auto &loadRes = universe()->loadFile(file, fType, m_domCreationOptions);
+ addExternalItemInfo<JsFile>(loadRes.currentItem, getLoadCallbackFor(fType, loadCallback),
+ endCallback);
+ return;
+ } break;
default: {
- myErrors().error(tr("Unexpected file to load: '%1'").arg(filePath)).handle(h);
+ myErrors().error(tr("Unexpected file to load: '%1'").arg(file.canonicalPath())).handle(h);
if (loadCallback)
loadCallback(self.canonicalPath(), DomItem::empty, DomItem::empty);
- if (directDepsCallback)
- directDepsCallback(self.canonicalPath(), DomItem::empty, DomItem::empty);
if (endCallback)
endCallback(self.canonicalPath(), DomItem::empty, DomItem::empty);
return;
@@ -1353,27 +1233,34 @@ void DomEnvironment::loadFile(DomItem &self, QString filePath, QString logicalPa
DomItem newValueObj = self.copy(newValue);
loadCallback(p, oldValueObj, newValueObj);
}
- if (directDepsCallback) {
- DomItem lInfoObj = self.copy(lInfo);
- lInfo->addEndCallback(lInfoObj, directDepsCallback);
- }
} else {
self.addError(myErrors().error(tr("missing load info in ")));
if (loadCallback)
loadCallback(self.canonicalPath(), DomItem::empty, DomItem::empty);
- if (directDepsCallback)
- directDepsCallback(self.canonicalPath(), DomItem::empty, DomItem::empty);
}
if (endCallback)
- addAllLoadedCallback(self, [p, endCallback](Path, DomItem &, DomItem &env) {
+ addAllLoadedCallback(self, [p = std::move(p), endCallback](
+ const Path &, const DomItem &, const DomItem &env) {
DomItem el = env.path(p);
endCallback(p, el, el);
});
}
-void DomEnvironment::loadModuleDependency(DomItem &self, QString uri, Version v,
+void DomEnvironment::loadModuleDependency(
+ const QString &uri, Version version,
+ const std::function<void(const Path &, const DomItem &, const DomItem &)> &callback,
+ const ErrorHandler &errorHandler)
+{
+ DomItem envItem(shared_from_this());
+ if (options() & DomEnvironment::Option::NoDependencies)
+ loadModuleDependency(envItem, uri, version, callback, nullptr, errorHandler);
+ else
+ loadModuleDependency(envItem, uri, version, nullptr, callback, errorHandler);
+}
+
+void DomEnvironment::loadModuleDependency(const DomItem &self, const QString &uri, Version v,
Callback loadCallback, Callback endCallback,
- ErrorHandler errorHandler)
+ const ErrorHandler &errorHandler)
{
Q_ASSERT(!uri.contains(u'/'));
Path p = Paths::moduleIndexPath(uri, v.majorVersion);
@@ -1388,6 +1275,9 @@ void DomEnvironment::loadModuleDependency(DomItem &self, QString uri, Version v,
QRegularExpression vRe(QRegularExpression::anchoredPattern(
QRegularExpression::escape(lastComponent) + QStringLiteral(u"\\.([0-9]*)")));
const auto lPaths = loadPaths();
+ qCDebug(QQmlJSDomImporting) << "DomEnvironment::loadModuleDependency: Searching module with"
+ " uri"
+ << uri;
for (const QString &path : lPaths) {
QDir dir(path + (subPathV.isEmpty() ? QStringLiteral(u"") : QStringLiteral(u"/"))
+ subPathV);
@@ -1399,25 +1289,39 @@ void DomEnvironment::loadModuleDependency(DomItem &self, QString uri, Version v,
if (majorV > maxV) {
QFileInfo fInfo(dir.canonicalPath() + QChar(u'/') + dirNow
+ QStringLiteral(u"/qmldir"));
- if (fInfo.isFile())
+ if (fInfo.isFile()) {
+ qCDebug(QQmlJSDomImporting)
+ << "Found qmldir in " << fInfo.canonicalFilePath();
maxV = majorV;
+ }
}
}
if (!commonV && dirNow == lastComponent) {
QFileInfo fInfo(dir.canonicalPath() + QChar(u'/') + dirNow
+ QStringLiteral(u"/qmldir"));
- if (fInfo.isFile())
+ if (fInfo.isFile()) {
+ qCDebug(QQmlJSDomImporting)
+ << "Found qmldir in " << fInfo.canonicalFilePath();
commonV = true;
+ }
}
}
}
- QAtomicInt toLoad((commonV ? 1 : 0) + ((maxV >= 0) ? 1 : 0));
- auto loadCallback2 = (loadCallback ? [p, loadCallback, toLoad](Path, DomItem &, DomItem &elV) mutable {
- if (--toLoad == 0) {
- DomItem el = elV.path(p);
- loadCallback(p, el, el);
- }
- }: Callback());
+
+ // This decrements _separately_ for each copy of the lambda. So, what we get here is not a
+ // limit on the total number of calls but a limit on the number of calls per caller
+ // location. It gets even funnier if the callback is first called and then copied further.
+ // TODO: Is this the intended behavior?
+ int toLoad = (commonV ? 1 : 0) + ((maxV >= 0) ? 1 : 0);
+ const auto loadCallback2 = loadCallback
+ ? [p, loadCallback, toLoad](Path, const DomItem &, const DomItem &elV) mutable {
+ if (--toLoad == 0) {
+ DomItem el = elV.path(p);
+ loadCallback(p, el, el);
+ }
+ }
+ : Callback();
+
if (maxV >= 0)
loadModuleDependency(self, uri, Version(maxV, v.minorVersion), loadCallback2, nullptr);
if (commonV)
@@ -1425,10 +1329,15 @@ void DomEnvironment::loadModuleDependency(DomItem &self, QString uri, Version v,
loadCallback2, nullptr);
else if (maxV < 0) {
if (uri != u"QML") {
- addErrorLocal(myErrors()
- .warning(tr("Failed to find main qmldir file for %1 %2")
- .arg(uri, v.stringValue()))
- .handle());
+ const QString loadPaths = lPaths.join(u", "_s);
+ qCDebug(QQmlJSDomImporting)
+ << "DomEnvironment::loadModuleDependency: qmldir at" << (uri + u"/qmldir"_s)
+ << "was not found in " << loadPaths;
+ addErrorLocal(
+ myErrors()
+ .warning(tr("Failed to find main qmldir file for %1 %2 in %3.")
+ .arg(uri, v.stringValue(), loadPaths))
+ .handle());
}
if (loadCallback)
loadCallback(p, DomItem::empty, DomItem::empty);
@@ -1447,14 +1356,16 @@ void DomEnvironment::loadModuleDependency(DomItem &self, QString uri, Version v,
loadCallback(p, DomItem::empty, DomItem::empty);
}
}
- if (endCallback)
- addAllLoadedCallback(self, [p, endCallback](Path, DomItem &, DomItem &env) {
+ if (endCallback) {
+ addAllLoadedCallback(self, [p = std::move(p), endCallback = std::move(endCallback)](
+ Path, const DomItem &, const DomItem &env) {
DomItem el = env.path(p);
endCallback(p, el, el);
});
+ }
}
-void DomEnvironment::loadBuiltins(DomItem &self, Callback callback, ErrorHandler h)
+void DomEnvironment::loadBuiltins(const Callback &callback, const ErrorHandler &h)
{
QString builtinsName = QLatin1String("builtins.qmltypes");
const auto lPaths = loadPaths();
@@ -1462,7 +1373,8 @@ void DomEnvironment::loadBuiltins(DomItem &self, Callback callback, ErrorHandler
QDir dir(path);
QFileInfo fInfo(dir.filePath(builtinsName));
if (fInfo.isFile()) {
- self.loadFile(fInfo.canonicalFilePath(), QString(), callback, LoadOption::DefaultLoad);
+ loadFile(FileToLoad::fromFileSystem(shared_from_this(), fInfo.canonicalFilePath()),
+ callback);
return;
}
}
@@ -1517,7 +1429,7 @@ QSet<QString> DomEnvironment::getStrings(function_ref<QSet<QString>()> getBase,
return res;
}
-QSet<QString> DomEnvironment::moduleIndexUris(DomItem &, EnvLookup lookup) const
+QSet<QString> DomEnvironment::moduleIndexUris(const DomItem &, EnvLookup lookup) const
{
DomItem baseObj = DomItem(m_base);
return this->getStrings<QMap<int, std::shared_ptr<ModuleIndex>>>(
@@ -1525,7 +1437,7 @@ QSet<QString> DomEnvironment::moduleIndexUris(DomItem &, EnvLookup lookup) const
m_moduleIndexWithUri, lookup);
}
-QSet<int> DomEnvironment::moduleIndexMajorVersions(DomItem &, QString uri, EnvLookup lookup) const
+QSet<int> DomEnvironment::moduleIndexMajorVersions(const DomItem &, const QString &uri, EnvLookup lookup) const
{
QSet<int> res;
if (lookup != EnvLookup::NoBase && m_base) {
@@ -1562,7 +1474,7 @@ std::shared_ptr<ModuleIndex> DomEnvironment::lookupModuleInEnv(const QString &ur
return it->value(majorVersion); // null shared_ptr is fine if no match
}
-DomEnvironment::ModuleLookupResult DomEnvironment::moduleIndexWithUriHelper(DomItem &self, QString uri, int majorVersion, EnvLookup options) const
+DomEnvironment::ModuleLookupResult DomEnvironment::moduleIndexWithUriHelper(const DomItem &self, const QString &uri, int majorVersion, EnvLookup options) const
{
std::shared_ptr<ModuleIndex> res;
if (options != EnvLookup::BaseOnly)
@@ -1594,10 +1506,9 @@ DomEnvironment::ModuleLookupResult DomEnvironment::moduleIndexWithUriHelper(DomI
}
}
-std::shared_ptr<ModuleIndex> DomEnvironment::moduleIndexWithUri(DomItem &self, QString uri,
- int majorVersion, EnvLookup options,
- Changeable changeable,
- ErrorHandler errorHandler)
+std::shared_ptr<ModuleIndex> DomEnvironment::moduleIndexWithUri(
+ const DomItem &self, const QString &uri, int majorVersion, EnvLookup options,
+ Changeable changeable, const ErrorHandler &errorHandler)
{
// sanity checks
Q_ASSERT((changeable == Changeable::ReadOnly
@@ -1636,7 +1547,7 @@ std::shared_ptr<ModuleIndex> DomEnvironment::moduleIndexWithUri(DomItem &self, Q
auto &modsNow = m_moduleIndexWithUri[uri];
// As we do not hold the lock for the whole operation, some other thread
// might have created the module already
- if (auto it = modsNow.find(majorVersion); it != modsNow.end())
+ if (auto it = modsNow.constFind(majorVersion); it != modsNow.cend())
return *it;
modsNow.insert(majorVersion, newModulePtr);
}
@@ -1654,30 +1565,20 @@ std::shared_ptr<ModuleIndex> DomEnvironment::moduleIndexWithUri(DomItem &self, Q
return newModulePtr;
}
-std::shared_ptr<ModuleIndex> DomEnvironment::moduleIndexWithUri(DomItem &self, QString uri,
+std::shared_ptr<ModuleIndex> DomEnvironment::moduleIndexWithUri(const DomItem &self, const QString &uri,
int majorVersion,
EnvLookup options) const
{
return moduleIndexWithUriHelper(self, uri, majorVersion, options).module;
}
-
-
std::shared_ptr<ExternalItemInfo<QmlDirectory>>
-DomEnvironment::qmlDirectoryWithPath(DomItem &self, QString path, EnvLookup options) const
+DomEnvironment::qmlDirectoryWithPath(const DomItem &, const QString &path, EnvLookup options) const
{
- if (options != EnvLookup::BaseOnly) {
- QMutexLocker l(mutex());
- if (m_qmlDirectoryWithPath.contains(path))
- return m_qmlDirectoryWithPath.value(path);
- }
- if (options != EnvLookup::NoBase && m_base) {
- return m_base->qmlDirectoryWithPath(self, path, options);
- }
- return {};
+ return lookup<QmlDirectory>(path, options);
}
-QSet<QString> DomEnvironment::qmlDirectoryPaths(DomItem &, EnvLookup options) const
+QSet<QString> DomEnvironment::qmlDirectoryPaths(const DomItem &, EnvLookup options) const
{
return getStrings<std::shared_ptr<ExternalItemInfo<QmlDirectory>>>(
[this] {
@@ -1688,20 +1589,12 @@ QSet<QString> DomEnvironment::qmlDirectoryPaths(DomItem &, EnvLookup options) co
}
std::shared_ptr<ExternalItemInfo<QmldirFile>>
-DomEnvironment::qmldirFileWithPath(DomItem &self, QString path, EnvLookup options) const
+DomEnvironment::qmldirFileWithPath(const DomItem &, const QString &path, EnvLookup options) const
{
- if (options != EnvLookup::BaseOnly) {
- QMutexLocker l(mutex());
- auto it = m_qmldirFileWithPath.find(path);
- if (it != m_qmldirFileWithPath.end())
- return *it;
- }
- if (options != EnvLookup::NoBase && m_base)
- return m_base->qmldirFileWithPath(self, path, options);
- return {};
+ return lookup<QmldirFile>(path, options);
}
-QSet<QString> DomEnvironment::qmldirFilePaths(DomItem &, EnvLookup lOptions) const
+QSet<QString> DomEnvironment::qmldirFilePaths(const DomItem &, EnvLookup lOptions) const
{
return getStrings<std::shared_ptr<ExternalItemInfo<QmldirFile>>>(
[this] {
@@ -1711,7 +1604,7 @@ QSet<QString> DomEnvironment::qmldirFilePaths(DomItem &, EnvLookup lOptions) con
m_qmldirFileWithPath, lOptions);
}
-std::shared_ptr<ExternalItemInfoBase> DomEnvironment::qmlDirWithPath(DomItem &self, QString path,
+std::shared_ptr<ExternalItemInfoBase> DomEnvironment::qmlDirWithPath(const DomItem &self, const QString &path,
EnvLookup options) const
{
if (auto qmldirFile = qmldirFileWithPath(self, path + QLatin1String("/qmldir"), options))
@@ -1719,7 +1612,7 @@ std::shared_ptr<ExternalItemInfoBase> DomEnvironment::qmlDirWithPath(DomItem &se
return qmlDirectoryWithPath(self, path, options);
}
-QSet<QString> DomEnvironment::qmlDirPaths(DomItem &self, EnvLookup options) const
+QSet<QString> DomEnvironment::qmlDirPaths(const DomItem &self, EnvLookup options) const
{
QSet<QString> res = qmlDirectoryPaths(self, options);
const auto qmldirFiles = qmldirFilePaths(self, options);
@@ -1737,20 +1630,12 @@ QSet<QString> DomEnvironment::qmlDirPaths(DomItem &self, EnvLookup options) cons
}
std::shared_ptr<ExternalItemInfo<QmlFile>>
-DomEnvironment::qmlFileWithPath(DomItem &self, QString path, EnvLookup options) const
+DomEnvironment::qmlFileWithPath(const DomItem &, const QString &path, EnvLookup options) const
{
- if (options != EnvLookup::BaseOnly) {
- QMutexLocker l(mutex());
- auto it = m_qmlFileWithPath.find(path);
- if (it != m_qmlFileWithPath.end())
- return *it;
- }
- if (options != EnvLookup::NoBase && m_base)
- return m_base->qmlFileWithPath(self, path, options);
- return {};
+ return lookup<QmlFile>(path, options);
}
-QSet<QString> DomEnvironment::qmlFilePaths(DomItem &, EnvLookup lookup) const
+QSet<QString> DomEnvironment::qmlFilePaths(const DomItem &, EnvLookup lookup) const
{
return getStrings<std::shared_ptr<ExternalItemInfo<QmlFile>>>(
[this] {
@@ -1761,19 +1646,12 @@ QSet<QString> DomEnvironment::qmlFilePaths(DomItem &, EnvLookup lookup) const
}
std::shared_ptr<ExternalItemInfo<JsFile>>
-DomEnvironment::jsFileWithPath(DomItem &self, QString path, EnvLookup options) const
+DomEnvironment::jsFileWithPath(const DomItem &, const QString &path, EnvLookup options) const
{
- if (options != EnvLookup::BaseOnly) {
- QMutexLocker l(mutex());
- if (m_jsFileWithPath.contains(path))
- return m_jsFileWithPath.value(path);
- }
- if (options != EnvLookup::NoBase && m_base)
- return m_base->jsFileWithPath(self, path, EnvLookup::Normal);
- return {};
+ return lookup<JsFile>(path, options);
}
-QSet<QString> DomEnvironment::jsFilePaths(DomItem &, EnvLookup lookup) const
+QSet<QString> DomEnvironment::jsFilePaths(const DomItem &, EnvLookup lookup) const
{
return getStrings<std::shared_ptr<ExternalItemInfo<JsFile>>>(
[this] {
@@ -1784,19 +1662,12 @@ QSet<QString> DomEnvironment::jsFilePaths(DomItem &, EnvLookup lookup) const
}
std::shared_ptr<ExternalItemInfo<QmltypesFile>>
-DomEnvironment::qmltypesFileWithPath(DomItem &self, QString path, EnvLookup options) const
+DomEnvironment::qmltypesFileWithPath(const DomItem &, const QString &path, EnvLookup options) const
{
- if (options != EnvLookup::BaseOnly) {
- QMutexLocker l(mutex());
- if (m_qmltypesFileWithPath.contains(path))
- return m_qmltypesFileWithPath.value(path);
- }
- if (options != EnvLookup::NoBase && m_base)
- return m_base->qmltypesFileWithPath(self, path, EnvLookup::Normal);
- return {};
+ return lookup<QmltypesFile>(path, options);
}
-QSet<QString> DomEnvironment::qmltypesFilePaths(DomItem &, EnvLookup lookup) const
+QSet<QString> DomEnvironment::qmltypesFilePaths(const DomItem &, EnvLookup lookup) const
{
return getStrings<std::shared_ptr<ExternalItemInfo<QmltypesFile>>>(
[this] {
@@ -1807,21 +1678,14 @@ QSet<QString> DomEnvironment::qmltypesFilePaths(DomItem &, EnvLookup lookup) con
}
std::shared_ptr<ExternalItemInfo<GlobalScope>>
-DomEnvironment::globalScopeWithName(DomItem &self, QString name, EnvLookup lookupOptions) const
+DomEnvironment::globalScopeWithName(const DomItem &, const QString &name,
+ EnvLookup lookupOptions) const
{
- if (lookupOptions != EnvLookup::BaseOnly) {
- QMutexLocker l(mutex());
- auto id = m_globalScopeWithName.find(name);
- if (id != m_globalScopeWithName.end())
- return *id;
- }
- if (lookupOptions != EnvLookup::NoBase && m_base)
- return m_base->globalScopeWithName(self, name, lookupOptions);
- return {};
+ return lookup<GlobalScope>(name, lookupOptions);
}
std::shared_ptr<ExternalItemInfo<GlobalScope>>
-DomEnvironment::ensureGlobalScopeWithName(DomItem &self, QString name, EnvLookup lookupOptions)
+DomEnvironment::ensureGlobalScopeWithName(const DomItem &self, const QString &name, EnvLookup lookupOptions)
{
if (auto current = globalScopeWithName(self, name, lookupOptions))
return current;
@@ -1844,7 +1708,7 @@ DomEnvironment::ensureGlobalScopeWithName(DomItem &self, QString name, EnvLookup
return {};
}
-QSet<QString> DomEnvironment::globalScopeNames(DomItem &, EnvLookup lookupOptions) const
+QSet<QString> DomEnvironment::globalScopeNames(const DomItem &, EnvLookup lookupOptions) const
{
QSet<QString> res;
if (lookupOptions != EnvLookup::NoBase && m_base) {
@@ -1869,7 +1733,26 @@ QSet<QString> DomEnvironment::globalScopeNames(DomItem &, EnvLookup lookupOption
return res;
}
-void DomEnvironment::addLoadInfo(DomItem &self, std::shared_ptr<LoadInfo> loadInfo)
+/*!
+ \internal
+ Depending on the creation options, this function adds LoadInfo of the provided path
+*/
+void DomEnvironment::addDependenciesToLoad(const Path &path)
+{
+ if (options() & Option::NoDependencies) {
+ return;
+ }
+ Q_ASSERT(path);
+ const auto loadInfo = std::make_shared<LoadInfo>(path);
+ return addLoadInfo(DomItem(shared_from_this()), loadInfo);
+}
+
+/*!
+ \internal
+ Enqueues path to the m_loadsWithWork (queue of the pending "load" jobs).
+ In simpler words, schedule the load of the dependencies of the path from loadInfo.
+*/
+void DomEnvironment::addLoadInfo(const DomItem &self, const std::shared_ptr<LoadInfo> &loadInfo)
{
if (!loadInfo)
return;
@@ -1891,7 +1774,7 @@ void DomEnvironment::addLoadInfo(DomItem &self, std::shared_ptr<LoadInfo> loadIn
}
}
-std::shared_ptr<LoadInfo> DomEnvironment::loadInfo(Path path) const
+std::shared_ptr<LoadInfo> DomEnvironment::loadInfo(const Path &path) const
{
QMutexLocker l(mutex());
return m_loadInfos.value(path);
@@ -1909,145 +1792,163 @@ QList<Path> DomEnvironment::loadInfoPaths() const
return lInfos.keys();
}
-DomItem::Callback DomEnvironment::callbackForQmlDirectory(DomItem &self, Callback loadCallback,
- Callback allDirectDepsCallback,
- Callback endCallback)
+DomItem::Callback DomEnvironment::getLoadCallbackFor(DomType fileType, const Callback &loadCallback)
{
- return envCallbackForFile<QmlDirectory>(self, &DomEnvironment::m_qmlDirectoryWithPath,
- &DomEnvironment::qmlDirectoryWithPath, loadCallback,
- allDirectDepsCallback, endCallback);
+ if (fileType == DomType::QmltypesFile) {
+ return [loadCallback](const Path &p, const DomItem &oldV, const DomItem &newV) {
+ DomItem newFile = newV.field(Fields::currentItem);
+ if (std::shared_ptr<QmltypesFile> newFilePtr = newFile.ownerAs<QmltypesFile>())
+ newFilePtr->ensureInModuleIndex(newFile);
+ if (loadCallback)
+ loadCallback(p, oldV, newV);
+ };
+ }
+ return loadCallback;
}
-DomItem::Callback DomEnvironment::callbackForQmlFile(DomItem &self, Callback loadCallback,
- Callback allDirectDepsCallback,
- Callback endCallback)
+DomEnvironment::DomEnvironment(const QStringList &loadPaths, Options options,
+ DomCreationOptions domCreationOptions,
+ const shared_ptr<DomUniverse> &universe)
+ : m_options(options),
+ m_universe(DomUniverse::guaranteeUniverse(universe)),
+ m_loadPaths(loadPaths),
+ m_implicitImports(defaultImplicitImports()),
+ m_domCreationOptions(domCreationOptions)
+
{
- return envCallbackForFile<QmlFile>(self, &DomEnvironment::m_qmlFileWithPath,
- &DomEnvironment::qmlFileWithPath, loadCallback,
- allDirectDepsCallback, endCallback);
}
-DomTop::Callback DomEnvironment::callbackForQmltypesFile(DomItem &self,
- DomTop::Callback loadCallback,
- Callback allDirectDepsCallback,
- DomTop::Callback endCallback)
-{
- return envCallbackForFile<QmltypesFile>(
- self, &DomEnvironment::m_qmltypesFileWithPath, &DomEnvironment::qmltypesFileWithPath,
- [loadCallback](Path p, DomItem &oldV, DomItem &newV) {
- DomItem newFile = newV.field(Fields::currentItem);
- if (std::shared_ptr<QmltypesFile> newFilePtr = newFile.ownerAs<QmltypesFile>())
- newFilePtr->ensureInModuleIndex(newFile);
- if (loadCallback)
- loadCallback(p, oldV, newV);
- },
- allDirectDepsCallback, endCallback);
+/*!
+\internal
+Do not call this method inside of DomEnvironment's constructor! It requires weak_from_this() that
+only works after the constructor call finished.
+*/
+DomEnvironment::SemanticAnalysis &DomEnvironment::semanticAnalysis()
+{
+ // QTBUG-124799: do not create a SemanticAnalysis in a temporary DomEnvironment, and use the one
+ // from the base environment instead.
+ if (m_base) {
+ auto &result = m_base->semanticAnalysis();
+ result.setLoadPaths(m_loadPaths);
+ return result;
+ }
+
+ if (m_semanticAnalysis)
+ return *m_semanticAnalysis;
+
+ Q_ASSERT(domCreationOptions().testFlag(DomCreationOption::WithSemanticAnalysis));
+ m_semanticAnalysis = SemanticAnalysis(m_loadPaths);
+ return *m_semanticAnalysis;
}
-DomTop::Callback DomEnvironment::callbackForQmldirFile(DomItem &self, DomTop::Callback loadCallback,
- Callback allDirectDepsCallback,
- DomTop::Callback endCallback)
+DomEnvironment::SemanticAnalysis::SemanticAnalysis(const QStringList &loadPaths)
+ : m_mapper(
+ std::make_shared<QQmlJSResourceFileMapper>(resourceFilesFromBuildFolders(loadPaths))),
+ m_importer(std::make_shared<QQmlJSImporter>(loadPaths, m_mapper.get(), true))
{
- return envCallbackForFile<QmldirFile>(self, &DomEnvironment::m_qmldirFileWithPath,
- &DomEnvironment::qmldirFileWithPath, loadCallback,
- allDirectDepsCallback, endCallback);
}
-DomEnvironment::DomEnvironment(QStringList loadPaths, Options options,
- shared_ptr<DomUniverse> universe)
- : m_options(options),
- m_universe(DomUniverse::guaranteeUniverse(universe)),
- m_loadPaths(loadPaths),
- m_implicitImports(defaultImplicitImports())
-{}
+void DomEnvironment::SemanticAnalysis::setLoadPaths(const QStringList &loadPaths)
+{
+ if (loadPaths == m_importer->importPaths())
+ return;
+
+ m_importer->setImportPaths(loadPaths);
+}
-DomItem DomEnvironment::create(QStringList loadPaths, Options options, DomItem &universe)
+std::shared_ptr<DomEnvironment> DomEnvironment::create(const QStringList &loadPaths,
+ Options options,
+ DomCreationOptions domCreationOptions,
+ const DomItem &universe)
{
std::shared_ptr<DomUniverse> universePtr = universe.ownerAs<DomUniverse>();
- auto envPtr = std::make_shared<DomEnvironment>(loadPaths, options, universePtr);
- return DomItem(envPtr);
+ return std::make_shared<DomEnvironment>(loadPaths, options, domCreationOptions, universePtr);
}
-DomEnvironment::DomEnvironment(shared_ptr<DomEnvironment> parent, QStringList loadPaths,
- Options options)
+DomEnvironment::DomEnvironment(const shared_ptr<DomEnvironment> &parent,
+ const QStringList &loadPaths, Options options,
+ DomCreationOptions domCreationOptions)
: m_options(options),
m_base(parent),
m_loadPaths(loadPaths),
- m_implicitImports(defaultImplicitImports())
-{}
+ m_implicitImports(defaultImplicitImports()),
+ m_domCreationOptions(domCreationOptions)
+{
+}
-template<typename T>
-std::shared_ptr<ExternalItemInfo<T>>
-addExternalItem(std::shared_ptr<T> file, QString key,
- QMap<QString, std::shared_ptr<ExternalItemInfo<T>>> &map, AddOption option,
- QBasicMutex *mutex)
+void DomEnvironment::addQmlFile(const std::shared_ptr<QmlFile> &file, AddOption options)
{
- if (!file)
- return {};
- auto eInfo = std::make_shared<ExternalItemInfo<T>>(
- file, QDateTime::currentDateTimeUtc());
- {
- QMutexLocker l(mutex);
- auto it = map.find(key);
- if (it != map.end()) {
- switch (option) {
- case AddOption::KeepExisting:
- eInfo = *it;
- break;
- case AddOption::Overwrite:
- map.insert(key, eInfo);
- break;
- }
- } else {
- map.insert(key, eInfo);
- }
+ addExternalItem(file, file->canonicalFilePath(), options);
+ if (domCreationOptions().testFlag(DomCreationOption::WithSemanticAnalysis)) {
+ const QQmlJSScope::Ptr &handle =
+ semanticAnalysis().m_importer->importFile(file->canonicalFilePath());
+
+ // force reset the outdated qqmljsscope in case it was already populated
+ QDeferredFactory<QQmlJSScope> newFactory(semanticAnalysis().m_importer.get(),
+ file->canonicalFilePath(),
+ TypeReader{ weak_from_this() });
+ file->setHandleForPopulation(handle);
+ handle.resetFactory(std::move(newFactory));
}
- return eInfo;
}
-std::shared_ptr<ExternalItemInfo<QmlFile>> DomEnvironment::addQmlFile(std::shared_ptr<QmlFile> file,
- AddOption options)
+void DomEnvironment::addQmlDirectory(const std::shared_ptr<QmlDirectory> &file, AddOption options)
{
- return addExternalItem<QmlFile>(file, file->canonicalFilePath(), m_qmlFileWithPath, options,
- mutex());
+ addExternalItem(file, file->canonicalFilePath(), options);
}
-std::shared_ptr<ExternalItemInfo<QmlDirectory>>
-DomEnvironment::addQmlDirectory(std::shared_ptr<QmlDirectory> file, AddOption options)
+void DomEnvironment::addQmldirFile(const std::shared_ptr<QmldirFile> &file, AddOption options)
{
- return addExternalItem<QmlDirectory>(file, file->canonicalFilePath(), m_qmlDirectoryWithPath,
- options, mutex());
+ addExternalItem(file, file->canonicalFilePath(), options);
}
-std::shared_ptr<ExternalItemInfo<QmldirFile>>
-DomEnvironment::addQmldirFile(std::shared_ptr<QmldirFile> file, AddOption options)
+void DomEnvironment::addQmltypesFile(const std::shared_ptr<QmltypesFile> &file, AddOption options)
{
- return addExternalItem<QmldirFile>(file, file->canonicalFilePath(), m_qmldirFileWithPath,
- options, mutex());
+ addExternalItem(file, file->canonicalFilePath(), options);
}
-std::shared_ptr<ExternalItemInfo<QmltypesFile>>
-DomEnvironment::addQmltypesFile(std::shared_ptr<QmltypesFile> file, AddOption options)
+void DomEnvironment::addJsFile(const std::shared_ptr<JsFile> &file, AddOption options)
{
- return addExternalItem<QmltypesFile>(file, file->canonicalFilePath(), m_qmltypesFileWithPath,
- options, mutex());
+ addExternalItem(file, file->canonicalFilePath(), options);
}
-std::shared_ptr<ExternalItemInfo<JsFile>> DomEnvironment::addJsFile(std::shared_ptr<JsFile> file,
- AddOption options)
+void DomEnvironment::addGlobalScope(const std::shared_ptr<GlobalScope> &scope, AddOption options)
{
- return addExternalItem<JsFile>(file, file->canonicalFilePath(), m_jsFileWithPath, options,
- mutex());
+ addExternalItem(scope, scope->name(), options);
}
-std::shared_ptr<ExternalItemInfo<GlobalScope>>
-DomEnvironment::addGlobalScope(std::shared_ptr<GlobalScope> scope, AddOption options)
+QList<QQmlJS::DiagnosticMessage>
+DomEnvironment::TypeReader::operator()(QQmlJSImporter *importer, const QString &filePath,
+ const QSharedPointer<QQmlJSScope> &scopeToPopulate)
{
- return addExternalItem<GlobalScope>(scope, scope->name(), m_globalScopeWithName, options,
- mutex());
+ Q_UNUSED(importer);
+ Q_UNUSED(scopeToPopulate);
+
+ const QFileInfo info{ filePath };
+ const QString baseName = info.baseName();
+ scopeToPopulate->setInternalName(baseName.endsWith(QStringLiteral(".ui")) ? baseName.chopped(3)
+ : baseName);
+
+ std::shared_ptr<DomEnvironment> envPtr = m_env.lock();
+ // populate QML File if from implicit import directory
+ // use the version in DomEnvironment and do *not* load from disk.
+ auto it = envPtr->m_qmlFileWithPath.constFind(filePath);
+ if (it == envPtr->m_qmlFileWithPath.constEnd()) {
+ qCDebug(domLog) << "Import visitor tried to lazily load file \"" << filePath
+ << "\", but that file was not found in the DomEnvironment. Was this "
+ "file not discovered by the Dom's dependency loading mechanism?";
+ return { QQmlJS::DiagnosticMessage{
+ u"Could not find file \"%1\" in the Dom."_s.arg(filePath), QtMsgType::QtWarningMsg,
+ SourceLocation{} } };
+ }
+ const DomItem qmlFile = it.value()->currentItem(DomItem(envPtr));
+ envPtr->populateFromQmlFile(MutableDomItem(qmlFile));
+ return {};
}
-bool DomEnvironment::commitToBase(DomItem &self, shared_ptr<DomEnvironment> validEnvPtr)
+
+bool DomEnvironment::commitToBase(
+ const DomItem &self, const shared_ptr<DomEnvironment> &validEnvPtr)
{
if (!base())
return false;
@@ -2059,6 +1960,7 @@ bool DomEnvironment::commitToBase(DomItem &self, shared_ptr<DomEnvironment> vali
QMap<QString, std::shared_ptr<ExternalItemInfo<JsFile>>> my_jsFileWithPath;
QMap<QString, std::shared_ptr<ExternalItemInfo<QmltypesFile>>> my_qmltypesFileWithPath;
QHash<Path, std::shared_ptr<LoadInfo>> my_loadInfos;
+ std::optional<SemanticAnalysis> my_semanticAnalysis;
{
QMutexLocker l(mutex());
my_moduleIndexWithUri = m_moduleIndexWithUri;
@@ -2069,9 +1971,11 @@ bool DomEnvironment::commitToBase(DomItem &self, shared_ptr<DomEnvironment> vali
my_jsFileWithPath = m_jsFileWithPath;
my_qmltypesFileWithPath = m_qmltypesFileWithPath;
my_loadInfos = m_loadInfos;
+ my_semanticAnalysis = semanticAnalysis();
}
{
QMutexLocker lBase(base()->mutex()); // be more careful about makeCopy calls with lock?
+ m_base->m_semanticAnalysis = my_semanticAnalysis;
m_base->m_globalScopeWithName.insert(my_globalScopeWithName);
m_base->m_qmlDirectoryWithPath.insert(my_qmlDirectoryWithPath);
m_base->m_qmldirFileWithPath.insert(my_qmldirFileWithPath);
@@ -2099,28 +2003,31 @@ bool DomEnvironment::commitToBase(DomItem &self, shared_ptr<DomEnvironment> vali
}
}
}
- if (validEnvPtr) {
+ if (validEnvPtr)
+ m_lastValidBase = validEnvPtr;
+ if (m_lastValidBase) {
QMutexLocker lValid(
- validEnvPtr->mutex()); // be more careful about makeCopy calls with lock?
- validEnvPtr->m_globalScopeWithName.insert(my_globalScopeWithName);
- validEnvPtr->m_qmlDirectoryWithPath.insert(my_qmlDirectoryWithPath);
- validEnvPtr->m_qmldirFileWithPath.insert(my_qmldirFileWithPath);
+ m_lastValidBase->mutex()); // be more careful about makeCopy calls with lock?
+ m_lastValidBase->m_semanticAnalysis = std::move(my_semanticAnalysis);
+ m_lastValidBase->m_globalScopeWithName.insert(my_globalScopeWithName);
+ m_lastValidBase->m_qmlDirectoryWithPath.insert(my_qmlDirectoryWithPath);
+ m_lastValidBase->m_qmldirFileWithPath.insert(my_qmldirFileWithPath);
for (auto it = my_qmlFileWithPath.cbegin(), end = my_qmlFileWithPath.cend(); it != end;
++it) {
if (it.value() && it.value()->current && it.value()->current->isValid())
- validEnvPtr->m_qmlFileWithPath.insert(it.key(), it.value());
+ m_lastValidBase->m_qmlFileWithPath.insert(it.key(), it.value());
}
for (auto it = my_jsFileWithPath.cbegin(), end = my_jsFileWithPath.cend(); it != end;
++it) {
if (it.value() && it.value()->current && it.value()->current->isValid())
- validEnvPtr->m_jsFileWithPath.insert(it.key(), it.value());
+ m_lastValidBase->m_jsFileWithPath.insert(it.key(), it.value());
}
- validEnvPtr->m_qmltypesFileWithPath.insert(my_qmltypesFileWithPath);
- validEnvPtr->m_loadInfos.insert(my_loadInfos);
+ m_lastValidBase->m_qmltypesFileWithPath.insert(my_qmltypesFileWithPath);
+ m_lastValidBase->m_loadInfos.insert(my_loadInfos);
for (auto it = my_moduleIndexWithUri.cbegin(), end = my_moduleIndexWithUri.cend();
it != end; ++it) {
QMap<int, shared_ptr<ModuleIndex>> &myVersions =
- validEnvPtr->m_moduleIndexWithUri[it.key()];
+ m_lastValidBase->m_moduleIndexWithUri[it.key()];
for (auto it2 = it.value().cbegin(), end2 = it.value().cend(); it2 != end2; ++it2) {
auto oldV = myVersions.value(it2.key());
DomItem it2Obj = self.copy(it2.value());
@@ -2130,11 +2037,31 @@ bool DomEnvironment::commitToBase(DomItem &self, shared_ptr<DomEnvironment> vali
}
}
}
+
+ auto newBaseForPopulation =
+ m_lastValidBase ? m_lastValidBase->weak_from_this() : m_base->weak_from_this();
+ // adapt the factory to the use the base or valid environment for unpopulated files, instead of
+ // the current environment which will very probably be destroyed anytime soon
+ for (const auto &qmlFile : my_qmlFileWithPath) {
+ if (!qmlFile || !qmlFile->current)
+ continue;
+ QQmlJSScope::ConstPtr handle = qmlFile->current->handleForPopulation();
+ if (!handle)
+ continue;
+ auto oldFactory = handle.factory();
+ if (!oldFactory)
+ continue;
+
+ const QDeferredFactory<QQmlJSScope> newFactory(
+ oldFactory->importer(), oldFactory->filePath(), TypeReader{ newBaseForPopulation });
+ handle.resetFactory(newFactory);
+ }
return true;
}
-void DomEnvironment::loadPendingDependencies(DomItem &self)
+void DomEnvironment::loadPendingDependencies()
{
+ DomItem self(shared_from_this());
while (true) {
Path elToDo;
std::shared_ptr<LoadInfo> loadInfo;
@@ -2147,7 +2074,7 @@ void DomEnvironment::loadPendingDependencies(DomItem &self)
loadInfo = m_loadInfos.value(elToDo);
}
if (loadInfo) {
- auto cleanup = qScopeGuard([this, elToDo, &self] {
+ auto cleanup = qScopeGuard([this, &elToDo, &self] {
QList<Callback> endCallbacks;
{
QMutexLocker l(mutex());
@@ -2176,12 +2103,12 @@ void DomEnvironment::loadPendingDependencies(DomItem &self)
}
}
-bool DomEnvironment::finishLoadingDependencies(DomItem &self, int waitMSec)
+bool DomEnvironment::finishLoadingDependencies(int waitMSec)
{
bool hasPendingLoads = true;
QDateTime endTime = QDateTime::currentDateTimeUtc().addMSecs(waitMSec);
for (int i = 0; i < waitMSec / 10 + 2; ++i) {
- loadPendingDependencies(self);
+ loadPendingDependencies();
auto lInfos = loadInfos();
auto it = lInfos.cbegin();
auto end = lInfos.cend();
@@ -2204,7 +2131,7 @@ bool DomEnvironment::finishLoadingDependencies(DomItem &self, int waitMSec)
return !hasPendingLoads;
}
-void DomEnvironment::addWorkForLoadInfo(Path elementCanonicalPath)
+void DomEnvironment::addWorkForLoadInfo(const Path &elementCanonicalPath)
{
QMutexLocker l(mutex());
m_loadsWithWork.enqueue(elementCanonicalPath);
@@ -2224,6 +2151,9 @@ void DomEnvironment::setLoadPaths(const QStringList &v)
{
QMutexLocker l(mutex());
m_loadPaths = v;
+
+ if (m_semanticAnalysis)
+ m_semanticAnalysis->setLoadPaths(v);
}
QStringList DomEnvironment::loadPaths() const
@@ -2232,6 +2162,12 @@ QStringList DomEnvironment::loadPaths() const
return m_loadPaths;
}
+QStringList DomEnvironment::qmldirFiles() const
+{
+ QMutexLocker l(mutex());
+ return m_qmldirFileWithPath.keys();
+}
+
QString DomEnvironment::globalScopeName() const
{
return m_globalScopeName;
@@ -2248,7 +2184,7 @@ QList<Import> DomEnvironment::implicitImports() const
return m_implicitImports;
}
-void DomEnvironment::addAllLoadedCallback(DomItem &self, DomTop::Callback c)
+void DomEnvironment::addAllLoadedCallback(const DomItem &self, DomTop::Callback c)
{
if (c) {
bool immediate = false;
@@ -2269,14 +2205,58 @@ void DomEnvironment::clearReferenceCache()
m_referenceCache.clear();
}
-QString ExternalItemInfoBase::canonicalFilePath(DomItem &self) const
+void DomEnvironment::populateFromQmlFile(MutableDomItem &&qmlFile)
+{
+ if (std::shared_ptr<QmlFile> qmlFilePtr = qmlFile.ownerAs<QmlFile>()) {
+ auto logger = std::make_shared<QQmlJSLogger>();
+ logger->setFileName(qmlFile.canonicalFilePath());
+ logger->setCode(qmlFilePtr->code());
+ logger->setSilent(true);
+
+ auto setupFile = [&qmlFilePtr, &qmlFile, this](auto &&visitor) {
+ Q_UNUSED(this); // note: integrity requires "this" to be in the capture list, while
+ // other compilers complain about "this" being unused in the lambda
+ AST::Node::accept(qmlFilePtr->ast(), visitor);
+ CommentCollector collector(qmlFile);
+ collector.collectComments();
+ };
+
+ if (m_domCreationOptions.testFlag(DomCreationOption::WithSemanticAnalysis)) {
+ auto &analysis = semanticAnalysis();
+ auto scope = analysis.m_importer->importFile(qmlFile.canonicalFilePath());
+ auto v = std::make_unique<QQmlDomAstCreatorWithQQmlJSScope>(
+ scope, qmlFile, logger.get(), analysis.m_importer.get());
+ v->enableLoadFileLazily(true);
+ v->enableScriptExpressions(m_domCreationOptions.testFlag(DomCreationOption::WithScriptExpressions));
+
+ setupFile(v.get());
+
+ auto typeResolver =
+ std::make_shared<QQmlJSTypeResolver>(analysis.m_importer.get());
+ typeResolver->init(&v->scopeCreator(), nullptr);
+ qmlFilePtr->setTypeResolverWithDependencies(
+ typeResolver, { analysis.m_importer, analysis.m_mapper, std::move(logger) });
+ } else {
+ auto v = std::make_unique<QQmlDomAstCreator>(qmlFile);
+ v->enableScriptExpressions(
+ m_domCreationOptions.testFlag(DomCreationOption::WithScriptExpressions));
+
+ setupFile(v.get());
+ }
+ } else {
+ qCWarning(domLog) << "populateQmlFile called on non qmlFile";
+ return;
+ }
+}
+
+QString ExternalItemInfoBase::canonicalFilePath(const DomItem &self) const
{
shared_ptr<ExternalOwningItem> current = currentItem();
DomItem currentObj = currentItem(self);
return current->canonicalFilePath(currentObj);
}
-bool ExternalItemInfoBase::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool ExternalItemInfoBase::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
if (!self.dvValueLazyField(visitor, Fields::currentRevision,
[this, &self]() { return currentRevision(self); }))
@@ -2296,38 +2276,38 @@ bool ExternalItemInfoBase::iterateDirectSubpaths(DomItem &self, DirectVisitor vi
return true;
}
-int ExternalItemInfoBase::currentRevision(DomItem &) const
+int ExternalItemInfoBase::currentRevision(const DomItem &) const
{
return currentItem()->revision();
}
-int ExternalItemInfoBase::lastRevision(DomItem &self) const
+int ExternalItemInfoBase::lastRevision(const DomItem &self) const
{
Path p = currentItem()->canonicalPath();
DomItem lastValue = self.universe()[p.mid(1, p.length() - 1)].field(u"revision");
return static_cast<int>(lastValue.value().toInteger(0));
}
-int ExternalItemInfoBase::lastValidRevision(DomItem &self) const
+int ExternalItemInfoBase::lastValidRevision(const DomItem &self) const
{
Path p = currentItem()->canonicalPath();
DomItem lastValidValue = self.universe()[p.mid(1, p.length() - 2)].field(u"validItem").field(u"revision");
return static_cast<int>(lastValidValue.value().toInteger(0));
}
-QString ExternalItemPairBase::canonicalFilePath(DomItem &) const
+QString ExternalItemPairBase::canonicalFilePath(const DomItem &) const
{
shared_ptr<ExternalOwningItem> current = currentItem();
return current->canonicalFilePath();
}
-Path ExternalItemPairBase::canonicalPath(DomItem &) const
+Path ExternalItemPairBase::canonicalPath(const DomItem &) const
{
shared_ptr<ExternalOwningItem> current = currentItem();
return current->canonicalPath().dropTail();
}
-bool ExternalItemPairBase::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
+bool ExternalItemPairBase::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
{
if (!self.dvValueLazyField(visitor, Fields::currentIsValid,
[this]() { return currentIsValid(); }))
@@ -2349,7 +2329,7 @@ bool ExternalItemPairBase::currentIsValid() const
return currentItem() == validItem();
}
-RefCacheEntry RefCacheEntry::forPath(DomItem &el, Path canonicalPath)
+RefCacheEntry RefCacheEntry::forPath(const DomItem &el, const Path &canonicalPath)
{
DomItem env = el.environment();
std::shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>();
@@ -2365,7 +2345,7 @@ RefCacheEntry RefCacheEntry::forPath(DomItem &el, Path canonicalPath)
return cached;
}
-bool RefCacheEntry::addForPath(DomItem &el, Path canonicalPath, const RefCacheEntry &entry,
+bool RefCacheEntry::addForPath(const DomItem &el, const Path &canonicalPath, const RefCacheEntry &entry,
AddOption addOption)
{
DomItem env = el.environment();
diff --git a/src/qmldom/qqmldomtop_p.h b/src/qmldom/qqmldomtop_p.h
index f73a973906..afdea6b311 100644
--- a/src/qmldom/qqmldomtop_p.h
+++ b/src/qmldom/qqmldomtop_p.h
@@ -31,43 +31,21 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::Literals::StringLiterals;
+
namespace QQmlJS {
namespace Dom {
-class QMLDOM_EXPORT ParsingTask {
-public:
- QCborMap toCbor() const {
- return QCborMap(
- {{ QString::fromUtf16(Fields::requestedAt), QCborValue(requestedAt)},
- { QString::fromUtf16(Fields::loadOptions), int(loadOptions)},
- { QString::fromUtf16(Fields::kind), int(kind)},
- { QString::fromUtf16(Fields::canonicalPath), canonicalPath},
- { QString::fromUtf16(Fields::logicalPath), logicalPath},
- { QString::fromUtf16(Fields::contents), contents},
- { QString::fromUtf16(Fields::contentsDate), QCborValue(contentsDate)},
- { QString::fromUtf16(Fields::hasCallback), bool(callback)}});
- }
-
- QDateTime requestedAt;
- LoadOptions loadOptions;
- DomType kind;
- QString canonicalPath;
- QString logicalPath;
- QString contents;
- QDateTime contentsDate;
- std::weak_ptr<DomUniverse> requestingUniverse; // make it a shared_ptr?
- function<void(Path, DomItem &, DomItem &)> callback;
-};
-
class QMLDOM_EXPORT ExternalItemPairBase: public OwningItem { // all access should have the lock of the DomUniverse containing this
Q_DECLARE_TR_FUNCTIONS(ExternalItemPairBase);
public:
constexpr static DomType kindValue = DomType::ExternalItemPair;
DomType kind() const final override { return kindValue; }
- ExternalItemPairBase(QDateTime validExposedAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
- QDateTime currentExposedAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
- int derivedFrom = 0,
- QDateTime lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC))
+ ExternalItemPairBase(
+ const QDateTime &validExposedAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
+ const QDateTime &currentExposedAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
+ int derivedFrom = 0,
+ const QDateTime &lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC))
: OwningItem(derivedFrom, lastDataUpdateAt),
validExposedAt(validExposedAt),
currentExposedAt(currentExposedAt)
@@ -76,21 +54,21 @@ public:
OwningItem(o), validExposedAt(o.validExposedAt), currentExposedAt(o.currentExposedAt)
{}
virtual std::shared_ptr<ExternalOwningItem> validItem() const = 0;
- virtual DomItem validItem(DomItem &self) const = 0;
+ virtual DomItem validItem(const DomItem &self) const = 0;
virtual std::shared_ptr<ExternalOwningItem> currentItem() const = 0;
- virtual DomItem currentItem(DomItem &self) const = 0;
+ virtual DomItem currentItem(const DomItem &self) const = 0;
- QString canonicalFilePath(DomItem &) const final override;
- Path canonicalPath(DomItem &self) const final override;
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor) final override;
- DomItem field(DomItem &self, QStringView name) const final override
+ QString canonicalFilePath(const DomItem &) const final override;
+ Path canonicalPath(const DomItem &self) const final override;
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const final override;
+ DomItem field(const DomItem &self, QStringView name) const final override
{
return OwningItem::field(self, name);
}
bool currentIsValid() const;
- std::shared_ptr<ExternalItemPairBase> makeCopy(DomItem &self) const
+ std::shared_ptr<ExternalItemPairBase> makeCopy(const DomItem &self) const
{
return std::static_pointer_cast<ExternalItemPairBase>(doCopy(self));
}
@@ -104,9 +82,9 @@ public:
void refreshedDataAt(QDateTime tNew) final override
{
- return OwningItem::refreshedDataAt(tNew);
if (currentItem())
currentItem()->refreshedDataAt(tNew);
+ return OwningItem::refreshedDataAt(tNew);
}
friend class DomUniverse;
@@ -119,7 +97,7 @@ template<class T>
class QMLDOM_EXPORT ExternalItemPair final : public ExternalItemPairBase
{ // all access should have the lock of the DomUniverse containing this
protected:
- std::shared_ptr<OwningItem> doCopy(DomItem &) const override
+ std::shared_ptr<OwningItem> doCopy(const DomItem &) const override
{
return std::make_shared<ExternalItemPair>(*this);
}
@@ -127,11 +105,12 @@ protected:
public:
constexpr static DomType kindValue = DomType::ExternalItemPair;
friend class DomUniverse;
- ExternalItemPair(std::shared_ptr<T> valid = {}, std::shared_ptr<T> current = {},
- QDateTime validExposedAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
- QDateTime currentExposedAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
- int derivedFrom = 0,
- QDateTime lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC))
+ ExternalItemPair(
+ const std::shared_ptr<T> &valid = {}, const std::shared_ptr<T> &current = {},
+ const QDateTime &validExposedAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
+ const QDateTime &currentExposedAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
+ int derivedFrom = 0,
+ const QDateTime &lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC))
: ExternalItemPairBase(validExposedAt, currentExposedAt, derivedFrom, lastDataUpdateAt),
valid(valid),
current(current)
@@ -141,10 +120,10 @@ public:
{
}
std::shared_ptr<ExternalOwningItem> validItem() const override { return valid; }
- DomItem validItem(DomItem &self) const override { return self.copy(valid); }
+ DomItem validItem(const DomItem &self) const override { return self.copy(valid); }
std::shared_ptr<ExternalOwningItem> currentItem() const override { return current; }
- DomItem currentItem(DomItem &self) const override { return self.copy(current); }
- std::shared_ptr<ExternalItemPair> makeCopy(DomItem &self) const
+ DomItem currentItem(const DomItem &self) const override { return self.copy(current); }
+ std::shared_ptr<ExternalItemPair> makeCopy(const DomItem &self) const
{
return std::static_pointer_cast<ExternalItemPair>(doCopy(self));
}
@@ -171,11 +150,11 @@ public:
virtual Path canonicalPath() const = 0;
- Path canonicalPath(DomItem &) const override;
- DomItem containingObject(DomItem &) const override;
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override;
+ Path canonicalPath(const DomItem &) const override;
+ DomItem containingObject(const DomItem &) const override;
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override;
template<typename T>
- void setExtraOwningItem(QString fieldName, std::shared_ptr<T> item)
+ void setExtraOwningItem(const QString &fieldName, const std::shared_ptr<T> &item)
{
QMutexLocker l(mutex());
if (!item)
@@ -191,55 +170,55 @@ private:
QMap<QString, OwnerT> m_extraOwningItems;
};
-class QMLDOM_EXPORT DomUniverse final : public DomTop
+class QMLDOM_EXPORT DomUniverse final : public DomTop,
+ public std::enable_shared_from_this<DomUniverse>
{
Q_GADGET
Q_DECLARE_TR_FUNCTIONS(DomUniverse);
protected:
- std::shared_ptr<OwningItem> doCopy(DomItem &self) const override;
+ std::shared_ptr<OwningItem> doCopy(const DomItem &self) const override;
public:
- enum class Option{
- Default,
- SingleThreaded
- };
- Q_ENUM(Option)
- Q_DECLARE_FLAGS(Options, Option);
constexpr static DomType kindValue = DomType::DomUniverse;
DomType kind() const override { return kindValue; }
static ErrorGroups myErrors();
- DomUniverse(QString universeName, Options options = Option::SingleThreaded);
+ DomUniverse(const QString &universeName);
DomUniverse(const DomUniverse &) = delete;
- static std::shared_ptr<DomUniverse> guaranteeUniverse(std::shared_ptr<DomUniverse> univ);
- static DomItem create(QString universeName, Options options = Option::SingleThreaded);
+ static std::shared_ptr<DomUniverse> guaranteeUniverse(const std::shared_ptr<DomUniverse> &univ);
+ static DomItem create(const QString &universeName);
Path canonicalPath() const override;
using DomTop::canonicalPath;
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override;
- std::shared_ptr<DomUniverse> makeCopy(DomItem &self) const
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override;
+ std::shared_ptr<DomUniverse> makeCopy(const DomItem &self) const
{
return std::static_pointer_cast<DomUniverse>(doCopy(self));
}
- void loadFile(DomItem &self, QString filePath, QString logicalPath, Callback callback,
- LoadOptions loadOptions,
- std::optional<DomType> fileType = std::optional<DomType>());
- void loadFile(DomItem &self, QString canonicalFilePath, QString logicalPath, QString code,
- QDateTime codeDate, Callback callback, LoadOptions loadOptions,
- std::optional<DomType> fileType = std::optional<DomType>());
- void execQueue();
+ // Helper structure reflecting the change in the map once loading && parsing is completed
+ // formerItem - DomItem representing value (ExternalItemPair) existing in the map before the
+ // loading && parsing. Might be empty (if didn't exist / failure) or equal to currentItem
+ // currentItem - DomItem representing current map value
+ struct LoadResult
+ {
+ DomItem formerItem;
+ DomItem currentItem;
+ };
+
+ LoadResult loadFile(const FileToLoad &file, DomType fileType,
+ DomCreationOptions creationOptions = {});
void removePath(const QString &dir);
- std::shared_ptr<ExternalItemPair<GlobalScope>> globalScopeWithName(QString name) const
+ std::shared_ptr<ExternalItemPair<GlobalScope>> globalScopeWithName(const QString &name) const
{
QMutexLocker l(mutex());
return m_globalScopeWithName.value(name);
}
- std::shared_ptr<ExternalItemPair<GlobalScope>> ensureGlobalScopeWithName(QString name)
+ std::shared_ptr<ExternalItemPair<GlobalScope>> ensureGlobalScopeWithName(const QString &name)
{
if (auto current = globalScopeWithName(name))
return current;
@@ -263,7 +242,7 @@ public:
return QSet<QString>(map.keyBegin(), map.keyEnd());
}
- std::shared_ptr<ExternalItemPair<QmlDirectory>> qmlDirectoryWithPath(QString path) const
+ std::shared_ptr<ExternalItemPair<QmlDirectory>> qmlDirectoryWithPath(const QString &path) const
{
QMutexLocker l(mutex());
return m_qmlDirectoryWithPath.value(path);
@@ -278,7 +257,7 @@ public:
return QSet<QString>(map.keyBegin(), map.keyEnd());
}
- std::shared_ptr<ExternalItemPair<QmldirFile>> qmldirFileWithPath(QString path) const
+ std::shared_ptr<ExternalItemPair<QmldirFile>> qmldirFileWithPath(const QString &path) const
{
QMutexLocker l(mutex());
return m_qmldirFileWithPath.value(path);
@@ -293,7 +272,7 @@ public:
return QSet<QString>(map.keyBegin(), map.keyEnd());
}
- std::shared_ptr<ExternalItemPair<QmlFile>> qmlFileWithPath(QString path) const
+ std::shared_ptr<ExternalItemPair<QmlFile>> qmlFileWithPath(const QString &path) const
{
QMutexLocker l(mutex());
return m_qmlFileWithPath.value(path);
@@ -308,7 +287,7 @@ public:
return QSet<QString>(map.keyBegin(), map.keyEnd());
}
- std::shared_ptr<ExternalItemPair<JsFile>> jsFileWithPath(QString path) const
+ std::shared_ptr<ExternalItemPair<JsFile>> jsFileWithPath(const QString &path) const
{
QMutexLocker l(mutex());
return m_jsFileWithPath.value(path);
@@ -323,7 +302,7 @@ public:
return QSet<QString>(map.keyBegin(), map.keyEnd());
}
- std::shared_ptr<ExternalItemPair<QmltypesFile>> qmltypesFileWithPath(QString path) const
+ std::shared_ptr<ExternalItemPair<QmltypesFile>> qmltypesFileWithPath(const QString &path) const
{
QMutexLocker l(mutex());
return m_qmltypesFileWithPath.value(path);
@@ -341,37 +320,145 @@ public:
QString name() const {
return m_name;
}
- Options options() const {
- return m_options;
+
+private:
+ struct ContentWithDate
+ {
+ QString content;
+ QDateTime date;
+ };
+ // contains either Content with the timestamp when it was read or an Error
+ using ReadResult = std::variant<ContentWithDate, ErrorMessage>;
+ ReadResult readFileContent(const QString &canonicalPath) const;
+
+ LoadResult load(const ContentWithDate &codeWithDate, const FileToLoad &file, DomType fType,
+ DomCreationOptions creationOptions = {});
+
+ // contains either Content to be parsed or LoadResult if loading / parsing is not needed
+ using PreloadResult = std::variant<ContentWithDate, LoadResult>;
+ PreloadResult preload(const DomItem &univ, const FileToLoad &file, DomType fType) const;
+
+ std::shared_ptr<QmlFile> parseQmlFile(const QString &code, const FileToLoad &file,
+ const QDateTime &contentDate,
+ DomCreationOptions creationOptions);
+ std::shared_ptr<JsFile> parseJsFile(const QString &code, const FileToLoad &file,
+ const QDateTime &contentDate);
+ std::shared_ptr<ExternalItemPairBase> getPathValueOrNull(DomType fType,
+ const QString &path) const;
+ std::optional<DomItem> getItemIfMostRecent(const DomItem &univ, DomType fType,
+ const QString &path) const;
+ std::optional<DomItem> getItemIfHasSameCode(const DomItem &univ, DomType fType,
+ const QString &canonicalPath,
+ const ContentWithDate &codeWithDate) const;
+ static bool valueHasMostRecentItem(const ExternalItemPairBase *value,
+ const QDateTime &lastModified);
+ static bool valueHasSameContent(const ExternalItemPairBase *value, const QString &content);
+
+ // TODO better name / consider proper public get/set
+ template <typename T>
+ QMap<QString, std::shared_ptr<ExternalItemPair<T>>> &getMutableRefToMap()
+ {
+ Q_ASSERT(!mutex()->tryLock());
+ if constexpr (std::is_same_v<T, QmlDirectory>) {
+ return m_qmlDirectoryWithPath;
+ }
+ if constexpr (std::is_same_v<T, QmldirFile>) {
+ return m_qmldirFileWithPath;
+ }
+ if constexpr (std::is_same_v<T, QmlFile>) {
+ return m_qmlFileWithPath;
+ }
+ if constexpr (std::is_same_v<T, JsFile>) {
+ return m_jsFileWithPath;
+ }
+ if constexpr (std::is_same_v<T, QmltypesFile>) {
+ return m_qmltypesFileWithPath;
+ }
+ if constexpr (std::is_same_v<T, GlobalScope>) {
+ return m_globalScopeWithName;
+ }
+ Q_UNREACHABLE();
}
- QQueue<ParsingTask> queue() const {
- QMutexLocker l(mutex());
- return m_queue;
+
+ // Inserts or updates an entry reflecting ExternalItem in the corresponding map
+ // Returns a pair of:
+ // - current ExternalItemPair, current value in the map (might be empty, or equal to curValue)
+ // - new current ExternalItemPair, value in the map after after the execution of this function
+ template <typename T>
+ QPair<std::shared_ptr<ExternalItemPair<T>>, std::shared_ptr<ExternalItemPair<T>>>
+ insertOrUpdateEntry(std::shared_ptr<T> newItem)
+ {
+ std::shared_ptr<ExternalItemPair<T>> curValue;
+ std::shared_ptr<ExternalItemPair<T>> newCurValue;
+ QString canonicalPath = newItem->canonicalFilePath();
+ QDateTime now = QDateTime::currentDateTimeUtc();
+ {
+ QMutexLocker l(mutex());
+ auto &map = getMutableRefToMap<T>();
+ auto it = map.find(canonicalPath);
+ if (it != map.cend() && (*it) && (*it)->current) {
+ curValue = *it;
+ if (valueHasSameContent(curValue.get(), newItem->code())) {
+ // value in the map has same content as newItem, a.k.a. most recent
+ newCurValue = curValue;
+ if (newCurValue->current->lastDataUpdateAt() < newItem->lastDataUpdateAt()) {
+ // update timestamp in the current, as if its content was refreshed by
+ // NewItem
+ newCurValue->current->refreshedDataAt(newItem->lastDataUpdateAt());
+ }
+ } else if (curValue->current->lastDataUpdateAt() > newItem->lastDataUpdateAt()) {
+ // value in the map is more recent than newItem, nothing to update
+ newCurValue = curValue;
+ } else {
+ // perform update with newItem
+ curValue->current = std::move(newItem);
+ curValue->currentExposedAt = now;
+ if (curValue->current->isValid()) {
+ curValue->valid = curValue->current;
+ curValue->validExposedAt = std::move(now);
+ }
+ newCurValue = curValue;
+ }
+ } else {
+ // not found / invalid, just insert
+ newCurValue = std::make_shared<ExternalItemPair<T>>(
+ (newItem->isValid() ? newItem : std::shared_ptr<T>()), newItem, now, now);
+ map.insert(canonicalPath, newCurValue);
+ }
+ }
+ return qMakePair(curValue, newCurValue);
+ }
+
+ // Inserts or updates an entry reflecting ExternalItem in the corresponding map
+ // returns LoadResult reflecting the change made to the map
+ template <typename T>
+ LoadResult insertOrUpdateExternalItem(std::shared_ptr<T> extItem)
+ {
+ auto change = insertOrUpdateEntry<T>(std::move(extItem));
+ DomItem univ(shared_from_this());
+ return { univ.copy(change.first), univ.copy(change.second) };
}
private:
QString m_name;
- Options m_options;
QMap<QString, std::shared_ptr<ExternalItemPair<GlobalScope>>> m_globalScopeWithName;
QMap<QString, std::shared_ptr<ExternalItemPair<QmlDirectory>>> m_qmlDirectoryWithPath;
QMap<QString, std::shared_ptr<ExternalItemPair<QmldirFile>>> m_qmldirFileWithPath;
QMap<QString, std::shared_ptr<ExternalItemPair<QmlFile>>> m_qmlFileWithPath;
QMap<QString, std::shared_ptr<ExternalItemPair<JsFile>>> m_jsFileWithPath;
QMap<QString, std::shared_ptr<ExternalItemPair<QmltypesFile>>> m_qmltypesFileWithPath;
- QQueue<ParsingTask> m_queue;
};
- Q_DECLARE_OPERATORS_FOR_FLAGS(DomUniverse::Options)
-
class QMLDOM_EXPORT ExternalItemInfoBase: public OwningItem {
Q_DECLARE_TR_FUNCTIONS(ExternalItemInfoBase);
public:
constexpr static DomType kindValue = DomType::ExternalItemInfo;
DomType kind() const final override { return kindValue; }
- ExternalItemInfoBase(Path canonicalPath,
- QDateTime currentExposedAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
- int derivedFrom = 0,
- QDateTime lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC))
+ ExternalItemInfoBase(
+ const Path &canonicalPath,
+ const QDateTime &currentExposedAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
+ int derivedFrom = 0,
+ const QDateTime &lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC))
: OwningItem(derivedFrom, lastDataUpdateAt),
m_canonicalPath(canonicalPath),
m_currentExposedAt(currentExposedAt)
@@ -379,22 +466,22 @@ public:
ExternalItemInfoBase(const ExternalItemInfoBase &o) = default;
virtual std::shared_ptr<ExternalOwningItem> currentItem() const = 0;
- virtual DomItem currentItem(DomItem &) const = 0;
+ virtual DomItem currentItem(const DomItem &) const = 0;
- QString canonicalFilePath(DomItem &) const final override;
+ QString canonicalFilePath(const DomItem &) const final override;
Path canonicalPath() const { return m_canonicalPath; }
- Path canonicalPath(DomItem &) const final override { return canonicalPath(); }
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor) final override;
- DomItem field(DomItem &self, QStringView name) const final override
+ Path canonicalPath(const DomItem &) const final override { return canonicalPath(); }
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const final override;
+ DomItem field(const DomItem &self, QStringView name) const final override
{
return OwningItem::field(self, name);
}
- int currentRevision(DomItem &self) const;
- int lastRevision(DomItem &self) const;
- int lastValidRevision(DomItem &self) const;
+ int currentRevision(const DomItem &self) const;
+ int lastRevision(const DomItem &self) const;
+ int lastValidRevision(const DomItem &self) const;
- std::shared_ptr<ExternalItemInfoBase> makeCopy(DomItem &self) const
+ std::shared_ptr<ExternalItemInfoBase> makeCopy(const DomItem &self) const
{
return std::static_pointer_cast<ExternalItemInfoBase>(doCopy(self));
}
@@ -408,12 +495,12 @@ public:
void refreshedDataAt(QDateTime tNew) final override
{
- return OwningItem::refreshedDataAt(tNew);
if (currentItem())
currentItem()->refreshedDataAt(tNew);
+ return OwningItem::refreshedDataAt(tNew);
}
- void ensureLogicalFilePath(QString path) {
+ void ensureLogicalFilePath(const QString &path) {
QMutexLocker l(mutex());
if (!m_logicalFilePaths.contains(path))
m_logicalFilePaths.append(path);
@@ -446,28 +533,29 @@ template<typename T>
class ExternalItemInfo final : public ExternalItemInfoBase
{
protected:
- std::shared_ptr<OwningItem> doCopy(DomItem &) const override
+ std::shared_ptr<OwningItem> doCopy(const DomItem &) const override
{
return std::make_shared<ExternalItemInfo>(*this);
}
public:
constexpr static DomType kindValue = DomType::ExternalItemInfo;
- ExternalItemInfo(std::shared_ptr<T> current = std::shared_ptr<T>(),
- QDateTime currentExposedAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
- int derivedFrom = 0,
- QDateTime lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC))
+ ExternalItemInfo(
+ const std::shared_ptr<T> &current = std::shared_ptr<T>(),
+ const QDateTime &currentExposedAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC),
+ int derivedFrom = 0,
+ const QDateTime &lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC))
: ExternalItemInfoBase(current->canonicalPath().dropTail(), currentExposedAt, derivedFrom,
lastDataUpdateAt),
current(current)
{}
- ExternalItemInfo(QString canonicalPath) : current(new T(canonicalPath)) { }
+ ExternalItemInfo(const QString &canonicalPath) : current(new T(canonicalPath)) { }
ExternalItemInfo(const ExternalItemInfo &o):
ExternalItemInfoBase(o), current(o.current)
{
}
- std::shared_ptr<ExternalItemInfo> makeCopy(DomItem &self) const
+ std::shared_ptr<ExternalItemInfo> makeCopy(const DomItem &self) const
{
return std::static_pointer_cast<ExternalItemInfo>(doCopy(self));
}
@@ -475,7 +563,7 @@ public:
std::shared_ptr<ExternalOwningItem> currentItem() const override {
return current;
}
- DomItem currentItem(DomItem &self) const override { return self.copy(current); }
+ DomItem currentItem(const DomItem &self) const override { return self.copy(current); }
std::shared_ptr<T> current;
};
@@ -499,7 +587,7 @@ class QMLDOM_EXPORT LoadInfo final : public OwningItem
Q_DECLARE_TR_FUNCTIONS(LoadInfo);
protected:
- std::shared_ptr<OwningItem> doCopy(DomItem &self) const override;
+ std::shared_ptr<OwningItem> doCopy(const DomItem &self) const override;
public:
constexpr static DomType kindValue = DomType::LoadInfo;
@@ -513,9 +601,9 @@ public:
Done // fully loaded
};
- LoadInfo(Path elPath = Path(), Status status = Status::NotStarted, int nLoaded = 0,
+ LoadInfo(const Path &elPath = Path(), Status status = Status::NotStarted, int nLoaded = 0,
int derivedFrom = 0,
- QDateTime lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC))
+ const QDateTime &lastDataUpdateAt = QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC))
: OwningItem(derivedFrom, lastDataUpdateAt),
m_elementCanonicalPath(elPath),
m_status(status),
@@ -534,23 +622,23 @@ public:
}
}
- Path canonicalPath(DomItem &self) const override;
+ Path canonicalPath(const DomItem &self) const override;
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override;
- std::shared_ptr<LoadInfo> makeCopy(DomItem &self) const
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override;
+ std::shared_ptr<LoadInfo> makeCopy(const DomItem &self) const
{
return std::static_pointer_cast<LoadInfo>(doCopy(self));
}
- void addError(DomItem &self, ErrorMessage msg) override
+ void addError(const DomItem &self, ErrorMessage &&msg) override
{
- self.path(elementCanonicalPath()).addError(msg);
+ self.path(elementCanonicalPath()).addError(std::move(msg));
}
- void addEndCallback(DomItem &self, std::function<void(Path, DomItem &, DomItem &)> callback);
+ void addEndCallback(const DomItem &self, std::function<void(Path, const DomItem &, const DomItem &)> callback);
- void advanceLoad(DomItem &self);
- void finishedLoadingDep(DomItem &self, const Dependency &d);
- void execEnd(DomItem &self);
+ void advanceLoad(const DomItem &self);
+ void finishedLoadingDep(const DomItem &self, const Dependency &d);
+ void execEnd(const DomItem &self);
Status status() const
{
@@ -595,15 +683,15 @@ public:
}
private:
- void doAddDependencies(DomItem &self);
- void addDependency(DomItem &self, const Dependency &dep);
+ void doAddDependencies(const DomItem &self);
+ void addDependency(const DomItem &self, const Dependency &dep);
Path m_elementCanonicalPath;
Status m_status;
int m_nLoaded;
QQueue<Dependency> m_toDo;
QList<Dependency> m_inProgress;
- QList<std::function<void(Path, DomItem &, DomItem &)>> m_endCallbacks;
+ QList<std::function<void(Path, const DomItem &, const DomItem &)>> m_endCallbacks;
};
enum class EnvLookup { Normal, NoBase, BaseOnly };
@@ -617,21 +705,31 @@ public:
enum class Cached { None, First, All };
Q_ENUM(Cached)
- static RefCacheEntry forPath(DomItem &el, Path canonicalPath);
- static bool addForPath(DomItem &el, Path canonicalPath, const RefCacheEntry &entry,
+ static RefCacheEntry forPath(const DomItem &el, const Path &canonicalPath);
+ static bool addForPath(const DomItem &el, const Path &canonicalPath, const RefCacheEntry &entry,
AddOption addOption = AddOption::KeepExisting);
Cached cached = Cached::None;
QList<Path> canonicalPaths;
};
-class QMLDOM_EXPORT DomEnvironment final : public DomTop
+class QMLDOM_EXPORT DomEnvironment final : public DomTop,
+ public std::enable_shared_from_this<DomEnvironment>
{
Q_GADGET
Q_DECLARE_TR_FUNCTIONS(DomEnvironment);
protected:
- std::shared_ptr<OwningItem> doCopy(DomItem &self) const override;
+ std::shared_ptr<OwningItem> doCopy(const DomItem &self) const override;
+private:
+ struct TypeReader
+ {
+ std::weak_ptr<DomEnvironment> m_env;
+
+ QList<QQmlJS::DiagnosticMessage>
+ operator()(QQmlJSImporter *importer, const QString &filePath,
+ const QSharedPointer<QQmlJSScope> &scopeToPopulate);
+ };
public:
enum class Option {
Default = 0x0,
@@ -651,121 +749,336 @@ public:
Path canonicalPath() const override;
using DomTop::canonicalPath;
- bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override;
- DomItem field(DomItem &self, QStringView name) const final override;
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override;
+ DomItem field(const DomItem &self, QStringView name) const final override;
- std::shared_ptr<DomEnvironment> makeCopy(DomItem &self) const;
+ std::shared_ptr<DomEnvironment> makeCopy(const DomItem &self) const;
- void loadFile(DomItem &self, QString filePath, QString logicalPath, Callback loadCallback,
- Callback directDepsCallback, Callback endCallback, LoadOptions loadOptions,
+ void loadFile(const FileToLoad &file, const Callback &callback,
std::optional<DomType> fileType = std::optional<DomType>(),
- ErrorHandler h = nullptr);
- void loadFile(DomItem &self, QString canonicalFilePath, QString logicalPath, QString code,
- QDateTime codeDate, Callback loadCallback, Callback directDepsCallback,
- Callback endCallback, LoadOptions loadOptions,
- std::optional<DomType> fileType = std::optional<DomType>(),
- ErrorHandler h = nullptr);
- void loadModuleDependency(DomItem &self, QString uri, Version v,
- Callback loadCallback = nullptr, Callback endCallback = nullptr,
- ErrorHandler = nullptr);
- void loadBuiltins(DomItem &self, Callback callback = nullptr, ErrorHandler h = nullptr);
+ const ErrorHandler &h = nullptr /* used only in loadPendingDependencies*/);
+ void loadBuiltins(const Callback &callback = nullptr, const ErrorHandler &h = nullptr);
+ void loadModuleDependency(const QString &uri, Version v, const Callback &callback = nullptr,
+ const ErrorHandler & = nullptr);
+
void removePath(const QString &path);
std::shared_ptr<DomUniverse> universe() const;
- QSet<QString> moduleIndexUris(DomItem &self, EnvLookup lookup = EnvLookup::Normal) const;
- QSet<int> moduleIndexMajorVersions(DomItem &self, QString uri,
+ QSet<QString> moduleIndexUris(const DomItem &self, EnvLookup lookup = EnvLookup::Normal) const;
+ QSet<int> moduleIndexMajorVersions(const DomItem &self, const QString &uri,
EnvLookup lookup = EnvLookup::Normal) const;
- std::shared_ptr<ModuleIndex> moduleIndexWithUri(DomItem &self, QString uri, int majorVersion,
+ std::shared_ptr<ModuleIndex> moduleIndexWithUri(const DomItem &self, const QString &uri, int majorVersion,
EnvLookup lookup, Changeable changeable,
- ErrorHandler errorHandler = nullptr);
- std::shared_ptr<ModuleIndex> moduleIndexWithUri(DomItem &self, QString uri, int majorVersion,
+ const ErrorHandler &errorHandler = nullptr);
+ std::shared_ptr<ModuleIndex> moduleIndexWithUri(const DomItem &self, const QString &uri, int majorVersion,
EnvLookup lookup = EnvLookup::Normal) const;
std::shared_ptr<ExternalItemInfo<QmlDirectory>>
- qmlDirectoryWithPath(DomItem &self, QString path, EnvLookup options = EnvLookup::Normal) const;
- QSet<QString> qmlDirectoryPaths(DomItem &self, EnvLookup options = EnvLookup::Normal) const;
+ qmlDirectoryWithPath(const DomItem &self, const QString &path, EnvLookup options = EnvLookup::Normal) const;
+ QSet<QString> qmlDirectoryPaths(const DomItem &self, EnvLookup options = EnvLookup::Normal) const;
std::shared_ptr<ExternalItemInfo<QmldirFile>>
- qmldirFileWithPath(DomItem &self, QString path, EnvLookup options = EnvLookup::Normal) const;
- QSet<QString> qmldirFilePaths(DomItem &self, EnvLookup options = EnvLookup::Normal) const;
+ qmldirFileWithPath(const DomItem &self, const QString &path, EnvLookup options = EnvLookup::Normal) const;
+ QSet<QString> qmldirFilePaths(const DomItem &self, EnvLookup options = EnvLookup::Normal) const;
std::shared_ptr<ExternalItemInfoBase>
- qmlDirWithPath(DomItem &self, QString path, EnvLookup options = EnvLookup::Normal) const;
- QSet<QString> qmlDirPaths(DomItem &self, EnvLookup options = EnvLookup::Normal) const;
+ qmlDirWithPath(const DomItem &self, const QString &path, EnvLookup options = EnvLookup::Normal) const;
+ QSet<QString> qmlDirPaths(const DomItem &self, EnvLookup options = EnvLookup::Normal) const;
std::shared_ptr<ExternalItemInfo<QmlFile>>
- qmlFileWithPath(DomItem &self, QString path, EnvLookup options = EnvLookup::Normal) const;
- QSet<QString> qmlFilePaths(DomItem &self, EnvLookup lookup = EnvLookup::Normal) const;
+ qmlFileWithPath(const DomItem &self, const QString &path, EnvLookup options = EnvLookup::Normal) const;
+ QSet<QString> qmlFilePaths(const DomItem &self, EnvLookup lookup = EnvLookup::Normal) const;
std::shared_ptr<ExternalItemInfo<JsFile>>
- jsFileWithPath(DomItem &self, QString path, EnvLookup options = EnvLookup::Normal) const;
- QSet<QString> jsFilePaths(DomItem &self, EnvLookup lookup = EnvLookup::Normal) const;
+ jsFileWithPath(const DomItem &self, const QString &path, EnvLookup options = EnvLookup::Normal) const;
+ QSet<QString> jsFilePaths(const DomItem &self, EnvLookup lookup = EnvLookup::Normal) const;
std::shared_ptr<ExternalItemInfo<QmltypesFile>>
- qmltypesFileWithPath(DomItem &self, QString path, EnvLookup options = EnvLookup::Normal) const;
- QSet<QString> qmltypesFilePaths(DomItem &self, EnvLookup lookup = EnvLookup::Normal) const;
+ qmltypesFileWithPath(const DomItem &self, const QString &path, EnvLookup options = EnvLookup::Normal) const;
+ QSet<QString> qmltypesFilePaths(const DomItem &self, EnvLookup lookup = EnvLookup::Normal) const;
std::shared_ptr<ExternalItemInfo<GlobalScope>>
- globalScopeWithName(DomItem &self, QString name, EnvLookup lookup = EnvLookup::Normal) const;
+ globalScopeWithName(const DomItem &self, const QString &name, EnvLookup lookup = EnvLookup::Normal) const;
std::shared_ptr<ExternalItemInfo<GlobalScope>>
- ensureGlobalScopeWithName(DomItem &self, QString name, EnvLookup lookup = EnvLookup::Normal);
- QSet<QString> globalScopeNames(DomItem &self, EnvLookup lookup = EnvLookup::Normal) const;
-
- explicit DomEnvironment(QStringList loadPaths, Options options = Option::SingleThreaded,
- std::shared_ptr<DomUniverse> universe = nullptr);
- explicit DomEnvironment(std::shared_ptr<DomEnvironment> parent, QStringList loadPaths,
- Options options = Option::SingleThreaded);
+ ensureGlobalScopeWithName(const DomItem &self, const QString &name, EnvLookup lookup = EnvLookup::Normal);
+ QSet<QString> globalScopeNames(const DomItem &self, EnvLookup lookup = EnvLookup::Normal) const;
+
+ explicit DomEnvironment(const QStringList &loadPaths, Options options = Option::SingleThreaded,
+ DomCreationOptions domCreationOptions = None,
+ const std::shared_ptr<DomUniverse> &universe = nullptr);
+ explicit DomEnvironment(const std::shared_ptr<DomEnvironment> &parent,
+ const QStringList &loadPaths, Options options = Option::SingleThreaded,
+ DomCreationOptions domCreationOptions = None);
DomEnvironment(const DomEnvironment &o) = delete;
- static DomItem create(QStringList loadPaths, Options options = Option::SingleThreaded,
- DomItem &universe = DomItem::empty);
-
- std::shared_ptr<ExternalItemInfo<QmlFile>>
- addQmlFile(std::shared_ptr<QmlFile> file, AddOption option = AddOption::KeepExisting);
- std::shared_ptr<ExternalItemInfo<QmlDirectory>>
- addQmlDirectory(std::shared_ptr<QmlDirectory> file, AddOption option = AddOption::KeepExisting);
- std::shared_ptr<ExternalItemInfo<QmldirFile>>
- addQmldirFile(std::shared_ptr<QmldirFile> file, AddOption option = AddOption::KeepExisting);
- std::shared_ptr<ExternalItemInfo<QmltypesFile>>
- addQmltypesFile(std::shared_ptr<QmltypesFile> file, AddOption option = AddOption::KeepExisting);
- std::shared_ptr<ExternalItemInfo<JsFile>> addJsFile(std::shared_ptr<JsFile> file,
- AddOption option = AddOption::KeepExisting);
- std::shared_ptr<ExternalItemInfo<GlobalScope>>
- addGlobalScope(std::shared_ptr<GlobalScope> file, AddOption option = AddOption::KeepExisting);
-
- bool commitToBase(DomItem &self, std::shared_ptr<DomEnvironment> validEnv = nullptr);
-
- void addLoadInfo(DomItem &self, std::shared_ptr<LoadInfo> loadInfo);
- std::shared_ptr<LoadInfo> loadInfo(Path path) const;
+ static std::shared_ptr<DomEnvironment>
+ create(const QStringList &loadPaths, Options options = Option::SingleThreaded,
+ DomCreationOptions creationOptions = DomCreationOption::None,
+ const DomItem &universe = DomItem::empty);
+
+ // TODO AddOption can easily be removed later. KeepExisting option only used in one
+ // place which will be removed in https://codereview.qt-project.org/c/qt/qtdeclarative/+/523217
+ void addQmlFile(const std::shared_ptr<QmlFile> &file,
+ AddOption option = AddOption::KeepExisting);
+ void addQmlDirectory(const std::shared_ptr<QmlDirectory> &file,
+ AddOption option = AddOption::KeepExisting);
+ void addQmldirFile(const std::shared_ptr<QmldirFile> &file,
+ AddOption option = AddOption::KeepExisting);
+ void addQmltypesFile(const std::shared_ptr<QmltypesFile> &file,
+ AddOption option = AddOption::KeepExisting);
+ void addJsFile(const std::shared_ptr<JsFile> &file, AddOption option = AddOption::KeepExisting);
+ void addGlobalScope(const std::shared_ptr<GlobalScope> &file,
+ AddOption option = AddOption::KeepExisting);
+
+ bool commitToBase(
+ const DomItem &self, const std::shared_ptr<DomEnvironment> &validEnv = nullptr);
+
+ void addDependenciesToLoad(const Path &path);
+ void addLoadInfo(
+ const DomItem &self, const std::shared_ptr<LoadInfo> &loadInfo);
+ std::shared_ptr<LoadInfo> loadInfo(const Path &path) const;
QList<Path> loadInfoPaths() const;
QHash<Path, std::shared_ptr<LoadInfo>> loadInfos() const;
- void loadPendingDependencies(DomItem &self);
- bool finishLoadingDependencies(DomItem &self, int waitMSec = 30000);
- void addWorkForLoadInfo(Path elementCanonicalPath);
+ void loadPendingDependencies();
+ bool finishLoadingDependencies(int waitMSec = 30000);
+ void addWorkForLoadInfo(const Path &elementCanonicalPath);
Options options() const;
std::shared_ptr<DomEnvironment> base() const;
QStringList loadPaths() const;
+ QStringList qmldirFiles() const;
QString globalScopeName() const;
static QList<Import> defaultImplicitImports();
QList<Import> implicitImports() const;
- void addAllLoadedCallback(DomItem &self, Callback c);
+ void addAllLoadedCallback(const DomItem &self, Callback c);
void clearReferenceCache();
void setLoadPaths(const QStringList &v);
+ // Helper structure reflecting the change in the map once loading / fetching is completed
+ // formerItem - DomItem representing value (ExternalItemInfo) existing in the map before the
+ // loading && parsing. Might be empty (if didn't exist / failure) or equal to currentItem
+ // currentItem - DomItem representing current map value
+ struct LoadResult
+ {
+ DomItem formerItem;
+ DomItem currentItem;
+ };
+ // TODO(QTBUG-121171)
+ template <typename T>
+ LoadResult insertOrUpdateExternalItemInfo(const QString &path, std::shared_ptr<T> extItem)
+ {
+ // maybe in the next revision this all can be just substituted by the addExternalItem
+ DomItem env(shared_from_this());
+ // try to fetch from the current env.
+ if (auto curValue = lookup<T>(path, EnvLookup::NoBase)) {
+ // found in the "initial" env
+ return { env.copy(curValue), env.copy(curValue) };
+ }
+ std::shared_ptr<ExternalItemInfo<T>> newCurValue;
+ // try to fetch from the base env
+ auto valueInBase = lookup<T>(path, EnvLookup::BaseOnly);
+ if (!valueInBase) {
+ // Nothing found. Just create an externalItemInfo which will be inserted
+ newCurValue = std::make_shared<ExternalItemInfo<T>>(std::move(extItem),
+ QDateTime::currentDateTimeUtc());
+ } else {
+ // prepare updated value as a copy of the value from the Base to be inserted
+ newCurValue = valueInBase->makeCopy(env);
+ if (newCurValue->current != extItem) {
+ newCurValue->current = std::move(extItem);
+ newCurValue->setCurrentExposedAt(QDateTime::currentDateTimeUtc());
+ }
+ }
+ // Before inserting new or updated value, check one more time, if ItemInfo is already
+ // present
+ // lookup<> can't be used here because of the data-race
+ {
+ QMutexLocker l(mutex());
+ auto &map = getMutableRefToMap<T>();
+ const auto &it = map.find(path);
+ if (it != map.end())
+ return { env.copy(*it), env.copy(*it) };
+ // otherwise insert
+ map.insert(path, newCurValue);
+ }
+ return { env.copy(valueInBase), env.copy(newCurValue) };
+ }
+
+ template <typename T>
+ void addExternalItemInfo(const DomItem &newExtItem, const Callback &loadCallback,
+ const Callback &endCallback)
+ {
+ // get either Valid "file" from the ExternalItemPair or the current (wip) "file"
+ std::shared_ptr<T> newItemPtr;
+ if (options() & DomEnvironment::Option::KeepValid)
+ newItemPtr = newExtItem.field(Fields::validItem).ownerAs<T>();
+ if (!newItemPtr)
+ newItemPtr = newExtItem.field(Fields::currentItem).ownerAs<T>();
+ Q_ASSERT(newItemPtr && "envCallbackForFile reached without current file");
+
+ auto loadResult = insertOrUpdateExternalItemInfo(newExtItem.canonicalFilePath(),
+ std::move(newItemPtr));
+ Path p = loadResult.currentItem.canonicalPath();
+ {
+ auto depLoad = qScopeGuard([p, this, endCallback] {
+ addDependenciesToLoad(p);
+ // add EndCallback to the queue, which should be called once all dependencies are
+ // loaded
+ if (endCallback) {
+ DomItem env = DomItem(shared_from_this());
+ addAllLoadedCallback(
+ env, [p, endCallback](Path, const DomItem &, const DomItem &env) {
+ DomItem el = env.path(p);
+ endCallback(p, el, el);
+ });
+ }
+ });
+ // call loadCallback
+ if (loadCallback) {
+ loadCallback(p, loadResult.formerItem, loadResult.currentItem);
+ }
+ }
+ }
+ void populateFromQmlFile(MutableDomItem &&qmlFile);
+ DomCreationOptions domCreationOptions() const { return m_domCreationOptions; }
+
private:
friend class RefCacheEntry;
- template<typename T>
+
+ void loadFile(const FileToLoad &file, const Callback &loadCallback, const Callback &endCallback,
+ std::optional<DomType> fileType = std::optional<DomType>(),
+ const ErrorHandler &h = nullptr);
+
+ void loadModuleDependency(const DomItem &self, const QString &uri, Version v,
+ Callback loadCallback = nullptr, Callback endCallback = nullptr,
+ const ErrorHandler & = nullptr);
+
+ template <typename T>
QSet<QString> getStrings(function_ref<QSet<QString>()> getBase, const QMap<QString, T> &selfMap,
EnvLookup lookup) const;
- Callback callbackForQmlDirectory(DomItem &self, Callback loadCallback,
- Callback directDepsCallback, Callback endCallback);
- Callback callbackForQmlFile(DomItem &self, Callback loadCallback, Callback directDepsCallback,
- Callback endCallback);
- Callback callbackForQmltypesFile(DomItem &self, Callback loadCallback,
- Callback directDepsCallback, Callback endCallback);
- Callback callbackForQmldirFile(DomItem &self, Callback loadCallback,
- Callback directDepsCallback, Callback endCallback);
+ template <typename T>
+ const QMap<QString, std::shared_ptr<ExternalItemInfo<T>>> &getConstRefToMap() const
+ {
+ Q_ASSERT(!mutex()->tryLock());
+ if constexpr (std::is_same_v<T, GlobalScope>) {
+ return m_globalScopeWithName;
+ }
+ if constexpr (std::is_same_v<T, QmlDirectory>) {
+ return m_qmlDirectoryWithPath;
+ }
+ if constexpr (std::is_same_v<T, QmldirFile>) {
+ return m_qmldirFileWithPath;
+ }
+ if constexpr (std::is_same_v<T, QmlFile>) {
+ return m_qmlFileWithPath;
+ }
+ if constexpr (std::is_same_v<T, JsFile>) {
+ return m_jsFileWithPath;
+ }
+ if constexpr (std::is_same_v<T, QmltypesFile>) {
+ return m_qmltypesFileWithPath;
+ }
+ Q_UNREACHABLE();
+ }
+
+ template <typename T>
+ std::shared_ptr<ExternalItemInfo<T>> lookup(const QString &path, EnvLookup options) const
+ {
+ if (options != EnvLookup::BaseOnly) {
+ QMutexLocker l(mutex());
+ const auto &map = getConstRefToMap<T>();
+ const auto &it = map.find(path);
+ if (it != map.end())
+ return *it;
+ }
+ if (options != EnvLookup::NoBase && m_base)
+ return m_base->lookup<T>(path, options);
+ return {};
+ }
+
+ template <typename T>
+ QMap<QString, std::shared_ptr<ExternalItemInfo<T>>> &getMutableRefToMap()
+ {
+ Q_ASSERT(!mutex()->tryLock());
+ if constexpr (std::is_same_v<T, QmlDirectory>) {
+ return m_qmlDirectoryWithPath;
+ }
+ if constexpr (std::is_same_v<T, QmldirFile>) {
+ return m_qmldirFileWithPath;
+ }
+ if constexpr (std::is_same_v<T, QmlFile>) {
+ return m_qmlFileWithPath;
+ }
+ if constexpr (std::is_same_v<T, JsFile>) {
+ return m_jsFileWithPath;
+ }
+ if constexpr (std::is_same_v<T, QmltypesFile>) {
+ return m_qmltypesFileWithPath;
+ }
+ if constexpr (std::is_same_v<T, GlobalScope>) {
+ return m_globalScopeWithName;
+ }
+ Q_UNREACHABLE();
+ }
+
+ template <typename T>
+ void addExternalItem(std::shared_ptr<T> file, QString key, AddOption option)
+ {
+ if (!file)
+ return;
+
+ auto eInfo = std::make_shared<ExternalItemInfo<T>>(file, QDateTime::currentDateTimeUtc());
+ // Lookup helper can't be used here, because it introduces data-race otherwise
+ // (other modifications might happen between the lookup and the insert)
+ QMutexLocker l(mutex());
+ auto &map = getMutableRefToMap<T>();
+ const auto &it = map.find(key);
+ if (it != map.end() && option == AddOption::KeepExisting)
+ return;
+ map.insert(key, eInfo);
+ }
+
+ using FetchResult =
+ QPair<std::shared_ptr<ExternalItemInfoBase>, std::shared_ptr<ExternalItemInfoBase>>;
+ // This function tries to get an Info object about the ExternalItem from the current env
+ // and depending on the result and options tries to fetch it from the Parent env,
+ // saving a copy with an updated timestamp
+ template <typename T>
+ FetchResult fetchFileFromEnvs(const FileToLoad &file)
+ {
+ const auto &path = file.canonicalPath();
+ // lookup only in the current env
+ if (auto value = lookup<T>(path, EnvLookup::NoBase)) {
+ return qMakePair(value, value);
+ }
+ // try to find the file in the base(parent) Env and insert if found
+ if (options() & Option::NoReload) {
+ if (auto baseV = lookup<T>(path, EnvLookup::BaseOnly)) {
+ // Watch out! QTBUG-121171
+ // It's possible between the lookup and creation of curVal, baseV && baseV->current
+ // might have changed
+ // Prepare a value to be inserted as copy of the value from Base
+ auto curV = std::make_shared<ExternalItemInfo<T>>(
+ baseV->current, QDateTime::currentDateTimeUtc(), baseV->revision(),
+ baseV->lastDataUpdateAt());
+ // Lookup one more time if the value was already inserted to the current env
+ // Lookup can't be used here because of the data-race
+ {
+ QMutexLocker l(mutex());
+ auto &map = getMutableRefToMap<T>();
+ const auto &it = map.find(path);
+ if (it != map.end())
+ return qMakePair(*it, *it);
+ // otherwise insert
+ map.insert(path, curV);
+ }
+ return qMakePair(baseV, curV);
+ }
+ }
+ return qMakePair(nullptr, nullptr);
+ }
+
+ Callback getLoadCallbackFor(DomType fileType, const Callback &loadCallback);
std::shared_ptr<ModuleIndex> lookupModuleInEnv(const QString &uri, int majorVersion) const;
// ModuleLookupResult contains the ModuleIndex pointer, and an indicator whether it was found
@@ -776,11 +1089,12 @@ private:
Origin fromBase = FromGlobal;
};
// helper function used by the moduleIndexWithUri methods
- ModuleLookupResult moduleIndexWithUriHelper(DomItem &self, QString uri, int majorVersion,
+ ModuleLookupResult moduleIndexWithUriHelper(const DomItem &self, const QString &uri, int majorVersion,
EnvLookup lookup = EnvLookup::Normal) const;
const Options m_options;
const std::shared_ptr<DomEnvironment> m_base;
+ std::shared_ptr<DomEnvironment> m_lastValidBase;
const std::shared_ptr<DomUniverse> m_universe;
QStringList m_loadPaths; // paths for qml
QString m_globalScopeName;
@@ -797,6 +1111,18 @@ private:
QList<Import> m_implicitImports;
QList<Callback> m_allLoadedCallback;
QHash<Path, RefCacheEntry> m_referenceCache;
+ DomCreationOptions m_domCreationOptions;
+
+ struct SemanticAnalysis
+ {
+ SemanticAnalysis(const QStringList &loadPaths);
+ void setLoadPaths(const QStringList &loadPaths);
+
+ std::shared_ptr<QQmlJSResourceFileMapper> m_mapper;
+ std::shared_ptr<QQmlJSImporter> m_importer;
+ };
+ std::optional<SemanticAnalysis> m_semanticAnalysis;
+ SemanticAnalysis &semanticAnalysis();
};
Q_DECLARE_OPERATORS_FOR_FLAGS(DomEnvironment::Options)
diff --git a/src/qmldom/qqmldomtypesreader.cpp b/src/qmldom/qqmldomtypesreader.cpp
index 3f83130234..ae1ec7fb94 100644
--- a/src/qmldom/qqmldomtypesreader.cpp
+++ b/src/qmldom/qqmldomtypesreader.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2020 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmldomtypesreader_p.h"
#include "qqmldomelements_p.h"
@@ -9,11 +9,7 @@
#include <QtQml/private/qqmljsparser_p.h>
#include <QtQml/private/qqmljslexer_p.h>
#include <QtQml/private/qqmljsengine_p.h>
-#ifdef QMLDOM_STANDALONE
-# include "qmlcompiler/qqmljstypedescriptionreader_p.h"
-#else
-# include <private/qqmljstypedescriptionreader_p.h>
-#endif
+#include <private/qqmljstypedescriptionreader_p.h>
#include <QtCore/qdir.h>
@@ -24,15 +20,16 @@ namespace Dom {
using namespace QQmlJS::AST;
-static ErrorGroups myParseErrors()
+static ErrorGroups readerParseErrors()
{
static ErrorGroups errs = { { NewErrorGroup("Dom"), NewErrorGroup("QmltypesFile"),
NewErrorGroup("Parsing") } };
return errs;
}
-void QmltypesReader::insertProperty(QQmlJSScope::Ptr jsScope, const QQmlJSMetaProperty &property,
- QMap<int, QmlObject> &objs)
+void QmltypesReader::insertProperty(
+ const QQmlJSScope::ConstPtr &jsScope, const QQmlJSMetaProperty &property,
+ QMap<int, QmlObject> &objs)
{
PropertyDefinition prop;
prop.name = property.propertyName();
@@ -49,7 +46,7 @@ void QmltypesReader::insertProperty(QQmlJSScope::Ptr jsScope, const QQmlJSMetaPr
prop.notify = property.notify();
if (prop.name.isEmpty() || prop.typeName.isEmpty()) {
- addError(myParseErrors()
+ addError(readerParseErrors()
.warning(tr("Property object is missing a name or type script binding."))
.handle());
return;
@@ -63,11 +60,11 @@ void QmltypesReader::insertSignalOrMethod(const QQmlJSMetaMethod &metaMethod,
MethodInfo methodInfo;
// ### confusion between Method and Slot. Method should be removed.
switch (metaMethod.methodType()) {
- case QQmlJSMetaMethod::Method:
- case QQmlJSMetaMethod::Slot:
+ case QQmlJSMetaMethodType::Method:
+ case QQmlJSMetaMethodType::Slot:
methodInfo.methodType = MethodInfo::MethodType::Method;
break;
- case QQmlJSMetaMethod::Signal:
+ case QQmlJSMetaMethodType::Signal:
methodInfo.methodType = MethodInfo::MethodType::Signal;
break;
default:
@@ -86,7 +83,7 @@ void QmltypesReader::insertSignalOrMethod(const QQmlJSMetaMethod &metaMethod,
int revision = metaMethod.revision();
methodInfo.isConstructor = metaMethod.isConstructor();
if (methodInfo.name.isEmpty()) {
- addError(myParseErrors().error(tr("Method or signal is missing a name.")).handle());
+ addError(readerParseErrors().error(tr("Method or signal is missing a name.")).handle());
return;
}
@@ -112,20 +109,26 @@ EnumDecl QmltypesReader::enumFromMetaEnum(const QQmlJSMetaEnum &metaEnum)
return res;
}
-void QmltypesReader::insertComponent(const QQmlJSScope::Ptr &jsScope,
+void QmltypesReader::insertComponent(const QQmlJSScope::ConstPtr &jsScope,
const QList<QQmlJSScope::Export> &exportsList)
{
QmltypesComponent comp;
+ comp.setSemanticScope(jsScope);
QMap<int, QmlObject> objects;
{
bool hasExports = false;
for (const QQmlJSScope::Export &jsE : exportsList) {
int metaRev = jsE.version().toEncodedVersion<int>();
hasExports = true;
- objects.insert(metaRev, QmlObject());
+ QmlObject object;
+ object.setSemanticScope(jsScope);
+ objects.insert(metaRev, object);
+ }
+ if (!hasExports) {
+ QmlObject object;
+ object.setSemanticScope(jsScope);
+ objects.insert(0, object);
}
- if (!hasExports)
- objects.insert(0, QmlObject());
}
bool incrementedPath = false;
QString prototype;
@@ -176,6 +179,7 @@ void QmltypesReader::insertComponent(const QQmlJSScope::Ptr &jsScope,
comp.setValueTypeName(jsScope->valueTypeName());
comp.setAccessSemantics(jsScope->accessSemantics());
comp.setExtensionTypeName(jsScope->extensionTypeName());
+ comp.setExtensionIsJavaScript(jsScope->extensionIsJavaScript());
comp.setExtensionIsNamespace(jsScope->extensionIsNamespace());
Path exportSourcePath = qmltypesFile().canonicalPath();
QMap<int, Path> revToPath;
@@ -193,7 +197,7 @@ void QmltypesReader::insertComponent(const QQmlJSScope::Ptr &jsScope,
while (it != begin) {
--it;
if (it.key() < 0) {
- addError(myParseErrors().error(
+ addError(readerParseErrors().error(
tr("negative meta revision %1 not supported").arg(it.key())));
}
revToPath.insert(it.key(), compPath.field(Fields::objects).index(objectIndex));
@@ -219,6 +223,7 @@ void QmltypesReader::insertComponent(const QQmlJSScope::Ptr &jsScope,
Export e;
e.uri = jsE.package();
e.typeName = jsE.type();
+ e.isSingleton = jsScope->isSingleton();
e.version = Version((v.hasMajorVersion() ? v.majorVersion() : Version::Latest),
(v.hasMinorVersion() ? v.minorVersion() : Version::Latest));
e.typePath = revToPath.value(metaRev);
@@ -230,7 +235,7 @@ void QmltypesReader::insertComponent(const QQmlJSScope::Ptr &jsScope,
}
if (comp.name().isEmpty()) {
- addError(myParseErrors()
+ addError(readerParseErrors()
.error(tr("Component definition is missing a name binding."))
.handle());
return;
@@ -246,14 +251,14 @@ bool QmltypesReader::parse()
qmltypesFilePtr()->code());
QStringList dependencies;
QList<QQmlJSExportedScope> objects;
- m_isValid = reader(&objects, &dependencies);
+ const bool isValid = reader(&objects, &dependencies);
for (const auto &obj : std::as_const(objects))
insertComponent(obj.scope, obj.exports);
- qmltypesFilePtr()->setIsValid(m_isValid);
- return m_isValid;
+ qmltypesFilePtr()->setIsValid(isValid);
+ return isValid;
}
-void QmltypesReader::addError(ErrorMessage message)
+void QmltypesReader::addError(ErrorMessage &&message)
{
if (message.file.isEmpty())
message.file = qmltypesFile().canonicalFilePath();
diff --git a/src/qmldom/qqmldomtypesreader_p.h b/src/qmldom/qqmldomtypesreader_p.h
index 7794ed16ff..dda0b8f5b3 100644
--- a/src/qmldom/qqmldomtypesreader_p.h
+++ b/src/qmldom/qqmldomtypesreader_p.h
@@ -1,5 +1,5 @@
// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLDOMTYPESREADER_H
#define QQMLDOMTYPESREADER_H
@@ -20,13 +20,9 @@
// for Q_DECLARE_TR_FUNCTIONS
#include <QtCore/qcoreapplication.h>
-#ifdef QMLDOM_STANDALONE
-# include "qmlcompiler/qqmljsmetatypes_p.h"
-# include "qmlcompiler/qqmljsscope_p.h"
-#else
-# include <private/qqmljsmetatypes_p.h>
-# include <private/qqmljsscope_p.h>
-#endif
+#include <private/qqmljsmetatypes_p.h>
+#include <private/qqmljsscope_p.h>
+
QT_BEGIN_NAMESPACE
namespace QQmlJS {
@@ -36,7 +32,7 @@ class QmltypesReader
{
Q_DECLARE_TR_FUNCTIONS(TypeDescriptionReader)
public:
- explicit QmltypesReader(DomItem qmltypesFile)
+ explicit QmltypesReader(const DomItem &qmltypesFile)
: m_qmltypesFilePtr(qmltypesFile.ownerAs<QmltypesFile>()), m_qmltypesFile(qmltypesFile)
{
}
@@ -44,12 +40,12 @@ public:
bool parse();
// static void read
private:
- void addError(ErrorMessage message);
+ void addError(ErrorMessage &&message);
- void insertProperty(QQmlJSScope::Ptr jsScope, const QQmlJSMetaProperty &property,
+ void insertProperty(const QQmlJSScope::ConstPtr &jsScope, const QQmlJSMetaProperty &property,
QMap<int, QmlObject> &objs);
void insertSignalOrMethod(const QQmlJSMetaMethod &metaMethod, QMap<int, QmlObject> &objs);
- void insertComponent(const QQmlJSScope::Ptr &jsScope,
+ void insertComponent(const QQmlJSScope::ConstPtr &jsScope,
const QList<QQmlJSScope::Export> &exportsList);
EnumDecl enumFromMetaEnum(const QQmlJSMetaEnum &metaEnum);
@@ -57,11 +53,10 @@ private:
DomItem &qmltypesFile() { return m_qmltypesFile; }
ErrorHandler handler()
{
- return [this](ErrorMessage m) { this->addError(m); };
+ return [this](const ErrorMessage &m) { this->addError(ErrorMessage(m)); };
}
private:
- bool m_isValid;
std::shared_ptr<QmltypesFile> m_qmltypesFilePtr;
DomItem m_qmltypesFile;
Path m_currentPath;
diff --git a/src/qmldom/standalone/CMakeLists.txt b/src/qmldom/standalone/CMakeLists.txt
deleted file mode 100644
index 68def86a20..0000000000
--- a/src/qmldom/standalone/CMakeLists.txt
+++ /dev/null
@@ -1,80 +0,0 @@
-# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
-
-cmake_minimum_required(VERSION 3.16)
-
-include(../../../.cmake.conf)
-project(standalone_qmldom LANGUAGES CXX VERSION "${QT_REPO_MODULE_VERSION}")
-option(QMLDOM_EXTERNAL_BUILD "If the build is against an external Qt, and not tested inside a build of this Qt" ON)
-
-if (QMLDOM_EXTERNAL_BUILD)
-find_package(Qt6 COMPONENTS Core Qml)
-set(CMAKE_AUTOMOC ON)
-endif()
-
-set(CMAKE_CXX_STANDARD_REQUIRED ON)
-
-if(MSVC)
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj")
-elseif (MINGW)
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wa,-mbig-obj")
-endif()
-
-
-add_library(qmldomlib
- STATIC
- private/qtqmlcompilerexports_p.h
- ../../qmlcompiler/qcoloroutput.cpp ../../qmlcompiler/qcoloroutput_p.h
- ../../qmlcompiler/qdeferredpointer_p.h
- ../../qmlcompiler/qqmljsannotation.cpp ../../qmlcompiler/qqmljsannotation_p.h
- ../../qmlcompiler/qqmljsimporter.cpp ../../qmlcompiler/qqmljsimporter_p.h
- ../../qmlcompiler/qqmljsimportvisitor.cpp ../../qmlcompiler/qqmljsimportvisitor_p.h
- ../../qmlcompiler/qqmljslogger.cpp ../../qmlcompiler/qqmljslogger_p.h
- ../../qmlcompiler/qqmljsmetatypes.cpp ../../qmlcompiler/qqmljsmetatypes_p.h
- ../../qmlcompiler/qqmljsresourcefilemapper.cpp ../../qmlcompiler/qqmljsresourcefilemapper_p.h
- ../../qmlcompiler/qqmljsscope.cpp ../../qmlcompiler/qqmljsscope_p.h
- ../../qmlcompiler/qqmljsscopesbyid_p.h
- ../../qmlcompiler/qqmljsutils.cpp ../../qmlcompiler/qqmljsutils_p.h
- ../../qmlcompiler/qqmljstypedescriptionreader.cpp ../../qmlcompiler/qqmljstypedescriptionreader_p.h
- ../../qmlcompiler/qqmljstypereader.cpp ../../qmlcompiler/qqmljstypereader_p.h
- ../../qmlcompiler/qqmljstyperesolver.cpp ../../qmlcompiler/qqmljstyperesolver_p.h
- ../../qmlcompiler/qqmljsregistercontent.cpp ../../qmlcompiler/qqmljsregistercontent_p.h
- ../qqmldom_fwd_p.h
- ../qqmldom_global.h
- ../qqmldomastcreator.cpp ../qqmldomastcreator_p.h
- ../qqmldomastdumper.cpp ../qqmldomastdumper_p.h
- ../qqmldomattachedinfo.cpp ../qqmldomattachedinfo_p.h
- ../qqmldomcodeformatter.cpp ../qqmldomcodeformatter_p.h
- ../qqmldomcomments.cpp ../qqmldomcomments_p.h
- ../qqmldomcompare.cpp ../qqmldomcompare_p.h
- ../qqmldomconstants_p.h
- ../qqmldomelements.cpp ../qqmldomelements_p.h
- ../qqmldomerrormessage.cpp ../qqmldomerrormessage_p.h
- ../qqmldomexternalitems.cpp ../qqmldomexternalitems_p.h
- ../qqmldomfieldfilter.cpp ../qqmldomfieldfilter_p.h
- ../qqmldomfilewriter.cpp ../qqmldomfilewriter_p.h
- ../qqmldomfunctionref_p.h
- ../qqmldomitem.cpp ../qqmldomitem_p.h
- ../qqmldomlinewriter.cpp ../qqmldomlinewriter_p.h
- ../qqmldommock.cpp ../qqmldommock_p.h
- ../qqmldommoduleindex.cpp ../qqmldommoduleindex_p.h
- ../qqmldomoutwriter.cpp ../qqmldomoutwriter_p.h
- ../qqmldompath.cpp ../qqmldompath_p.h
- ../qqmldomreformatter.cpp ../qqmldomreformatter_p.h
- ../qqmldomscanner.cpp ../qqmldomscanner_p.h
- ../qqmldomstringdumper.cpp ../qqmldomstringdumper_p.h
- ../qqmldomtop.cpp ../qqmldomtop_p.h
- ../qqmldomtypesreader.cpp ../qqmldomtypesreader_p.h
-)
-if(NOT QMLDOM_EXTERNAL_BUILD)
- qt_autogen_tools_initial_setup(qmldomlib)
-endif()
-
-target_compile_definitions(qmldomlib PUBLIC QMLDOM_STANDALONE)
-
-target_include_directories(qmldomlib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../..)
-target_link_libraries(qmldomlib
- PUBLIC
- Qt::CorePrivate
- Qt::QmlPrivate
-)
diff --git a/src/qmldom/standalone/private/qtqmlcompilerexports_p.h b/src/qmldom/standalone/private/qtqmlcompilerexports_p.h
deleted file mode 100644
index a8b6d86456..0000000000
--- a/src/qmldom/standalone/private/qtqmlcompilerexports_p.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (C) 2022 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_global.h"
-#ifndef QTQMLCOMPILEREXPORTS_P_H
-#define QTQMLCOMPILEREXPORTS_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#define Q_QMLCOMPILER_PRIVATE_EXPORT QMLDOM_EXPORT
-#endif