aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmldom/qqmldomitem_p.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/qmldom/qqmldomitem_p.h')
-rw-r--r--src/qmldom/qqmldomitem_p.h2579
1 files changed, 1878 insertions, 701 deletions
diff --git a/src/qmldom/qqmldomitem_p.h b/src/qmldom/qqmldomitem_p.h
index 92535b87ac..50775a1db2 100644
--- a/src/qmldom/qqmldomitem_p.h
+++ b/src/qmldom/qqmldomitem_p.h
@@ -1,40 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**/
+// 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
+
#ifndef QMLDOMITEM_H
#define QMLDOMITEM_H
@@ -51,24 +17,36 @@
#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"
#include "qqmldomerrormessage_p.h"
+#include "qqmldomfunctionref_p.h"
+#include "qqmldomfilewriter_p.h"
+#include "qqmldomlinewriter_p.h"
+#include "qqmldomfieldfilter_p.h"
#include <QtCore/QMap>
#include <QtCore/QMultiMap>
+#include <QtCore/QSet>
#include <QtCore/QString>
#include <QtCore/QStringView>
#include <QtCore/QDebug>
#include <QtCore/QDateTime>
#include <QtCore/QMutex>
#include <QtCore/QCborValue>
+#include <QtCore/QTimeZone>
#include <QtQml/private/qqmljssourcelocation_p.h>
+#include <QtQmlCompiler/private/qqmljsscope_p.h>
#include <memory>
#include <typeinfo>
#include <utility>
+#include <type_traits>
+#include <variant>
+#include <optional>
+#include <cstddef>
QT_BEGIN_NAMESPACE
@@ -78,50 +56,193 @@ namespace Dom {
class Path;
-bool domTypeIsObjWrap(DomType k);
-bool domTypeIsDomElement(DomType);
-bool domTypeIsOwningItem(DomType);
-bool domTypeIsExternalItem(DomType k);
-bool domTypeIsTopItem(DomType k);
-bool domTypeIsContainer(DomType k);
-bool domTypeCanBeInline(DomType k);
+Q_DECLARE_LOGGING_CATEGORY(writeOutLog);
+
+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);
+constexpr bool domTypeCanBeInline(DomType k)
+{
+ switch (k) {
+ case DomType::Empty:
+ case DomType::Map:
+ case DomType::List:
+ case DomType::ListP:
+ case DomType::ConstantData:
+ case DomType::SimpleObjectWrap:
+ case DomType::ScriptElementWrap:
+ case DomType::Reference:
+ return true;
+ default:
+ return false;
+ }
+}
+QMLDOM_EXPORT bool domTypeIsScope(DomType k);
QMLDOM_EXPORT QMap<DomType,QString> domTypeToStringMap();
QMLDOM_EXPORT QString domTypeToString(DomType k);
+QMLDOM_EXPORT QMap<DomKind, QString> domKindToStringMap();
+QMLDOM_EXPORT QString domKindToString(DomKind k);
+
+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, const DomItem &)>;
+
+namespace {
+template<typename T>
+struct IsMultiMap : std::false_type
+{
+};
+
+template<typename Key, typename T>
+struct IsMultiMap<QMultiMap<Key, T>> : std::true_type
+{
+};
+
+template<typename T>
+struct IsMap : std::false_type
+{
+};
+
+template<typename Key, typename T>
+struct IsMap<QMap<Key, T>> : std::true_type
+{
+};
+
+template<typename... Ts>
+using void_t = void;
+
+template<typename T, typename = void>
+struct IsDomObject : std::false_type
+{
+};
+
+template<typename T>
+struct IsDomObject<T, void_t<decltype(T::kindValue)>> : std::true_type
+{
+};
+
+template<typename T, typename = void>
+struct IsInlineDom : std::false_type
+{
+};
+
+template<typename T>
+struct IsInlineDom<T, void_t<decltype(T::kindValue)>>
+ : std::integral_constant<bool, domTypeCanBeInline(T::kindValue)>
+{
+};
+
+template<typename T>
+struct IsInlineDom<T *, void_t<decltype(T::kindValue)>> : std::true_type
+{
+};
+
+template<typename T>
+struct IsInlineDom<std::shared_ptr<T>, void_t<decltype(T::kindValue)>> : std::true_type
+{
+};
+
+template<typename T>
+struct IsSharedPointerToDomObject : std::false_type
+{
+};
+
+template<typename T>
+struct IsSharedPointerToDomObject<std::shared_ptr<T>> : IsDomObject<T>
+{
+};
+
+template<typename T, typename = void>
+struct IsList : std::false_type
+{
+};
+
+template<typename T>
+struct IsList<T, void_t<typename T::value_type>> : std::true_type
+{
+};
+
+}
+
+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()); }
+ SubclassStorage(const SubclassStorage &o) : SubclassStorage(o.data()) { }
+ SubclassStorage(const SubclassStorage &&o) : SubclassStorage(o.data()) { }
+ SubclassStorage &operator=(const SubclassStorage &o)
+ {
+ data()->~T();
+ o.data()->copyTo(data());
+ return *this;
+ }
+ ~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(const DomItem &self) const = 0;
virtual Path canonicalPath(const DomItem &self) const = 0;
- virtual bool iterateDirectSubpaths(DomItem &self, std::function<bool(Path, DomItem &)>) = 0; // iterates the *direct* subpaths, returns false if a quick end was requested
- bool iterateDirectSubpathsConst(const DomItem &self, std::function<bool(Path, const DomItem &)>) const; // iterates the *direct* subpaths, returns false if a quick end was requested
+ virtual bool
+ 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(const DomItem &self) const; // the DomItem corresponding to the canonicalSource source
- virtual void dump(const DomItem &, Sink sink, int indent) const;
+ virtual DomItem containingObject(
+ 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;
- virtual QString typeName() const;
+ QString typeName() const;
- virtual QList<QString> const fields(const DomItem &self) const;
+ virtual QList<QString> fields(const DomItem &self) const;
virtual DomItem field(const DomItem &self, QStringView name) const;
virtual index_type indexes(const DomItem &self) const;
virtual DomItem index(const DomItem &self, index_type index) const;
virtual QSet<QString> const keys(const DomItem &self) const;
- virtual DomItem key(const DomItem &self, QString name) const;
+ virtual DomItem key(const DomItem &self, const QString &name) const;
virtual QString canonicalFilePath(const DomItem &self) const;
- virtual SourceLocation location(const DomItem &self) const;
+
+ virtual void writeOut(const DomItem &self, OutWriter &lw) const;
virtual QCborValue value() const {
return QCborValue();
}
-
};
inline DomKind kind2domKind(DomType k)
@@ -130,6 +251,7 @@ inline DomKind kind2domKind(DomType k)
case DomType::Empty:
return DomKind::Empty;
case DomType::List:
+ case DomType::ListP:
return DomKind::List;
case DomType::Map:
return DomKind::Map;
@@ -140,80 +262,128 @@ inline DomKind kind2domKind(DomType k)
}
}
-class QMLDOM_EXPORT Empty: public DomBase {
+class QMLDOM_EXPORT Empty final : public DomBase
+{
public:
constexpr static DomType kindValue = DomType::Empty;
DomType kind() const override { return kindValue; }
+ Empty *operator->() { return this; }
+ const Empty *operator->() const { return this; }
+ Empty &operator*() { return *this; }
+ const Empty &operator*() const { return *this; }
+
Empty();
+ quintptr id() const override { return ~quintptr(0); }
Path pathFromOwner(const DomItem &self) const override;
Path canonicalPath(const DomItem &self) const override;
DomItem containingObject(const DomItem &self) const override;
- bool iterateDirectSubpaths(DomItem &self, std::function<bool (Path, DomItem &)>) override;
- void dump(const DomItem &, Sink s, int indent) 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;
};
class QMLDOM_EXPORT DomElement: public DomBase {
protected:
DomElement& operator=(const DomElement&) = default;
public:
- DomElement(Path pathFromOwner = Path(), const SourceLocation & loc = SourceLocation());
+ DomElement(const Path &pathFromOwner = Path());
DomElement(const DomElement &o) = default;
Path pathFromOwner(const DomItem &self) const override;
Path pathFromOwner() const { return m_pathFromOwner; }
Path canonicalPath(const DomItem &self) const override;
DomItem containingObject(const DomItem &self) const override;
- virtual void updatePathFromOwner(Path newPath);
- SourceLocation location(const DomItem &self) const override;
+ virtual void updatePathFromOwner(const Path &newPath);
- SourceLocation loc;
private:
Path m_pathFromOwner;
};
-class QMLDOM_EXPORT Map: public DomElement {
+class QMLDOM_EXPORT Map final : public DomElement
+{
public:
constexpr static DomType kindValue = DomType::Map;
DomType kind() const override { return kindValue; }
- using LookupFunction = std::function<DomItem (const DomItem&, QString)>;
- using Keys = std::function<QSet<QString> (const DomItem &)>;
- Map(Path pathFromOwner, LookupFunction lookup, Keys keys, QString targetType);
+ Map *operator->() { return this; }
+ const Map *operator->() const { return this; }
+ Map &operator*() { return *this; }
+ const Map &operator*() const { return *this; }
+
+ 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, std::function<bool(Path, DomItem &)>) override;
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override;
QSet<QString> const keys(const DomItem &self) const override;
- DomItem key(const DomItem &self, QString name) const override;
+ DomItem key(const DomItem &self, const QString &name) const override;
+
+ template<typename T>
+ 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(
+ 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);
- template <typename T>
- static Map fromMultiMapRef(Path pathFromOwner, QMultiMap<QString,T> &mmap, std::function<DomItem(const DomItem &, Path, T&)> elWrapper);
- template <typename T>
- static Map fromMapRef(Path pathFromOwner, QMap<QString,T> &mmap, std::function<DomItem(const DomItem &, Path, T&)> elWrapper);
private:
+ template<typename MapT>
+ static QSet<QString> fileRegionKeysFromMap(const MapT &map);
LookupFunction m_lookup;
Keys m_keys;
QString m_targetType;
};
-class QMLDOM_EXPORT List: public DomElement {
+class QMLDOM_EXPORT List final : public DomElement
+{
public:
constexpr static DomType kindValue = DomType::List;
DomType kind() const override { return kindValue; }
- using LookupFunction = std::function<DomItem (const DomItem &, index_type)>;
- using Length = std::function<index_type (const DomItem &)>;
- using IteratorFunction = std::function<bool (const DomItem &, std::function<bool(index_type,DomItem &)>)>;
+ List *operator->() { return this; }
+ const List *operator->() const { return this; }
+ List &operator*() { return *this; }
+ const List &operator*() const { return *this; }
- List(Path pathFromOwner, LookupFunction lookup, Length length, IteratorFunction iterator, QString elType);
+ using LookupFunction = std::function<DomItem(const DomItem &, index_type)>;
+ using Length = std::function<index_type(const DomItem &)>;
+ using IteratorFunction =
+ std::function<bool(const DomItem &, function_ref<bool(index_type, function_ref<DomItem()>)>)>;
+
+ List(const Path &pathFromOwner, const LookupFunction &lookup, const Length &length,
+ const IteratorFunction &iterator, const QString &elType);
quintptr id() const override;
- bool iterateDirectSubpaths(DomItem &self, std::function<bool(Path, DomItem &)>) override;
- void dump(const DomItem &, Sink s, int indent) 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 &)>) 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(const DomItem &, Path, T&)> elWrapper, ListOptions options = ListOptions::Normal);
+ static List
+ 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(const DomItem &, Path, T&)> elWrapper, ListOptions options = ListOptions::Normal);
+ static List
+ 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(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;
Length m_length;
@@ -221,18 +391,103 @@ private:
QString m_elType;
};
-class QMLDOM_EXPORT ConstantData: public DomElement {
+class QMLDOM_EXPORT ListPBase : public DomElement
+{
+public:
+ constexpr static DomType kindValue = DomType::ListP;
+ DomType kind() const override { return kindValue; }
+
+ ListPBase(const Path &pathFromOwner, const QList<const void *> &pList, const QString &elType)
+ : DomElement(pathFromOwner), m_pList(pList), m_elType(elType)
+ {
+ }
+ 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(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<const void *> m_pList;
+ QString m_elType;
+};
+
+template<typename T>
+class ListPT final : public ListPBase
+{
+public:
+ constexpr static DomType kindValue = DomType::ListP;
+
+ 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))
+ {
+ static_assert(sizeof(ListPBase) == sizeof(ListPT),
+ "ListPT does not have the same size as ListPBase");
+ static_assert(alignof(ListPBase) == alignof(ListPT),
+ "ListPT does not have the same size as ListPBase");
+ m_pList.reserve(pList.size());
+ if (options == ListOptions::Normal) {
+ for (const void *p : pList)
+ m_pList.append(p);
+ } else if (options == ListOptions::Reverse) {
+ for (qsizetype i = pList.size(); i-- != 0;)
+ // probably writing in reverse and reading sequentially would be better
+ m_pList.append(pList.at(i));
+ } else {
+ Q_ASSERT(false);
+ }
+ }
+ void copyTo(ListPBase *t) const override { new (t) ListPT(*this); }
+ void moveTo(ListPBase *t) const override { new (t) ListPT(std::move(*this)); }
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor v) const override;
+
+ DomItem index(const DomItem &self, index_type index) const override;
+};
+
+class QMLDOM_EXPORT ListP
+{
+public:
+ constexpr static DomType kindValue = DomType::ListP;
+ template<typename T>
+ ListP(const Path &pathFromOwner, const QList<T *> &pList, const QString &elType = QString(),
+ ListOptions options = ListOptions::Normal)
+ : list(ListPT<T>(pathFromOwner, pList, elType, options))
+ {
+ }
+ ListP() = delete;
+
+ ListPBase *operator->() { return list.data(); }
+ const ListPBase *operator->() const { return list.data(); }
+ ListPBase &operator*() { return *list.data(); }
+ const ListPBase &operator*() const { return *list.data(); }
+
+private:
+ SubclassStorage<ListPBase> list;
+};
+
+class QMLDOM_EXPORT ConstantData final : public DomElement
+{
public:
constexpr static DomType kindValue = DomType::ConstantData;
- DomType kind() const override { return kindValue; }
+ DomType kind() const override { return kindValue; }
enum class Options {
MapIsMap,
FirstMapIsFields
};
- ConstantData(Path pathFromOwner, QCborValue value, Options options = Options::MapIsMap, const SourceLocation & loc = SourceLocation());
- bool iterateDirectSubpaths(DomItem &self, std::function<bool(Path, DomItem &)>) override;
+ ConstantData *operator->() { return this; }
+ const ConstantData *operator->() const { return this; }
+ ConstantData &operator*() { return *this; }
+ const ConstantData &operator*() const { return *this; }
+
+ 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; }
@@ -242,157 +497,595 @@ private:
Options m_options;
};
-class QMLDOM_EXPORT SimpleObjectWrap: public DomElement {
+class QMLDOM_EXPORT SimpleObjectWrapBase : public DomElement
+{
public:
constexpr static DomType kindValue = DomType::SimpleObjectWrap;
- DomType kind() const override { return kindValue; }
+ DomType kind() const final override { return m_kind; }
- template <typename T>
- static SimpleObjectWrap fromDataObject(
- Path pathFromOwner, T const & val,
- std::function<QCborValue(T const &)> toData,
- const SourceLocation & loc = SourceLocation(),
- DomType kind = kindValue,
- DomKind domKind = DomKind::Object,
- QString typeName = QString());
+ quintptr id() const final override { return m_id; }
+ DomKind domKind() const final override { return m_domKind; }
template <typename T>
- static SimpleObjectWrap fromObjectRef(
- Path pathFromOwner, T &value,
- std::function<bool(DomItem &, T &val, std::function<bool(Path, DomItem &)>)> directSubpathsIterate,
- const SourceLocation & loc = SourceLocation(),
- DomType kind = kindValue,
- QString typeName = QString(),
- DomKind domKind = DomKind::Object);
-
- bool iterateDirectSubpaths(DomItem &self, std::function<bool(Path, DomItem &)>) override;
- quintptr id() const override;
- QString typeName() const override { return m_typeName; }
- DomType internalKind() const { return m_kind; }
- DomKind domKind() const override { return m_domKind; }
- template <typename T>
T const *as() const
{
- return m_value.value<T*>();
+ if (m_options & SimpleWrapOption::ValueType) {
+ if (m_value.metaType() == QMetaType::fromType<T>())
+ return static_cast<const T *>(m_value.constData());
+ return nullptr;
+ } else {
+ return m_value.value<const T *>();
+ }
}
- template <typename T>
- T *mutableAs()
+
+ SimpleObjectWrapBase() = delete;
+ virtual void copyTo(SimpleObjectWrapBase *) const { Q_ASSERT(false); }
+ virtual void moveTo(SimpleObjectWrapBase *) const { Q_ASSERT(false); }
+ bool iterateDirectSubpaths(const DomItem &, DirectVisitor) const override
+ {
+ Q_ASSERT(false);
+ return true;
+ }
+
+protected:
+ friend class TestDomItem;
+ SimpleObjectWrapBase(const Path &pathFromOwner, const QVariant &value, quintptr idValue,
+ DomType kind = kindValue,
+ SimpleWrapOptions options = SimpleWrapOption::None)
+ : DomElement(pathFromOwner),
+ m_kind(kind),
+ m_domKind(kind2domKind(kind)),
+ m_value(value),
+ m_id(idValue),
+ m_options(options)
{
- return m_value.value<T*>();
}
-private:
- SimpleObjectWrap(
- Path pathFromOwner, QVariant value,
- std::function<bool(DomItem &, QVariant, std::function<bool(Path, DomItem &)>)> directSubpathsIterate,
- DomType kind = kindValue,
- DomKind domKind = DomKind::Object,
- QString typeName = QString(),
- const SourceLocation & loc = SourceLocation());
DomType m_kind;
DomKind m_domKind;
- QString m_typeName;
QVariant m_value;
- std::function<bool(DomItem &, QVariant, std::function<bool(Path, DomItem &)>)> m_directSubpathsIterate;
+ quintptr m_id;
+ SimpleWrapOptions m_options;
};
-class QMLDOM_EXPORT Reference: public DomElement {
+template<typename T>
+class SimpleObjectWrapT final : public SimpleObjectWrapBase
+{
+public:
+ constexpr static DomType kindValue = DomType::SimpleObjectWrap;
+
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override
+ {
+ return asT()->iterateDirectSubpaths(self, visitor);
+ }
+
+ void writeOut(const DomItem &self, OutWriter &lw) const override;
+
+ const T *asT() const
+ {
+ if constexpr (domTypeIsValueWrap(T::kindValue)) {
+ if (m_value.metaType() == QMetaType::fromType<T>())
+ return static_cast<const T *>(m_value.constData());
+ return nullptr;
+ } else if constexpr (domTypeIsObjWrap(T::kindValue)) {
+ 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");
+ return nullptr; // necessary to avoid warnings on INTEGRITY
+ }
+ }
+
+ void copyTo(SimpleObjectWrapBase *target) const override
+ {
+ static_assert(sizeof(SimpleObjectWrapBase) == sizeof(SimpleObjectWrapT),
+ "Size mismatch in SimpleObjectWrapT");
+ static_assert(alignof(SimpleObjectWrapBase) == alignof(SimpleObjectWrapT),
+ "Size mismatch in SimpleObjectWrapT");
+ new (target) SimpleObjectWrapT(*this);
+ }
+
+ void moveTo(SimpleObjectWrapBase *target) const override
+ {
+ static_assert(sizeof(SimpleObjectWrapBase) == sizeof(SimpleObjectWrapT),
+ "Size mismatch in SimpleObjectWrapT");
+ static_assert(alignof(SimpleObjectWrapBase) == alignof(SimpleObjectWrapT),
+ "Size mismatch in SimpleObjectWrapT");
+ new (target) SimpleObjectWrapT(std::move(*this));
+ }
+
+ 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));
+ }
+};
+
+class QMLDOM_EXPORT SimpleObjectWrap
+{
+public:
+ constexpr static DomType kindValue = DomType::SimpleObjectWrap;
+
+ SimpleObjectWrapBase *operator->() { return wrap.data(); }
+ const SimpleObjectWrapBase *operator->() const { return wrap.data(); }
+ SimpleObjectWrapBase &operator*() { return *wrap.data(); }
+ const SimpleObjectWrapBase &operator*() const { return *wrap.data(); }
+
+ template<typename T>
+ static SimpleObjectWrap fromObjectRef(const Path &pathFromOwner, T &value)
+ {
+ return SimpleObjectWrap(pathFromOwner, value);
+ }
+ SimpleObjectWrap() = delete;
+
+private:
+ template<typename T>
+ SimpleObjectWrap(const Path &pathFromOwner, T &value)
+ {
+ using BaseT = std::decay_t<T>;
+ if constexpr (domTypeIsObjWrap(BaseT::kindValue)) {
+ new (wrap.data()) SimpleObjectWrapT<BaseT>(pathFromOwner, QVariant::fromValue(&value),
+ quintptr(&value), SimpleWrapOption::None);
+ } else if constexpr (domTypeIsValueWrap(BaseT::kindValue)) {
+ new (wrap.data()) SimpleObjectWrapT<BaseT>(pathFromOwner, QVariant::fromValue(value),
+ quintptr(0), SimpleWrapOption::ValueType);
+ } else {
+ qCWarning(domLog) << "Unexpected object to wrap in SimpleObjectWrap: "
+ << domTypeToString(BaseT::kindValue);
+ Q_ASSERT_X(false, "SimpleObjectWrap",
+ "simple wrap of unexpected object"); // allow? (mocks for testing,...)
+ new (wrap.data())
+ SimpleObjectWrapT<BaseT>(pathFromOwner, nullptr, 0, SimpleWrapOption::None);
+ }
+ }
+ SubclassStorage<SimpleObjectWrapBase> wrap;
+};
+
+class QMLDOM_EXPORT Reference final : public DomElement
+{
+ Q_GADGET
public:
constexpr static DomType kindValue = DomType::Reference;
DomType kind() const override { return kindValue; }
- Reference(Path referredObject = Path(), Path pathFromOwner = Path(), const SourceLocation & loc = SourceLocation());
+ Reference *operator->() { return this; }
+ const Reference *operator->() const { return this; }
+ Reference &operator*() { return *this; }
+ const Reference &operator*() const { return *this; }
+
+ bool shouldCache() const;
+ Reference(const Path &referredObject = Path(), const Path &pathFromOwner = Path(),
+ const SourceLocation &loc = SourceLocation());
quintptr id() const override;
- bool iterateDirectSubpaths(DomItem &self, std::function<bool(Path, DomItem &)>) override;
+ bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override;
DomItem field(const DomItem &self, QStringView name) const override;
- QList<QString> const fields(const DomItem &self) const override;
- index_type indexes(const DomItem &) const override {
- return 0;
- }
+ 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 &, QString) 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;
+ 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;
};
+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;
+
+ 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(); }
+
+ ScriptElementVariant element() const { return m_element; }
+
+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, const DomItem &, const DomItem &)>;
+ using Callback = function<void(const Path &, const DomItem &, const DomItem &)>;
using InternalKind = DomType;
- using Visitor = std::function<bool(Path, const DomItem &)>;
- using ChildrenVisitor = std::function<bool(Path, const 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();
static ErrorGroups myResolveErrors();
+ static DomItem empty;
- operator bool() const { return base()->kind() != DomType::Empty; }
+ enum class CopyOption { EnvConnected, EnvDisconnected };
+
+ template<typename F>
+ auto visitEl(F f) const
+ {
+ return std::visit(f, this->m_element);
+ }
+
+ explicit operator bool() const { return m_kind != DomType::Empty; }
InternalKind internalKind() const {
- InternalKind res = base()->kind();
- if (res == InternalKind::SimpleObjectWrap)
- return static_cast<SimpleObjectWrap const *>(base())->internalKind();
- return res;
+ return m_kind;
}
- DomKind domKind() const {
- return base()->domKind();
+ QString internalKindStr() const { return domTypeToString(internalKind()); }
+ DomKind domKind() const
+ {
+ if (m_kind == DomType::ConstantData)
+ return std::get<ConstantData>(m_element).domKind();
+ else
+ return kind2domKind(m_kind);
}
Path canonicalPath() const;
+
+ DomItem filterUp(function_ref<bool(DomType k, const DomItem &)> filter, FilterUpOptions options) const;
DomItem containingObject() const;
DomItem container() const;
- DomItem component() 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) 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
- QString name() const;
- DomItem qmlChildren() const;
- DomItem annotations() const;
+ 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);
+ else
+ return DomItem();
+ }
- bool resolve(Path path, Visitor visitor, ErrorHandler errorHandler, ResolveOptions options = ResolveOption::None, Path fullPath = Path(), QList<Path> *visitedRefs = nullptr) const;
+ 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) const;
+ 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[](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) 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(Path p, ErrorHandler h = &defaultErrorHandler) const;
- DomItem path(QString p, ErrorHandler h = &defaultErrorHandler) const;
- DomItem path(QStringView p, ErrorHandler h = &defaultErrorHandler) const;
+ 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> const fields() const;
+ QList<QString> fields() const;
DomItem field(QStringView name) const;
index_type indexes() const;
DomItem index(index_type) const;
-
- QSet<QString> const keys() const;
- DomItem key(QString name) const;
-
- bool visitChildren(Path basePath, ChildrenVisitor visitor, VisitOptions options = VisitOption::VisitAdopted, ChildrenVisitor openingVisitor = ChildrenVisitor(), ChildrenVisitor closingVisitor = ChildrenVisitor()) const;
-
- quintptr id() const { return base()->id(); }
- Path pathFromOwner() const { return base()->pathFromOwner(*this); }
- QString canonicalFilePath() const { return base()->canonicalFilePath(*this); }
- SourceLocation location() const { return base()->location(*this); }
-
+ 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,
+ const FieldFilter &filter = FieldFilter::noFilter()) const;
+ bool visitPrototypeChain(function_ref<bool(const DomItem &)> visitor,
+ VisitPrototypesOptions options = VisitPrototypesOption::Normal,
+ 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,
+ const ErrorHandler &h = nullptr, QSet<quintptr> *visited = nullptr,
+ QList<Path> *visitedRefs = nullptr) const;
+ bool
+ visitStaticTypePrototypeChains(function_ref<bool(const DomItem &)> visitor,
+ VisitPrototypesOptions options = VisitPrototypesOption::Normal,
+ 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(Sink) const;
- void dump(Sink, int indent = 0) 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(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
@@ -402,54 +1095,126 @@ public:
QDateTime frozenAt() const;
QDateTime lastDataUpdateAt() const;
- void addError(ErrorMessage msg) const;
+ void addError(ErrorMessage &&msg) const;
ErrorHandler errorHandler() const;
- void clearErrors(ErrorGroups groups = ErrorGroups({}), bool iterate = true) const;
+ void clearErrors(const ErrorGroups &groups = ErrorGroups({}), bool iterate = true) const;
// return false if a quick exit was requested
- bool iterateErrors(std::function<bool(DomItem source, ErrorMessage msg)> visitor, bool iterate,
- Path inPath = Path())const;
-
- bool iterateSubOwners(std::function<bool(DomItem owner)> visitor) const;
-
- Subpath subDataField(QStringView fieldName, QCborValue value, ConstantData::Options options = ConstantData::Options::MapIsMap, const SourceLocation &loc = SourceLocation()) const;
- Subpath subDataField(QString fieldName, QCborValue value, ConstantData::Options options = ConstantData::Options::MapIsMap, const SourceLocation &loc = SourceLocation()) const;
- Subpath subDataIndex(index_type i, QCborValue value, ConstantData::Options options = ConstantData::Options::MapIsMap, const SourceLocation &loc = SourceLocation()) const;
- Subpath subDataKey(QStringView keyName, QCborValue value, ConstantData::Options options = ConstantData::Options::MapIsMap, const SourceLocation &loc = SourceLocation()) const;
- Subpath subDataKey(QString keyName, QCborValue value, ConstantData::Options options = ConstantData::Options::MapIsMap, const SourceLocation &loc = SourceLocation()) const;
- Subpath subDataPath(Path path, QCborValue value, ConstantData::Options options = ConstantData::Options::MapIsMap, const SourceLocation &loc = SourceLocation()) const;
- Subpath subReferenceField(QStringView fieldName, Path referencedObject,
- const SourceLocation & loc = SourceLocation()) const;
- Subpath subReferenceField(QString fieldName, Path referencedObject, const SourceLocation & loc = SourceLocation()) const;
- Subpath subReferenceKey(QStringView keyName, Path referencedObject, const SourceLocation & loc = SourceLocation()) const;
- Subpath subReferenceKey(QString keyName, Path referencedObject, const SourceLocation & loc = SourceLocation()) const;
- Subpath subReferenceIndex(index_type i, Path referencedObject, const SourceLocation & loc = SourceLocation()) const;
- Subpath subReferencePath(Path subPath, Path referencedObject, const SourceLocation & loc = SourceLocation()) const;
-
- Subpath toSubField(QStringView fieldName) const;
- Subpath toSubField(QString fieldName) const;
- Subpath toSubKey(QStringView keyName) const;
- Subpath toSubKey(QString keyName) const;
- Subpath toSubIndex(index_type i) const;
- Subpath toSubPath(Path subPath) const;
- Subpath subList(const List &list) const;
- Subpath subMap(const Map &map) const;
- Subpath subObjectWrap(const SimpleObjectWrap &o) const;
- template <typename T>
- Subpath subWrapPath(Path p, T &obj, SourceLocation loc = SourceLocation()) const;
- template <typename T>
- Subpath subWrapField(QString p, T &obj, SourceLocation loc = SourceLocation()) const;
- template <typename T>
- Subpath subWrapField(QStringView p, T &obj, SourceLocation loc = SourceLocation()) const;
- template <typename T>
- Subpath subWrapKey(QString p, T &obj, SourceLocation loc = SourceLocation()) const;
- template <typename T>
- Subpath subWrapKey(QStringView p, T &obj, SourceLocation loc = SourceLocation()) const;
- template <typename T>
- Subpath subWrapIndex(index_type i, T &obj, SourceLocation loc = SourceLocation()) const;
+ bool iterateErrors(
+ function_ref<bool (const DomItem &, const ErrorMessage &)> visitor, bool iterate,
+ Path inPath = Path()) const;
- DomItem();
- DomItem(std::shared_ptr<DomEnvironment>);
- DomItem(std::shared_ptr<DomUniverse>);
+ bool iterateSubOwners(function_ref<bool(const DomItem &owner)> visitor) const;
+ bool iterateDirectSubpaths(DirectVisitor v) const;
+
+ template<typename T>
+ DomItem subDataItem(const PathEls::PathComponent &c, const T &value,
+ ConstantData::Options options = ConstantData::Options::MapIsMap) const;
+ template<typename T>
+ 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, const T &value,
+ ConstantData::Options options = ConstantData::Options::MapIsMap) const;
+ template<typename T>
+ 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, const T &value,
+ ConstantData::Options options = ConstantData::Options::MapIsMap) const
+ {
+ 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) const;
+ template<typename F>
+ bool dvValueLazyField(DirectVisitor visitor, QStringView f, F valueF,
+ ConstantData::Options options = ConstantData::Options::MapIsMap) const
+ {
+ return this->dvValueLazy(std::move(visitor), PathEls::Field(f), valueF, options);
+ }
+ DomItem subLocationItem(const PathEls::PathComponent &c, SourceLocation loc) const
+ {
+ return this->subDataItem(c, sourceLocationToQCborValue(loc));
+ }
+ // bool dvSubReference(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(std::move(visitor), c, [c, this, referencedObject]() {
+ return this->subReferenceItem(c, referencedObject);
+ });
+ }
+ bool dvReferences(
+ DirectVisitor visitor, const PathEls::PathComponent &c, const QList<Path> &paths) const
+ {
+ return dvItem(std::move(visitor), c, [c, this, paths]() {
+ return this->subReferencesItem(c, paths);
+ });
+ }
+ bool dvReferenceField(DirectVisitor visitor, QStringView f, const Path &referencedObject) const
+ {
+ return dvReference(std::move(visitor), PathEls::Field(f), referencedObject);
+ }
+ bool dvReferencesField(DirectVisitor visitor, QStringView f, const QList<Path> &paths) const
+ {
+ return dvReferences(std::move(visitor), PathEls::Field(f), paths);
+ }
+ 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) const
+ {
+ return dvItem(std::move(visitor), PathEls::Field(f), it);
+ }
+ 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) const
+ {
+ if constexpr (domTypeIsUnattachedOwningItem(Owner::element_type::kindValue))
+ return DomItem(m_top, o, canonicalPath().appendComponent(c), o.get());
+ else
+ return DomItem(m_top, o, Path(), o.get());
+ }
+ template<typename T>
+ DomItem wrap(const PathEls::PathComponent &c, const T &obj) const;
+ template<typename T>
+ 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) const;
+ template<typename T>
+ bool dvWrapField(DirectVisitor visitor, QStringView f, T &obj) const
+ {
+ return dvWrap<T>(std::move(visitor), PathEls::Field(f), obj);
+ }
+
+ DomItem() = default;
+ 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? ---
@@ -457,64 +1222,100 @@ public:
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<DomBase, T>::value, bool>::type = true>
- T const*as() const {
- InternalKind k = base()->kind();
- if (k == T::kindValue)
- return static_cast<T const*>(base());
- if (k == InternalKind::SimpleObjectWrap)
- return static_cast<SimpleObjectWrap const *>(base())->as<T>();
+ template<typename T, typename std::enable_if<std::is_base_of_v<DomBase, T>, bool>::type = true>
+ T const *as() const
+ {
+ if (m_kind == T::kindValue) {
+ if constexpr (domTypeIsObjWrap(T::kindValue) || domTypeIsValueWrap(T::kindValue))
+ return std::get<SimpleObjectWrap>(m_element)->as<T>();
+ else
+ return static_cast<T const *>(base());
+ }
return nullptr;
}
- template <typename T, typename std::enable_if<!std::is_base_of<DomBase, T>::value, bool>::type = true>
- T const*as() const {
- InternalKind k = base()->kind();
- if (k == InternalKind::SimpleObjectWrap)
- return static_cast<SimpleObjectWrap const *>(base())->as<T>();
+ template<typename T, typename std::enable_if<!std::is_base_of_v<DomBase, T>, bool>::type = true>
+ T const *as() const
+ {
+ if (m_kind == T::kindValue) {
+ Q_ASSERT(domTypeIsObjWrap(m_kind) || domTypeIsValueWrap(m_kind));
+ return std::get<SimpleObjectWrap>(m_element)->as<T>();
+ }
return nullptr;
}
- template <typename T>
+ template<typename T>
std::shared_ptr<T> ownerAs() const;
- DomItem copy(std::shared_ptr<OwningItem> owner, DomBase *base) const;
- DomItem copy(std::shared_ptr<OwningItem> owner) const;
- DomItem copy(DomBase *base) const;
-private:
- DomBase const* base() const {
- if (m_base == nullptr)
- return reinterpret_cast<DomBase const*>(&inlineEl);
- return m_base;
+ template<typename Owner, typename T>
+ DomItem copy(const Owner &owner, const Path &ownerPath, const T &base) const
+ {
+ 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 T, typename std::enable_if<std::is_base_of<DomBase, T>::value, bool>::type = true>
- T *mutableAs() {
- InternalKind k = base()->kind();
- if (k == T::kindValue)
- return static_cast<T*>(mutableBase());
- if (k == InternalKind::SimpleObjectWrap)
- return static_cast<SimpleObjectWrap *>(mutableBase())->mutableAs<T>();
- return nullptr;
+
+ template<typename Owner>
+ DomItem copy(const Owner &owner, const Path &ownerPath) const
+ {
+ Q_ASSERT(!std::holds_alternative<std::monostate>(m_top));
+ return DomItem(m_top, owner, ownerPath, owner.get());
}
- template <typename T, typename std::enable_if<!std::is_base_of<DomBase, T>::value, bool>::type = true>
- T *mutableAs() {
- InternalKind k = base()->kind();
- if (k == InternalKind::SimpleObjectWrap)
- return static_cast<SimpleObjectWrap *>(mutableBase())->mutableAs<T>();
- return nullptr;
+ template<typename T>
+ DomItem copy(const T &base) const
+ {
+ 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 || 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 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:
+ enum class WriteOutCheckResult { Success, Failed };
+ WriteOutCheckResult performWriteOutChecks(const DomItem &, const DomItem &, OutWriter &, WriteOutChecks) const;
+ const DomBase *base() const;
+
+ 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, const Path &ownerPath, const T &el)
+ : m_top(env), m_owner(owner), m_ownerPath(ownerPath), m_element(el)
+ {
+ using BaseT = std::decay_t<T>;
+ if constexpr (std::is_pointer_v<BaseT>) {
+ if (!el || el->kind() == DomType::Empty) { // avoid null ptr, and allow only a
+ // single kind of Empty
+ m_kind = DomType::Empty;
+ m_top = std::monostate();
+ m_owner = std::monostate();
+ m_ownerPath = Path();
+ m_element = Empty();
+ } else {
+ using DomT = std::remove_pointer_t<BaseT>;
+ m_element = el;
+ m_kind = DomT::kindValue;
+ }
+ } else {
+ static_assert(!std::is_same_v<BaseT, ElementT>,
+ "variant not supported, pass in the internal type");
+ m_kind = el->kind();
+ }
}
- DomBase * mutableBase() {
- if (m_base == nullptr)
- return reinterpret_cast<DomBase*>(&inlineEl);
- return m_base;
- }
- DomItem(std::shared_ptr<DomTop> env, std::shared_ptr<OwningItem> owner, DomBase *base);
- DomItem(std::shared_ptr<DomTop> env, std::shared_ptr<OwningItem> owner, Map map);
- DomItem(std::shared_ptr<DomTop> env, std::shared_ptr<OwningItem> owner, List list);
- DomItem(std::shared_ptr<DomTop> env, std::shared_ptr<OwningItem> owner, ConstantData data);
- DomItem(std::shared_ptr<DomTop> env, std::shared_ptr<OwningItem> owner, Reference reference);
- DomItem(std::shared_ptr<DomTop> env, std::shared_ptr<OwningItem> owner, SimpleObjectWrap wrapper);
+ friend class DomBase;
friend class DomElement;
friend class Map;
friend class List;
@@ -524,209 +1325,198 @@ private:
friend class ExternalItemInfoBase;
friend class ConstantData;
friend class MutableDomItem;
- friend bool operator ==(const DomItem &, const DomItem &);
- std::shared_ptr<DomTop> m_top;
- std::shared_ptr<OwningItem> m_owner;
- DomBase *m_base;
- union InlineEl {
- // Should add optimized move ops (should be able to do a bit copy of union)
- InlineEl(): empty() { }
- InlineEl(const InlineEl &d) {
- switch (d.kind()){
- case DomType::Empty:
- Q_ASSERT((quintptr)this == (quintptr)&empty && "non C++11 compliant compiler");
- new (&empty) Empty(d.empty);
- break;
- case DomType::Map:
- Q_ASSERT((quintptr)this == (quintptr)&map && "non C++11 compliant compiler");
- new (&map) Map(d.map);
- break;
- case DomType::List:
- Q_ASSERT((quintptr)this == (quintptr)&list && "non C++11 compliant compiler");
- new (&list) List(d.list);
- break;
- case DomType::ConstantData:
- Q_ASSERT((quintptr)this == (quintptr)&data && "non C++11 compliant compiler");
- new (&data) ConstantData(d.data);
- break;
- case DomType::SimpleObjectWrap:
- Q_ASSERT((quintptr)this == (quintptr)&simpleObjectWrap && "non C++11 compliant compiler");
- new (&simpleObjectWrap) SimpleObjectWrap(d.simpleObjectWrap);
- break;
- case DomType::Reference:
- Q_ASSERT((quintptr)this == (quintptr)&reference && "non C++11 compliant compiler");
- new (&reference) Reference(d.reference);
- break;
- default:
- Q_ASSERT(false && "unexpected kind in inline element");
- break;
- }
- }
- InlineEl(const Empty &o) {
- Q_ASSERT((quintptr)this == (quintptr)&empty && "non C++11 compliant compiler");
- new (&empty) Empty(o);
- }
- InlineEl(const Map &o) {
- Q_ASSERT((quintptr)this == (quintptr)&map && "non C++11 compliant compiler");
- new (&map) Map(o);
- }
- InlineEl(const List &o){
- Q_ASSERT((quintptr)this == (quintptr)&list && "non C++11 compliant compiler");
- new (&list) List(o);
- }
- InlineEl(const ConstantData &o) {
- Q_ASSERT((quintptr)this == (quintptr)&data && "non C++11 compliant compiler");
- new (&data) ConstantData(o);
- }
- InlineEl(const SimpleObjectWrap &o) {
- Q_ASSERT((quintptr)this == (quintptr)&simpleObjectWrap && "non C++11 compliant compiler");
- new (&simpleObjectWrap) SimpleObjectWrap(o);
- }
- InlineEl(const Reference &o) {
- Q_ASSERT((quintptr)this == (quintptr)&reference && "non C++11 compliant compiler");
- new (&reference) Reference(o);
- }
- InlineEl &operator=(const InlineEl &d) {
- Q_ASSERT(this != &d);
- this->~InlineEl(); // destruct & construct new...
- new (this)InlineEl(d);
- return *this;
- }
- DomType kind() const {
- return reinterpret_cast<const DomBase*>(this)->kind();
- }
- ~InlineEl() {
- reinterpret_cast<const DomBase*>(this)->~DomBase();
- }
- Empty empty;
- Map map;
- List list;
- ConstantData data;
- SimpleObjectWrap simpleObjectWrap;
- Reference reference;
- } inlineEl;
+ friend class ScriptExpression;
+ friend class AstComments;
+ friend class AttachedInfo;
+ friend class TestDomItem;
+ friend QMLDOM_EXPORT bool operator==(const DomItem &, const DomItem &);
+ DomType m_kind = DomType::Empty;
+ TopT m_top;
+ OwnerT m_owner;
+ Path m_ownerPath;
+ ElementT m_element = Empty();
};
-bool operator ==(const DomItem &o1, const DomItem &o2);
-inline bool operator !=(const DomItem &o1, const DomItem &o2) {
+QMLDOM_EXPORT bool operator==(const DomItem &o1, const DomItem &o2);
+
+inline bool operator!=(const DomItem &o1, const DomItem &o2)
+{
return !(o1 == o2);
}
-Q_DECLARE_OPERATORS_FOR_FLAGS(LoadOptions)
+template<typename T>
+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);
+ }
+}
-class Subpath {
-public:
- Path path;
- DomItem item;
+template<typename T>
+Map Map::fromMultiMapRef(const Path &pathFromOwner, const QMultiMap<QString, T> &mmap)
+{
+ return Map(
+ pathFromOwner,
+ [&mmap](const DomItem &self, const QString &key) {
+ return keyMultiMapHelper(self, key, mmap);
+ },
+ [&mmap](const DomItem &) { return QSet<QString>(mmap.keyBegin(), mmap.keyEnd()); },
+ QLatin1String(typeid(T).name()));
+}
- bool visit(std::function <bool(Path, DomItem &)> visitor){
- return visitor(path, item);
- }
-};
+template<typename T>
+Map Map::fromMapRef(
+ 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](const DomItem &self, const QString &key) {
+ const auto it = map.constFind(key);
+ if (it == map.constEnd())
+ return DomItem();
+ return elWrapper(self, PathEls::Key(key), it.value());
+ },
+ [&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::fromMultiMapRef(Path pathFromOwner, QMultiMap<QString,T> &mmap, std::function<DomItem(const DomItem &, Path, T&)> elWrapper)
+Map Map::fromFileRegionMap(const Path &pathFromOwner, const QMap<FileLocationRegion, T> &map)
{
- return Map(pathFromOwner, [&mmap, elWrapper](const DomItem &self, QString key) {
- auto it = mmap.find(key);
- auto end = mmap.cend();
- if (it == end)
- return DomItem();
- else {
- QList<T *> values;
- while (it != end && it.key() == key)
- values.append(&(*it++));
- return self.subList(List::fromQList<T*>(self.pathFromOwner().subKey(key), values, [elWrapper](const DomItem &l, Path p,T * &el) {
- return elWrapper(l,p,*el);
- }, ListOptions::Reverse)).item;
- }
- }, [&mmap](const DomItem&){
- return QSet<QString>(mmap.keyBegin(), mmap.keyEnd());
- }, QLatin1String(typeid(T).name()));
+ 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::fromMapRef(Path pathFromOwner, QMap<QString,T> &map,
- std::function<DomItem(const DomItem &, Path, T&)> elWrapper)
+Map Map::fromFileRegionListMap(const Path &pathFromOwner,
+ const QMap<FileLocationRegion, QList<T>> &map)
{
- return Map(pathFromOwner, [&map, elWrapper](const DomItem &self, QString key) {
- if (!map.contains(key))
- return DomItem();
- else {
- return elWrapper(self, Path::key(key), map[key]);
- }
- }, [&map](const DomItem&){
- return QSet<QString>(map.keyBegin(), map.keyEnd());
- }, QLatin1String(typeid(T).name()));
+ 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(const DomItem &, Path, T&)> elWrapper, ListOptions options)
+List List::fromQList(
+ 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.length();
+ index_type len = list.size();
if (options == ListOptions::Reverse) {
return List(
- pathFromOwner,
- [list, elWrapper](const DomItem &self, index_type i) mutable {
- if (i < 0 || i >= list.length())
- return DomItem();
- return elWrapper(self, Path::index(i), list[list.length() -i - 1]);
- }, [len](const DomItem &) {
- return len;
- }, nullptr, QLatin1String(typeid(T).name()));
+ pathFromOwner,
+ [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](const DomItem &) { return len; }, nullptr, QLatin1String(typeid(T).name()));
} else {
- return List(pathFromOwner,
- [list, elWrapper](const DomItem &self, index_type i) mutable {
- if (i < 0 || i >= list.length())
- return DomItem();
- return elWrapper(self, Path::index(i), list[i]);
- }, [len](const DomItem &) {
- return len;
- }, nullptr, QLatin1String(typeid(T).name()));
+ return List(
+ pathFromOwner,
+ [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](const DomItem &) { return len; }, nullptr, QLatin1String(typeid(T).name()));
}
}
template<typename T>
-List List::fromQListRef(Path pathFromOwner, QList<T> &list, std::function<DomItem(const DomItem &, Path, T&)> elWrapper, ListOptions options)
+List List::fromQListRef(
+ 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](const DomItem &self, index_type i) {
- if (i < 0 || i >= list.length())
- return DomItem();
- return elWrapper(self, Path::index(i), list[list.length() -i - 1]);
- }, [&list](const DomItem &) {
- return list.length();
- }, nullptr, QLatin1String(typeid(T).name()));
+ pathFromOwner,
+ [&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](const DomItem &) { return list.size(); }, nullptr,
+ QLatin1String(typeid(T).name()));
} else {
- return List(pathFromOwner,
- [&list, elWrapper](const DomItem &self, index_type i) {
- if (i < 0 || i >= list.length())
- return DomItem();
- return elWrapper(self, Path::index(i), list[i]);
- }, [&list](const DomItem &) {
- return list.length();
- }, nullptr, QLatin1String(typeid(T).name()));
+ return List(
+ pathFromOwner,
+ [&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](const DomItem &) { return list.size(); }, nullptr,
+ QLatin1String(typeid(T).name()));
}
}
class QMLDOM_EXPORT OwningItem: public DomBase {
protected:
- virtual std::shared_ptr<OwningItem> doCopy(const DomItem &self) = 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(const DomItem &self) const override = 0;
- bool iterateDirectSubpaths(DomItem &self, std::function<bool (Path, DomItem &)>) override;
- std::shared_ptr<OwningItem> makeCopy(const DomItem &self) {
- return doCopy(self);
- }
- Path pathFromOwner(const DomItem &self) const override;
+ 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(const DomItem &) const override final { return Path(); }
DomItem containingObject(const DomItem &self) const override;
int derivedFrom() const;
virtual int revision() const;
@@ -740,18 +1530,20 @@ public:
virtual bool freeze();
QDateTime frozenAt() const;
- virtual void addError(const 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(const DomItem &self, std::function<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(const DomItem &self, std::function<bool(const DomItem &owner)> visitor);
+ virtual bool iterateSubOwners(const DomItem &self, function_ref<bool(const DomItem &owner)> visitor);
QBasicMutex *mutex() const { return &m_mutex; }
private:
@@ -762,164 +1554,90 @@ private:
QDateTime m_lastDataUpdateAt;
QDateTime m_frozenAt;
QMultiMap<Path, ErrorMessage> m_errors;
+ QMap<ErrorMessage, quint32> m_errorsCounts;
};
-template <typename T>
-std::shared_ptr<T> DomItem::ownerAs() const {
- if (m_owner && m_owner->kind() == T::kindValue)
- return std::static_pointer_cast<T>(m_owner);
- return nullptr;
-}
-
-template <typename T>
-SimpleObjectWrap SimpleObjectWrap::fromDataObject(
- Path pathFromOwner, T const & val,
- std::function<QCborValue(T const &)> toData,
- const SourceLocation &loc,
- DomType kind,
- DomKind domKind,
- QString typeName)
-{
- QString objectName;
- if (!typeName.isEmpty())
- objectName = typeName;
- else if (kind != kindValue)
- objectName = domTypeToStringMap()[kind];
- else
- objectName = QLatin1String("SimpleObjectWrap<%1>").arg(QLatin1String(typeid(T).name()));
- return SimpleObjectWrap(
- pathFromOwner, QVariant::fromValue(&val),
- [toData, pathFromOwner](DomItem &self, QVariant v, std::function<bool(Path, DomItem &)> visitor){
- ConstantData data = ConstantData(pathFromOwner, toData(*v.value<T const*>()), ConstantData::Options::FirstMapIsFields);
- return data.iterateDirectSubpaths(self, visitor);
- }, kind, domKind, objectName, loc);
+template<typename T>
+std::shared_ptr<T> DomItem::ownerAs() const
+{
+ if constexpr (domTypeIsOwningItem(T::kindValue)) {
+ if (!std::holds_alternative<std::monostate>(m_owner)) {
+ if constexpr (T::kindValue == DomType::AttachedInfo) {
+ if (std::holds_alternative<std::shared_ptr<AttachedInfo>>(m_owner))
+ return std::static_pointer_cast<T>(
+ 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))
+ return std::static_pointer_cast<T>(
+ 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))
+ return std::static_pointer_cast<T>(
+ 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);
+ }
+ }
+ }
+ } else {
+ Q_ASSERT_X(false, "DomItem::ownerAs", "unexpected non owning value in ownerAs");
+ }
+ return std::shared_ptr<T> {};
}
-template <typename T>
-SimpleObjectWrap SimpleObjectWrap::fromObjectRef(
- Path pathFromOwner, T &value,
- std::function<bool(DomItem &, T &val, std::function<bool(Path, DomItem &)>)> directSubpathsIterate,
- const SourceLocation &loc,
- DomType kind,
- QString typeName,
- DomKind domKind)
-{
- return SimpleObjectWrap(
- pathFromOwner, QVariant::fromValue(&value),
- [directSubpathsIterate](DomItem &self, QVariant v, std::function<bool(Path, DomItem &)> visitor){
- return directSubpathsIterate(self, *v.value<T *>(), visitor);
- },
- kind, domKind,
- ((!typeName.isEmpty()) ? typeName :
- (kind != kindValue) ? domTypeToStringMap()[kind] :
- QStringLiteral(u"SimpleObjectWrap<%1>").arg(QLatin1String(typeid(T).name()))),
- loc);
-}
+template<int I>
+struct rank : rank<I - 1>
+{
+ static_assert(I > 0, "");
+};
+template<>
+struct rank<0>
+{
+};
-template <typename T>
-Subpath DomItem::subWrapPath(Path p, T &obj, SourceLocation loc) const {
- return this->subObjectWrap(SimpleObjectWrap::fromObjectRef<T>(
- this->pathFromOwner().subPath(p),
- obj,
- [](DomItem &self, T &fDef, std::function<bool(Path, DomItem &)> visitor) {
- return fDef.iterateDirectSubpaths(self, visitor);
- },loc,
- T::kindValue));
+template<typename T>
+auto writeOutWrap(const T &t, const DomItem &self, OutWriter &lw, rank<1>)
+ -> decltype(t.writeOut(self, lw))
+{
+ t.writeOut(self, lw);
}
-template <typename T>
-Subpath DomItem::subWrapField(QString p, T &obj, SourceLocation loc) const {
- return this->subWrapPath<T>(Path::field(p), obj, loc);
-}
-template <typename T>
-Subpath DomItem::subWrapField(QStringView p, T &obj, SourceLocation loc) const {
- return this->subWrapPath<T>(Path::field(p), obj, loc);
-}
-template <typename T>
-Subpath DomItem::subWrapKey(QString p, T &obj, SourceLocation loc) const {
- return this->subWrapPath<T>(Path::key(p), obj, loc);
-}
-template <typename T>
-Subpath DomItem::subWrapKey(QStringView p, T &obj, SourceLocation loc) const {
- return this->subWrapPath<T>(Path::key(p), obj, loc);
+template<typename T>
+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>
-Subpath DomItem::subWrapIndex(index_type i, T &obj, SourceLocation loc) const {
- return this->subWrapPath<T>(Path::index(i), obj, loc);
+template<typename T>
+auto writeOutWrap(const T &t, const DomItem &self, OutWriter &lw) -> void
+{
+ writeOutWrap(t, self, lw, rank<1>());
}
-// mainly for debugging purposes
-class GenericObject: public DomElement {
-public:
- constexpr static DomType kindValue = DomType::GenericObject;
- DomType kind() const override { return kindValue; }
-
- GenericObject(Path pathFromOwner = Path(), const SourceLocation & loc = SourceLocation(),
- QMap<QString, GenericObject> subObjects = {},
- QMap<QString, QCborValue> subValues = {}):
- DomElement(pathFromOwner, loc), subObjects(subObjects), subValues(subValues) {}
-
- GenericObject copy() const;
- std::pair<QString, GenericObject> asStringPair() const;
-
- bool iterateDirectSubpaths(DomItem &self, std::function<bool (Path, DomItem &)>) override;
-
- QMap<QString, GenericObject> subObjects;
- QMap<QString, QCborValue> subValues;
-};
-
-// mainly for debugging purposes
-class GenericOwner: public OwningItem {
-protected:
- std::shared_ptr<OwningItem> doCopy(const DomItem &self) override;
-public:
- constexpr static DomType kindValue = DomType::GenericOwner;
- DomType kind() const override { return kindValue; }
-
- GenericOwner(Path pathFromTop = Path(), int derivedFrom = 0,
- QMap<QString, GenericObject> subObjects = {},
- QMap<QString, QCborValue> subValues = {}):
- OwningItem(derivedFrom), pathFromTop(pathFromTop), subObjects(subObjects),
- subValues(subValues)
- {}
-
- GenericOwner(Path pathFromTop, int derivedFrom, QDateTime dataRefreshedAt,
- QMap<QString, GenericObject> subObjects = {},
- QMap<QString, QCborValue> subValues = {}):
- OwningItem(derivedFrom, dataRefreshedAt), pathFromTop(pathFromTop), subObjects(subObjects),
- subValues(subValues)
- {}
-
- GenericOwner(const GenericOwner &o);
-
- std::shared_ptr<GenericOwner> makeCopy(const DomItem &self);
- Path canonicalPath(const DomItem &self) const override;
-
- bool iterateDirectSubpaths(DomItem &self, std::function<bool (Path, DomItem &)>) override;
-
- Path pathFromTop;
- QMap<QString, GenericObject> subObjects;
- QMap<QString, QCborValue> subValues;
-};
-
-QDebug operator<<(QDebug debug, const DomItem &c);
+template<typename T>
+void SimpleObjectWrapT<T>::writeOut(const DomItem &self, OutWriter &lw) const
+{
+ writeOutWrap<T>(*asT(), self, lw);
+}
+QMLDOM_EXPORT QDebug operator<<(QDebug debug, const DomItem &c);
-class MutableDomItem {
+class QMLDOM_EXPORT MutableDomItem {
public:
- operator bool() const {
- return m_owner && base();
- }
- DomType internalKind() const {
- return base().internalKind();
- }
- DomKind domKind() const { return kind2domKind(internalKind()); }
+ using CopyOption = DomItem::CopyOption;
- Path canonicalPath() const
+ explicit operator bool() const
+ {
+ return bool(m_owner);
+ } // this is weaker than item(), but normally correct
+ DomType internalKind() { return item().internalKind(); }
+ QString internalKindStr() { return domTypeToString(internalKind()); }
+ DomKind domKind() { return kind2domKind(internalKind()); }
+
+ Path canonicalPath() const { return m_owner.canonicalPath().path(m_pathFromOwner); }
+ MutableDomItem containingObject()
{
- return m_owner.canonicalPath().subPath(m_pathFromOwner);
- }
- MutableDomItem containingObject() const {
if (m_pathFromOwner)
return MutableDomItem(m_owner, m_pathFromOwner.split().pathToSource);
else {
@@ -928,170 +1646,229 @@ public:
}
}
- MutableDomItem container() const {
+ MutableDomItem container()
+ {
if (m_pathFromOwner)
return MutableDomItem(m_owner, m_pathFromOwner.dropTail());
else {
- return MutableDomItem(base().container());
+ return MutableDomItem(item().container());
}
}
- MutableDomItem component() const {
- return MutableDomItem{base().component()};
- }
- MutableDomItem owner() const {
- return MutableDomItem(m_owner);
- }
- MutableDomItem top() const {
- return MutableDomItem(base().top());
- }
- MutableDomItem environment() const {
- return MutableDomItem(base().environment());
- }
- MutableDomItem universe() const {
- return MutableDomItem(base().universe());
+ MutableDomItem qmlObject(GoTo option = GoTo::Strict,
+ FilterUpOptions fOptions = FilterUpOptions::ReturnOuter)
+ {
+ return MutableDomItem(item().qmlObject(option, fOptions));
}
- Path pathFromOwner() const {
- return m_pathFromOwner;
+ MutableDomItem fileObject(GoTo option = GoTo::Strict)
+ {
+ return MutableDomItem(item().fileObject(option));
}
- MutableDomItem operator[](const Path &path) const {
- return MutableDomItem(base()[path]);
+ MutableDomItem rootQmlObject(GoTo option = GoTo::Strict)
+ {
+ return MutableDomItem(item().rootQmlObject(option));
}
- MutableDomItem operator[](QStringView component) const {
- return MutableDomItem(base()[component]);
+ MutableDomItem globalScope() { return MutableDomItem(item().globalScope()); }
+ MutableDomItem scope() { return MutableDomItem(item().scope()); }
+
+ MutableDomItem component(GoTo option = GoTo::Strict)
+ {
+ return MutableDomItem { item().component(option) };
}
- MutableDomItem operator[](const QString &component) const {
- return MutableDomItem(base()[component]);
+ MutableDomItem owner() { return MutableDomItem(m_owner); }
+ MutableDomItem top() { return MutableDomItem(item().top()); }
+ MutableDomItem environment() { return MutableDomItem(item().environment()); }
+ MutableDomItem universe() { return MutableDomItem(item().universe()); }
+ Path pathFromOwner() { return m_pathFromOwner; }
+ MutableDomItem operator[](const Path &path) { return MutableDomItem(item()[path]); }
+ MutableDomItem operator[](QStringView component) { return MutableDomItem(item()[component]); }
+ MutableDomItem operator[](const QString &component)
+ {
+ return MutableDomItem(item()[component]);
}
- MutableDomItem operator[](const char16_t *component) const {
+ MutableDomItem operator[](const char16_t *component)
+ {
// to avoid clash with stupid builtin ptrdiff_t[MutableDomItem&], coming from C
- return MutableDomItem(base()[QStringView(component)]);
- }
- MutableDomItem operator[](index_type i) const {
- return MutableDomItem(base().index(i));
+ return MutableDomItem(item()[QStringView(component)]);
}
+ MutableDomItem operator[](index_type i) { return MutableDomItem(item().index(i)); }
- MutableDomItem path(const Path &p) const {
- return MutableDomItem(base().path(p));
- }
- MutableDomItem path(const QString &p) const {
- return path(Path::fromString(p));
- }
- MutableDomItem path(QStringView p) const {
- return path(Path::fromString(p));
- }
+ MutableDomItem path(const Path &p) { return MutableDomItem(item().path(p)); }
+ MutableDomItem path(const QString &p) { return path(Path::fromString(p)); }
+ MutableDomItem path(QStringView p) { return path(Path::fromString(p)); }
- QList<QString> const fields() const {
- return base().fields();
- }
- MutableDomItem field(QStringView name) const {
- return MutableDomItem(base().field(name));
- }
- index_type indexes() const {
- return base().indexes();
- }
- MutableDomItem index(index_type i) const {
- return MutableDomItem(base().index(i));
- }
-
- QSet<QString> const keys() const {
- return base().keys();
- }
- MutableDomItem key(QString name) const {
- return MutableDomItem(base().key(name));
- }
+ QList<QString> const fields() { return item().fields(); }
+ MutableDomItem field(QStringView name) { return MutableDomItem(item().field(name)); }
+ index_type indexes() { return item().indexes(); }
+ MutableDomItem index(index_type i) { return MutableDomItem(item().index(i)); }
- QString canonicalFilePath() const { return base().canonicalFilePath(); }
- SourceLocation location() const { return base().location(); }
+ QSet<QString> const keys() { return item().keys(); }
+ MutableDomItem key(const QString &name) { return MutableDomItem(item().key(name)); }
+ MutableDomItem key(QStringView name) { return key(name.toString()); }
- QCborValue value() const {
- return base().value();
+ void
+ dump(const Sink &s, int indent = 0,
+ function_ref<bool(const DomItem &, const PathEls::PathComponent &, const DomItem &)> filter = noFilter)
+ {
+ item().dump(s, indent, filter);
}
-
- void dump(Sink sink, int indent = 0) const {
- return base().dump(sink, indent);
+ FileWriter::Status
+ 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);
}
- QString toString() const {
- return base().toString();
+ void writeOut(OutWriter &lw) { return item().writeOut(lw); }
+ bool writeOut(const QString &path, int nBackups = 2,
+ const LineWriterOptions &opt = LineWriterOptions(), FileWriter *fw = nullptr)
+ {
+ return item().writeOut(path, nBackups, opt, fw);
}
- // convenience getters
- QString name() const;
- MutableDomItem qmlChildren() const {
- return MutableDomItem(base().qmlChildren());
+ MutableDomItem fileLocations() { return MutableDomItem(item().fileLocations()); }
+ MutableDomItem makeCopy(CopyOption option = CopyOption::EnvConnected)
+ {
+ return item().makeCopy(option);
}
- MutableDomItem annotations() const {
- return MutableDomItem(base().annotations());
+ bool commitToBase(const std::shared_ptr<DomEnvironment> &validEnvPtr = nullptr)
+ {
+ return item().commitToBase(validEnvPtr);
}
+ QString canonicalFilePath() const { return item().canonicalFilePath(); }
- QMultiMap<QString, RequiredProperty> extraRequired() const;
+ MutableDomItem refreshed() { return MutableDomItem(item().refreshed()); }
+ QCborValue value() { return item().value(); }
-// // OwnigItem elements
- int derivedFrom() const {
- return m_owner.derivedFrom();
- }
- int revision() const {
- return m_owner.revision();
- }
- QDateTime createdAt() const {
- return m_owner.createdAt();
- }
- QDateTime frozenAt() const {
- return m_owner.frozenAt();
- }
- QDateTime lastDataUpdateAt() const {
- return m_owner.lastDataUpdateAt();
- }
+ QString toString() { return item().toString(); }
- void addError(ErrorMessage msg) const {
- base().addError(msg);
- }
- ErrorHandler errorHandler() const;
+ // convenience getters
+ QString name() { return item().name(); }
+ MutableDomItem pragmas() { return item().pragmas(); }
+ MutableDomItem ids() { return MutableDomItem::item().ids(); }
+ QString idStr() { return item().idStr(); }
+ MutableDomItem propertyDefs() { return MutableDomItem(item().propertyDefs()); }
+ MutableDomItem bindings() { return MutableDomItem(item().bindings()); }
+ MutableDomItem methods() { return MutableDomItem(item().methods()); }
+ MutableDomItem children() { return MutableDomItem(item().children()); }
+ MutableDomItem child(index_type i) { return MutableDomItem(item().child(i)); }
+ MutableDomItem annotations() { return MutableDomItem(item().annotations()); }
+
+ // // OwnigItem elements
+ int derivedFrom() { return m_owner.derivedFrom(); }
+ int revision() { return m_owner.revision(); }
+ QDateTime createdAt() { return m_owner.createdAt(); }
+ QDateTime frozenAt() { return m_owner.frozenAt(); }
+ QDateTime lastDataUpdateAt() { return m_owner.lastDataUpdateAt(); }
+
+ void addError(ErrorMessage &&msg) { item().addError(std::move(msg)); }
+ ErrorHandler errorHandler();
+
+ // convenience setters
+ 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(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(
+ const MethodInfo &functionDef, AddOption option = AddOption::Overwrite);
+ MutableDomItem addChild(QmlObject child);
+ MutableDomItem addAnnotation(QmlObject child);
+ 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())
{}
- std::shared_ptr<DomTop> topPtr() const {
- return m_owner.topPtr();
- }
- std::shared_ptr<OwningItem> owningItemPtr() const {
- return m_owner.owningItemPtr();
- }
+ std::shared_ptr<DomTop> topPtr() { return m_owner.topPtr(); }
+ std::shared_ptr<OwningItem> owningItemPtr() { return m_owner.owningItemPtr(); }
- template <typename T>
- T const*as() const {
- return base().as<T>();
+ template<typename T>
+ T const *as()
+ {
+ return item().as<T>();
}
template <typename T>
T *mutableAs() {
- Q_ASSERT(!m_owner.owningItemPtr()->frozen());
- return base().mutableAs<T>();
+ Q_ASSERT(!m_owner || !m_owner.owningItemPtr()->frozen());
+
+ 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() const {
+ template<typename T>
+ std::shared_ptr<T> ownerAs() const
+ {
return m_owner.ownerAs<T>();
}
// it is dangerous to assume it stays valid when updates are preformed...
- DomItem base() const {
- return m_owner.path(m_pathFromOwner);
+ DomItem item() const { return m_owner.path(m_pathFromOwner); }
+
+ friend bool operator==(const MutableDomItem &o1, const MutableDomItem &o2)
+ {
+ return o1.m_owner == o2.m_owner && o1.m_pathFromOwner == o2.m_pathFromOwner;
+ }
+ friend bool operator!=(const MutableDomItem &o1, const MutableDomItem &o2)
+ {
+ return !(o1 == o2);
}
+
private:
DomItem m_owner;
Path m_pathFromOwner;
};
-QDebug operator<<(QDebug debug, const MutableDomItem &c);
+QMLDOM_EXPORT QDebug operator<<(QDebug debug, const MutableDomItem &c);
-template <typename K, typename T>
-Path insertUpdatableElementInMultiMap(Path mapPathFromOwner, QMultiMap<K, T> &mmap, K key, const T&value) {
+template<typename K, typename T>
+Path insertUpdatableElementInMultiMap(const Path &mapPathFromOwner, QMultiMap<K, T> &mmap, K key,
+ const T &value, AddOption option = AddOption::KeepExisting,
+ T **valuePtr = nullptr)
+{
+ if (option == AddOption::Overwrite) {
+ auto it = mmap.find(key);
+ if (it != mmap.end()) {
+ T &v = *it;
+ v = value;
+ if (++it != mmap.end() && it.key() == key) {
+ qWarning() << " requested overwrite of " << key
+ << " that contains aleready multiple entries in" << mapPathFromOwner;
+ }
+ Path newPath = mapPathFromOwner.key(key).index(0);
+ v.updatePathFromOwner(newPath);
+ if (valuePtr)
+ *valuePtr = &v;
+ return newPath;
+ }
+ }
mmap.insert(key, value);
auto it = mmap.find(key);
auto it2 = it;
@@ -1100,24 +1877,30 @@ Path insertUpdatableElementInMultiMap(Path mapPathFromOwner, QMultiMap<K, T> &mm
++nVal;
++it2;
}
- Path newPath = mapPathFromOwner.subKey(key).subIndex(nVal-1);
- T &newComp = *it;
- newComp.updatePathFromOwner(newPath);
+ Path newPath = mapPathFromOwner.key(key).index(nVal-1);
+ T &v = *it;
+ v.updatePathFromOwner(newPath);
+ if (valuePtr)
+ *valuePtr = &v;
return newPath;
}
-template <typename T>
-Path appendUpdatableElementInQList(Path listPathFromOwner, QList<T> &list, const T&value) {
- int idx = list.length();
+template<typename T>
+Path appendUpdatableElementInQList(const Path &listPathFromOwner, QList<T> &list, const T &value,
+ T **vPtr = nullptr)
+{
+ int idx = list.size();
list.append(value);
- Path newPath = listPathFromOwner.subIndex(idx);
- list[idx].updatePathFromOwner(newPath);
+ Path newPath = listPathFromOwner.index(idx);
+ T &targetV = list[idx];
+ targetV.updatePathFromOwner(newPath);
+ if (vPtr)
+ *vPtr = &targetV;
return newPath;
}
-
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();
@@ -1126,9 +1909,9 @@ void updatePathFromOwnerMultiMap(QMultiMap<K, T> &mmap, Path newPath)
QList<T*> els;
while (it != end) {
if (i > 0 && name != it.key()) {
- Path pName = newPath.subKey(QString(name));
- foreach (T *el, els)
- el->updatePathFromOwner(pName.subIndex(--i));
+ Path pName = newPath.key(QString(name));
+ for (T *el : els)
+ el->updatePathFromOwner(pName.index(--i));
els.clear();
els.append(&(*it));
name = it.key();
@@ -1140,19 +1923,413 @@ void updatePathFromOwnerMultiMap(QMultiMap<K, T> &mmap, Path newPath)
}
++it;
}
- Path pName = newPath.subKey(name);
- foreach (T *el, els)
- el->updatePathFromOwner(pName.subIndex(--i));
+ Path pName = newPath.key(name);
+ for (T *el : els)
+ el->updatePathFromOwner(pName.index(--i));
}
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();
index_type i = 0;
while (it != end)
- (it++)->updatePathFromOwner(newPath.subIndex(i++));
+ (it++)->updatePathFromOwner(newPath.index(i++));
+}
+
+constexpr bool domTypeIsObjWrap(DomType k)
+{
+ switch (k) {
+ case DomType::Binding:
+ case DomType::EnumItem:
+ case DomType::ErrorMessage:
+ case DomType::Export:
+ case DomType::Id:
+ case DomType::Import:
+ case DomType::ImportScope:
+ case DomType::MethodInfo:
+ case DomType::MethodParameter:
+ case DomType::ModuleAutoExport:
+ case DomType::Pragma:
+ case DomType::PropertyDefinition:
+ case DomType::Version:
+ case DomType::Comment:
+ case DomType::CommentedElement:
+ case DomType::RegionComments:
+ case DomType::FileLocations:
+ case DomType::UpdatedScriptExpression:
+ return true;
+ default:
+ return false;
+ }
+}
+
+constexpr bool domTypeIsValueWrap(DomType k)
+{
+ switch (k) {
+ case DomType::PropertyInfo:
+ return true;
+ default:
+ return false;
+ }
+}
+
+constexpr bool domTypeIsDomElement(DomType k)
+{
+ switch (k) {
+ case DomType::ModuleScope:
+ case DomType::QmlObject:
+ case DomType::ConstantData:
+ case DomType::SimpleObjectWrap:
+ case DomType::Reference:
+ case DomType::Map:
+ case DomType::List:
+ case DomType::ListP:
+ case DomType::EnumDecl:
+ case DomType::JsResource:
+ case DomType::QmltypesComponent:
+ case DomType::QmlComponent:
+ case DomType::GlobalComponent:
+ case DomType::MockObject:
+ return true;
+ default:
+ return false;
+ }
+}
+
+constexpr bool domTypeIsOwningItem(DomType k)
+{
+ switch (k) {
+ case DomType::ModuleIndex:
+
+ case DomType::MockOwner:
+
+ case DomType::ExternalItemInfo:
+ case DomType::ExternalItemPair:
+
+ case DomType::QmlDirectory:
+ case DomType::QmldirFile:
+ case DomType::JsFile:
+ case DomType::QmlFile:
+ case DomType::QmltypesFile:
+ case DomType::GlobalScope:
+
+ case DomType::ScriptExpression:
+ case DomType::AstComments:
+
+ case DomType::LoadInfo:
+ case DomType::AttachedInfo:
+
+ case DomType::DomEnvironment:
+ case DomType::DomUniverse:
+ return true;
+ default:
+ return false;
+ }
+}
+
+constexpr bool domTypeIsUnattachedOwningItem(DomType k)
+{
+ switch (k) {
+ case DomType::ScriptExpression:
+ case DomType::AstComments:
+ case DomType::AttachedInfo:
+ return true;
+ default:
+ return false;
+ }
+}
+
+constexpr bool domTypeIsScriptElement(DomType k)
+{
+ return DomType::ScriptElementStart <= k && k <= DomType::ScriptElementStop;
+}
+
+template<typename T>
+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 (
+ std::is_base_of_v<
+ QCborValue,
+ BaseT> || std::is_base_of_v<QCborArray, BaseT> || std::is_base_of_v<QCborMap, BaseT>) {
+ return DomItem(m_top, m_owner, m_ownerPath,
+ ConstantData(pathFromOwner().appendComponent(c), value, options));
+ } else if constexpr (std::is_same_v<DomItem, BaseT>) {
+ Q_UNUSED(options);
+ return 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](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);
+ } else {
+ return subDataItem(c, value, options);
+ }
+}
+
+template<typename T>
+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>) {
+ return this->copy(value);
+ } else if constexpr (std::is_base_of_v<QCborValue, BaseT>) {
+ return DomItem(m_top, m_owner, m_ownerPath,
+ ConstantData(pathFromOwner().appendComponent(c), value, options));
+ } else {
+ return DomItem(
+ m_top, m_owner, m_ownerPath,
+ ConstantData(pathFromOwner().appendComponent(c), QCborValue(value), options));
+ }
+}
+
+template<typename T>
+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);
+ };
+ return visitor(c, lazyWrap);
+}
+
+template<typename F>
+bool DomItem::dvValueLazy(DirectVisitor visitor, const PathEls::PathComponent &c, F valueF,
+ ConstantData::Options options) const
+{
+ auto lazyWrap = [this, &c, &valueF, options]() {
+ return this->subValueItem<decltype(valueF())>(c, valueF(), options);
+ };
+ return visitor(c, lazyWrap);
+}
+
+template<typename T>
+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>) {
+ return this->subDataItem(c, QCborValue(obj));
+ } else if constexpr (std::is_same_v<SourceLocation, BaseT>) {
+ return this->subLocationItem(c, obj);
+ } else if constexpr (std::is_same_v<BaseT, Reference>) {
+ Q_ASSERT_X(false, "DomItem::wrap",
+ "wrapping a reference object, probably an error (wrap the target path instead)");
+ return this->copy(obj);
+ } else if constexpr (std::is_same_v<BaseT, ConstantData>) {
+ return this->subDataItem(c, obj);
+ } else if constexpr (std::is_same_v<BaseT, Map>) {
+ return this->subMapItem(obj);
+ } else if constexpr (std::is_same_v<BaseT, List>) {
+ return this->subListItem(obj);
+ } else if constexpr (std::is_base_of_v<ListPBase, BaseT>) {
+ return this->subListItem(obj);
+ } else if constexpr (std::is_same_v<BaseT, SimpleObjectWrap>) {
+ return this->subObjectWrapItem(obj);
+ } else if constexpr (IsDomObject<BaseT>::value) {
+ if constexpr (domTypeIsObjWrap(BaseT::kindValue) || domTypeIsValueWrap(BaseT::kindValue)) {
+ return this->subObjectWrapItem(
+ SimpleObjectWrap::fromObjectRef(this->pathFromOwner().appendComponent(c), obj));
+ } else if constexpr (domTypeIsDomElement(BaseT::kindValue)) {
+ return this->copy(&obj);
+ } else {
+ qCWarning(domLog) << "Unhandled object of type " << domTypeToString(BaseT::kindValue)
+ << " in DomItem::wrap, not using a shared_ptr for an "
+ << "OwningItem, or unexpected wrapped object?";
+ return DomItem();
+ }
+ } else if constexpr (IsSharedPointerToDomObject<BaseT>::value) {
+ if constexpr (domTypeIsOwningItem(BaseT::element_type::kindValue)) {
+ return this->subOwnerItem(c, obj);
+ } else {
+ Q_ASSERT_X(false, "DomItem::wrap", "shared_ptr with non owning item");
+ return DomItem();
+ }
+ } else if constexpr (IsMultiMap<BaseT>::value) {
+ if constexpr (std::is_same_v<typename BaseT::key_type, QString>) {
+ return subMapItem(Map::fromMultiMapRef<typename BaseT::mapped_type>(
+ pathFromOwner().appendComponent(c), obj));
+ } else {
+ Q_ASSERT_X(false, "DomItem::wrap", "non string keys not supported (try .toString()?)");
+ }
+ } else if constexpr (IsMap<BaseT>::value) {
+ if constexpr (std::is_same_v<typename BaseT::key_type, QString>) {
+ return subMapItem(Map::fromMapRef<typename BaseT::mapped_type>(
+ pathFromOwner().appendComponent(c), obj,
+ [](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()?)");
+ }
+ } else if constexpr (IsList<BaseT>::value) {
+ if constexpr (IsDomObject<typename BaseT::value_type>::value) {
+ return subListItem(List::fromQListRef<typename BaseT::value_type>(
+ pathFromOwner().appendComponent(c), obj,
+ [](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();
+ }
+ } else {
+ qCWarning(domLog) << "Cannot wrap " << typeid(BaseT).name();
+ Q_ASSERT_X(false, "DomItem::wrap", "Do not know how to wrap type T");
+ return DomItem();
+ }
+}
+
+template<typename T>
+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(const DomItem &self, DirectVisitor v) const
+{
+ index_type len = index_type(m_pList.size());
+ for (index_type i = 0; i < len; ++i) {
+ if (!v(PathEls::Index(i), [this, &self, i] { return this->index(self, i); }))
+ return false;
+ }
+ return true;
+}
+
+template<typename T>
+DomItem ListPT<T>::index(const DomItem &self, index_type index) const
+{
+ if (index >= 0 && index < m_pList.size())
+ return self.wrap(PathEls::Index(index), *static_cast<const T *>(m_pList.value(index)));
+ return DomItem();
+}
+
+// allow inlining of DomBase
+inline DomKind DomBase::domKind() const
+{
+ return kind2domKind(kind());
+}
+
+inline bool DomBase::iterateDirectSubpathsConst(const DomItem &self, DirectVisitor visitor) const
+{
+ Q_ASSERT(self.base() == this);
+ return self.iterateDirectSubpaths(std::move(visitor));
+}
+
+inline DomItem DomBase::containingObject(const DomItem &self) const
+{
+ Path path = pathFromOwner(self);
+ DomItem base = self.owner();
+ if (!path) {
+ path = canonicalPath(self);
+ base = self;
+ }
+ Source source = path.split();
+ return base.path(source.pathToSource);
+}
+
+inline quintptr DomBase::id() const
+{
+ return quintptr(this);
+}
+
+inline QString DomBase::typeName() const
+{
+ return domTypeToString(kind());
+}
+
+inline QList<QString> DomBase::fields(const DomItem &self) const
+{
+ QList<QString> res;
+ self.iterateDirectSubpaths([&res](const PathEls::PathComponent &c, function_ref<DomItem()>) {
+ if (c.kind() == Path::Kind::Field)
+ res.append(c.name());
+ return true;
+ });
+ return res;
+}
+
+inline DomItem DomBase::field(const DomItem &self, QStringView name) const
+{
+ DomItem res;
+ self.iterateDirectSubpaths(
+ [&res, name](const PathEls::PathComponent &c, function_ref<DomItem()> obj) {
+ if (c.kind() == Path::Kind::Field && c.checkName(name)) {
+ res = obj();
+ return false;
+ }
+ return true;
+ });
+ return res;
+}
+
+inline index_type DomBase::indexes(const DomItem &self) const
+{
+ index_type res = 0;
+ self.iterateDirectSubpaths([&res](const PathEls::PathComponent &c, function_ref<DomItem()>) {
+ if (c.kind() == Path::Kind::Index) {
+ index_type i = c.index() + 1;
+ if (res < i)
+ res = i;
+ }
+ return true;
+ });
+ return res;
+}
+
+inline DomItem DomBase::index(const DomItem &self, qint64 index) const
+{
+ DomItem res;
+ self.iterateDirectSubpaths(
+ [&res, index](const PathEls::PathComponent &c, function_ref<DomItem()> obj) {
+ if (c.kind() == Path::Kind::Index && c.index() == index) {
+ res = obj();
+ return false;
+ }
+ return true;
+ });
+ return res;
+}
+
+inline QSet<QString> const DomBase::keys(const DomItem &self) const
+{
+ QSet<QString> res;
+ self.iterateDirectSubpaths([&res](const PathEls::PathComponent &c, function_ref<DomItem()>) {
+ if (c.kind() == Path::Kind::Key)
+ res.insert(c.name());
+ return true;
+ });
+ return res;
+}
+
+inline DomItem DomBase::key(const DomItem &self, const QString &name) const
+{
+ DomItem res;
+ self.iterateDirectSubpaths(
+ [&res, name](const PathEls::PathComponent &c, function_ref<DomItem()> obj) {
+ if (c.kind() == Path::Kind::Key && c.checkName(name)) {
+ res = obj();
+ return false;
+ }
+ return true;
+ });
+ return res;
+}
+
+inline DomItem DomItem::subListItem(const List &list) const
+{
+ return DomItem(m_top, m_owner, m_ownerPath, list);
+}
+
+inline DomItem DomItem::subMapItem(const Map &map) const
+{
+ return DomItem(m_top, m_owner, m_ownerPath, map);
}
} // end namespace Dom