diff options
Diffstat (limited to 'src/qmldom/qqmldomitem_p.h')
-rw-r--r-- | src/qmldom/qqmldomitem_p.h | 1288 |
1 files changed, 773 insertions, 515 deletions
diff --git a/src/qmldom/qqmldomitem_p.h b/src/qmldom/qqmldomitem_p.h index 631a0ff335..50775a1db2 100644 --- a/src/qmldom/qqmldomitem_p.h +++ b/src/qmldom/qqmldomitem_p.h @@ -17,6 +17,7 @@ #include "qqmldom_global.h" #include "qqmldom_fwd_p.h" +#include "qqmldom_utils_p.h" #include "qqmldomconstants_p.h" #include "qqmldomstringdumper_p.h" #include "qqmldompath_p.h" @@ -24,6 +25,7 @@ #include "qqmldomfunctionref_p.h" #include "qqmldomfilewriter_p.h" #include "qqmldomlinewriter_p.h" +#include "qqmldomfieldfilter_p.h" #include <QtCore/QMap> #include <QtCore/QMultiMap> @@ -36,6 +38,7 @@ #include <QtCore/QCborValue> #include <QtCore/QTimeZone> #include <QtQml/private/qqmljssourcelocation_p.h> +#include <QtQmlCompiler/private/qqmljsscope_p.h> #include <memory> #include <typeinfo> @@ -60,6 +63,7 @@ constexpr bool domTypeIsValueWrap(DomType k); constexpr bool domTypeIsDomElement(DomType); constexpr bool domTypeIsOwningItem(DomType); constexpr bool domTypeIsUnattachedOwningItem(DomType); +constexpr bool domTypeIsScriptElement(DomType); QMLDOM_EXPORT bool domTypeIsExternalItem(DomType k); QMLDOM_EXPORT bool domTypeIsTopItem(DomType k); QMLDOM_EXPORT bool domTypeIsContainer(DomType k); @@ -72,6 +76,7 @@ constexpr bool domTypeCanBeInline(DomType k) case DomType::ListP: case DomType::ConstantData: case DomType::SimpleObjectWrap: + case DomType::ScriptElementWrap: case DomType::Reference: return true; default: @@ -85,15 +90,13 @@ QMLDOM_EXPORT QString domTypeToString(DomType k); QMLDOM_EXPORT QMap<DomKind, QString> domKindToStringMap(); QMLDOM_EXPORT QString domKindToString(DomKind k); -QMLDOM_EXPORT QCborValue locationToData(SourceLocation loc, QStringView strValue=u""); - -inline bool noFilter(DomItem &, const PathEls::PathComponent &, DomItem &) +inline bool noFilter(const DomItem &, const PathEls::PathComponent &, const DomItem &) { return true; } using DirectVisitor = function_ref<bool(const PathEls::PathComponent &, function_ref<DomItem()>)>; -// using DirectVisitor = function_ref<bool(Path, DomItem &)>; +// using DirectVisitor = function_ref<bool(Path, const DomItem &)>; namespace { template<typename T> @@ -176,8 +179,11 @@ template<typename T> union SubclassStorage { int i; T lp; + + // TODO: these are extremely nasty. What is this int doing in here? T *data() { return reinterpret_cast<T *>(this); } const T *data() const { return reinterpret_cast<const T *>(this); } + SubclassStorage() { } SubclassStorage(T &&el) { el.moveTo(data()); } SubclassStorage(const T *el) { el->copyTo(data()); } @@ -192,42 +198,47 @@ union SubclassStorage { ~SubclassStorage() { data()->~T(); } }; -class QMLDOM_EXPORT DomBase{ +class QMLDOM_EXPORT DomBase +{ public: + using FilterT = function_ref<bool(const DomItem &, const PathEls::PathComponent &, const DomItem &)>; + virtual ~DomBase() = default; + DomBase *domBase() { return this; } + const DomBase *domBase() const { return this; } + // minimal overload set: virtual DomType kind() const = 0; virtual DomKind domKind() const; - virtual Path pathFromOwner(DomItem &self) const = 0; - virtual Path canonicalPath(DomItem &self) const = 0; + virtual Path pathFromOwner(const DomItem &self) const = 0; + virtual Path canonicalPath(const DomItem &self) const = 0; virtual bool - iterateDirectSubpaths(DomItem &self, - DirectVisitor visitor) = 0; // iterates the *direct* subpaths, returns - // false if a quick end was requested - bool iterateDirectSubpathsConst(DomItem &self, DirectVisitor) + iterateDirectSubpaths(const DomItem &self, + DirectVisitor visitor) const = 0; // iterates the *direct* subpaths, returns + // false if a quick end was requested + + bool iterateDirectSubpathsConst(const DomItem &self, DirectVisitor) const; // iterates the *direct* subpaths, returns false if a quick end was requested virtual DomItem containingObject( - DomItem &self) const; // the DomItem corresponding to the canonicalSource source - virtual void - dump(DomItem &, Sink sink, int indent, - function_ref<bool(DomItem &, const PathEls::PathComponent &, DomItem &)> filter) const; + const DomItem &self) const; // the DomItem corresponding to the canonicalSource source + virtual void dump(const DomItem &, const Sink &sink, int indent, FilterT filter) const; virtual quintptr id() const; QString typeName() const; - virtual QList<QString> fields(DomItem &self) const; - virtual DomItem field(DomItem &self, QStringView name) const; + virtual QList<QString> fields(const DomItem &self) const; + virtual DomItem field(const DomItem &self, QStringView name) const; - virtual index_type indexes(DomItem &self) const; - virtual DomItem index(DomItem &self, index_type index) const; + virtual index_type indexes(const DomItem &self) const; + virtual DomItem index(const DomItem &self, index_type index) const; - virtual QSet<QString> const keys(DomItem &self) const; - virtual DomItem key(DomItem &self, QString name) const; + virtual QSet<QString> const keys(const DomItem &self) const; + virtual DomItem key(const DomItem &self, const QString &name) const; - virtual QString canonicalFilePath(DomItem &self) const; + virtual QString canonicalFilePath(const DomItem &self) const; - virtual void writeOut(DomItem &self, OutWriter &lw) const; + virtual void writeOut(const DomItem &self, OutWriter &lw) const; virtual QCborValue value() const { return QCborValue(); @@ -264,12 +275,12 @@ public: Empty(); quintptr id() const override { return ~quintptr(0); } - Path pathFromOwner(DomItem &self) const override; - Path canonicalPath(DomItem &self) const override; - DomItem containingObject(DomItem &self) const override; - bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override; - void dump(DomItem &, Sink s, int indent, - function_ref<bool(DomItem &, const PathEls::PathComponent &, DomItem &)> filter) + Path pathFromOwner(const DomItem &self) const override; + Path canonicalPath(const DomItem &self) const override; + DomItem containingObject(const DomItem &self) const override; + bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override; + void dump(const DomItem &, const Sink &s, int indent, + function_ref<bool(const DomItem &, const PathEls::PathComponent &, const DomItem &)> filter) const override; }; @@ -277,13 +288,14 @@ class QMLDOM_EXPORT DomElement: public DomBase { protected: DomElement& operator=(const DomElement&) = default; public: - DomElement(Path pathFromOwner = Path()); + DomElement(const Path &pathFromOwner = Path()); DomElement(const DomElement &o) = default; - Path pathFromOwner(DomItem &self) const override; + Path pathFromOwner(const DomItem &self) const override; Path pathFromOwner() const { return m_pathFromOwner; } - Path canonicalPath(DomItem &self) const override; - DomItem containingObject(DomItem &self) const override; - virtual void updatePathFromOwner(Path newPath); + Path canonicalPath(const DomItem &self) const override; + DomItem containingObject(const DomItem &self) const override; + virtual void updatePathFromOwner(const Path &newPath); + private: Path m_pathFromOwner; }; @@ -299,22 +311,35 @@ public: Map &operator*() { return *this; } const Map &operator*() const { return *this; } - using LookupFunction = std::function<DomItem(DomItem &, QString)>; - using Keys = std::function<QSet<QString>(DomItem &)>; - Map(Path pathFromOwner, LookupFunction lookup, Keys keys, QString targetType); + using LookupFunction = std::function<DomItem(const DomItem &, QString)>; + using Keys = std::function<QSet<QString>(const DomItem &)>; + Map(const Path &pathFromOwner, const LookupFunction &lookup, + const Keys &keys, const QString &targetType); quintptr id() const override; - bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override; - QSet<QString> const keys(DomItem &self) const override; - DomItem key(DomItem &self, QString name) const override; + bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override; + QSet<QString> const keys(const DomItem &self) const override; + DomItem key(const DomItem &self, const QString &name) const override; template<typename T> - static Map fromMultiMapRef(Path pathFromOwner, QMultiMap<QString, T> &mmap); + static Map fromMultiMapRef(const Path &pathFromOwner, const QMultiMap<QString, T> &mmap); + template<typename T> + static Map fromMultiMap(const Path &pathFromOwner, const QMultiMap<QString, T> &mmap); template<typename T> static Map - fromMapRef(Path pathFromOwner, QMap<QString, T> &mmap, - std::function<DomItem(DomItem &, const PathEls::PathComponent &, T &)> elWrapper); + fromMapRef( + const Path &pathFromOwner, const QMap<QString, T> &mmap, + const std::function<DomItem(const DomItem &, const PathEls::PathComponent &, const T &)> &elWrapper); + + template<typename T> + static Map fromFileRegionMap( + const Path &pathFromOwner, const QMap<FileLocationRegion, T> &map); + template<typename T> + static Map fromFileRegionListMap( + const Path &pathFromOwner, const QMap<FileLocationRegion, QList<T>> &map); private: + template<typename MapT> + static QSet<QString> fileRegionKeysFromMap(const MapT &map); LookupFunction m_lookup; Keys m_keys; QString m_targetType; @@ -331,32 +356,33 @@ public: List &operator*() { return *this; } const List &operator*() const { return *this; } - using LookupFunction = std::function<DomItem(DomItem &, index_type)>; - using Length = std::function<index_type(DomItem &)>; + using LookupFunction = std::function<DomItem(const DomItem &, index_type)>; + using Length = std::function<index_type(const DomItem &)>; using IteratorFunction = - std::function<bool(DomItem &, function_ref<bool(index_type, function_ref<DomItem()>)>)>; + std::function<bool(const DomItem &, function_ref<bool(index_type, function_ref<DomItem()>)>)>; - List(Path pathFromOwner, LookupFunction lookup, Length length, IteratorFunction iterator, QString elType); + List(const Path &pathFromOwner, const LookupFunction &lookup, const Length &length, + const IteratorFunction &iterator, const QString &elType); quintptr id() const override; - bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override; + bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override; void - dump(DomItem &, Sink s, int indent, - function_ref<bool(DomItem &, const PathEls::PathComponent &, DomItem &)>) const override; - index_type indexes(DomItem &self) const override; - DomItem index(DomItem &self, index_type index) const override; + dump(const DomItem &, const Sink &s, int indent, + function_ref<bool(const DomItem &, const PathEls::PathComponent &, const DomItem &)>) const override; + index_type indexes(const DomItem &self) const override; + DomItem index(const DomItem &self, index_type index) const override; template<typename T> static List - fromQList(Path pathFromOwner, QList<T> list, - std::function<DomItem(DomItem &, const PathEls::PathComponent &, T &)> elWrapper, + fromQList(const Path &pathFromOwner, const QList<T> &list, + const std::function<DomItem(const DomItem &, const PathEls::PathComponent &, const T &)> &elWrapper, ListOptions options = ListOptions::Normal); template<typename T> static List - fromQListRef(Path pathFromOwner, QList<T> &list, - std::function<DomItem(DomItem &, const PathEls::PathComponent &, T &)> elWrapper, + fromQListRef(const Path &pathFromOwner, const QList<T> &list, + const std::function<DomItem(const DomItem &, const PathEls::PathComponent &, const T &)> &elWrapper, ListOptions options = ListOptions::Normal); - void writeOut(DomItem &self, OutWriter &ow, bool compact) const; - void writeOut(DomItem &self, OutWriter &ow) const override { writeOut(self, ow, true); } + void writeOut(const DomItem &self, OutWriter &ow, bool compact) const; + void writeOut(const DomItem &self, OutWriter &ow) const override { writeOut(self, ow, true); } private: LookupFunction m_lookup; @@ -371,20 +397,20 @@ public: constexpr static DomType kindValue = DomType::ListP; DomType kind() const override { return kindValue; } - ListPBase(Path pathFromOwner, const QList<void *> &pList, QString elType) + ListPBase(const Path &pathFromOwner, const QList<const void *> &pList, const QString &elType) : DomElement(pathFromOwner), m_pList(pList), m_elType(elType) { } - bool iterateDirectSubpaths(DomItem &self, DirectVisitor v) override; + bool iterateDirectSubpaths(const DomItem &self, DirectVisitor v) const override; virtual void copyTo(ListPBase *) const { Q_ASSERT(false); }; virtual void moveTo(ListPBase *) const { Q_ASSERT(false); }; quintptr id() const override { return quintptr(0); } - index_type indexes(DomItem &) const override { return index_type(m_pList.size()); } - void writeOut(DomItem &self, OutWriter &ow, bool compact) const; - void writeOut(DomItem &self, OutWriter &ow) const override { writeOut(self, ow, true); } + index_type indexes(const DomItem &) const override { return index_type(m_pList.size()); } + void writeOut(const DomItem &self, OutWriter &ow, bool compact) const; + void writeOut(const DomItem &self, OutWriter &ow) const override { writeOut(self, ow, true); } protected: - QList<void *> m_pList; + QList<const void *> m_pList; QString m_elType; }; @@ -394,7 +420,7 @@ class ListPT final : public ListPBase public: constexpr static DomType kindValue = DomType::ListP; - ListPT(Path pathFromOwner, QList<T *> pList, QString elType = QString(), + ListPT(const Path &pathFromOwner, const QList<T *> &pList, const QString &elType = QString(), ListOptions options = ListOptions::Normal) : ListPBase(pathFromOwner, {}, (elType.isEmpty() ? QLatin1String(typeid(T).name()) : elType)) @@ -405,7 +431,7 @@ public: "ListPT does not have the same size as ListPBase"); m_pList.reserve(pList.size()); if (options == ListOptions::Normal) { - for (void *p : pList) + for (const void *p : pList) m_pList.append(p); } else if (options == ListOptions::Reverse) { for (qsizetype i = pList.size(); i-- != 0;) @@ -417,9 +443,9 @@ public: } void copyTo(ListPBase *t) const override { new (t) ListPT(*this); } void moveTo(ListPBase *t) const override { new (t) ListPT(std::move(*this)); } - bool iterateDirectSubpaths(DomItem &self, DirectVisitor v) override; + bool iterateDirectSubpaths(const DomItem &self, DirectVisitor v) const override; - DomItem index(DomItem &self, index_type index) const override; + DomItem index(const DomItem &self, index_type index) const override; }; class QMLDOM_EXPORT ListP @@ -427,7 +453,7 @@ class QMLDOM_EXPORT ListP public: constexpr static DomType kindValue = DomType::ListP; template<typename T> - ListP(Path pathFromOwner, QList<T *> pList, QString elType = QString(), + ListP(const Path &pathFromOwner, const QList<T *> &pList, const QString &elType = QString(), ListOptions options = ListOptions::Normal) : list(ListPT<T>(pathFromOwner, pList, elType, options)) { @@ -459,8 +485,9 @@ public: ConstantData &operator*() { return *this; } const ConstantData &operator*() const { return *this; } - ConstantData(Path pathFromOwner, QCborValue value, Options options = Options::MapIsMap); - bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override; + ConstantData(const Path &pathFromOwner, const QCborValue &value, + Options options = Options::MapIsMap); + bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override; quintptr id() const override; DomKind domKind() const override; QCborValue value() const override { return m_value; } @@ -484,27 +511,17 @@ public: { if (m_options & SimpleWrapOption::ValueType) { if (m_value.metaType() == QMetaType::fromType<T>()) - return reinterpret_cast<const T *>(m_value.constData()); - return nullptr; - } else { - return m_value.value<T *>(); - } - } - template <typename T> - T *mutableAs() - { - if (m_options & SimpleWrapOption::ValueType) { - if (m_value.metaType() == QMetaType::fromType<T>()) - return reinterpret_cast<T *>(m_value.data()); + return static_cast<const T *>(m_value.constData()); return nullptr; } else { - return m_value.value<T *>(); + return m_value.value<const T *>(); } } + SimpleObjectWrapBase() = delete; virtual void copyTo(SimpleObjectWrapBase *) const { Q_ASSERT(false); } virtual void moveTo(SimpleObjectWrapBase *) const { Q_ASSERT(false); } - bool iterateDirectSubpaths(DomItem &, DirectVisitor) override + bool iterateDirectSubpaths(const DomItem &, DirectVisitor) const override { Q_ASSERT(false); return true; @@ -512,7 +529,7 @@ public: protected: friend class TestDomItem; - SimpleObjectWrapBase(Path pathFromOwner, QVariant value, quintptr idValue, + SimpleObjectWrapBase(const Path &pathFromOwner, const QVariant &value, quintptr idValue, DomType kind = kindValue, SimpleWrapOptions options = SimpleWrapOption::None) : DomElement(pathFromOwner), @@ -537,21 +554,21 @@ class SimpleObjectWrapT final : public SimpleObjectWrapBase public: constexpr static DomType kindValue = DomType::SimpleObjectWrap; - bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) override + bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override { - return mutableAsT()->iterateDirectSubpaths(self, visitor); + return asT()->iterateDirectSubpaths(self, visitor); } - void writeOut(DomItem &self, OutWriter &lw) const override; + void writeOut(const DomItem &self, OutWriter &lw) const override; - T const *asT() const + const T *asT() const { if constexpr (domTypeIsValueWrap(T::kindValue)) { if (m_value.metaType() == QMetaType::fromType<T>()) - return reinterpret_cast<const T *>(m_value.constData()); + return static_cast<const T *>(m_value.constData()); return nullptr; } else if constexpr (domTypeIsObjWrap(T::kindValue)) { - return m_value.value<T *>(); + return m_value.value<const T *>(); } else { // need dependent static assert to not unconditially trigger static_assert(!std::is_same_v<T, T>, "wrapping of unexpected type"); @@ -559,20 +576,6 @@ public: } } - T *mutableAsT() - { - if (domTypeIsValueWrap(T::kindValue)) { - if (m_value.metaType() == QMetaType::fromType<T>()) - return reinterpret_cast<T *>(m_value.data()); - return nullptr; - } else if constexpr (domTypeIsObjWrap(T::kindValue)) { - return m_value.value<T *>(); - } else { - Q_ASSERT_X(false, "SimpleObjectWrap", "wrapping of unexpected type"); - return nullptr; - } - } - void copyTo(SimpleObjectWrapBase *target) const override { static_assert(sizeof(SimpleObjectWrapBase) == sizeof(SimpleObjectWrapT), @@ -591,7 +594,8 @@ public: new (target) SimpleObjectWrapT(std::move(*this)); } - SimpleObjectWrapT(Path pathFromOwner, QVariant v, quintptr idValue, SimpleWrapOptions o) + SimpleObjectWrapT(const Path &pathFromOwner, const QVariant &v, + quintptr idValue, SimpleWrapOptions o) : SimpleObjectWrapBase(pathFromOwner, v, idValue, T::kindValue, o) { Q_ASSERT(domTypeIsValueWrap(T::kindValue) == bool(o & SimpleWrapOption::ValueType)); @@ -609,7 +613,7 @@ public: const SimpleObjectWrapBase &operator*() const { return *wrap.data(); } template<typename T> - static SimpleObjectWrap fromObjectRef(Path pathFromOwner, T &value) + static SimpleObjectWrap fromObjectRef(const Path &pathFromOwner, T &value) { return SimpleObjectWrap(pathFromOwner, value); } @@ -617,7 +621,7 @@ public: private: template<typename T> - SimpleObjectWrap(Path pathFromOwner, T &value) + SimpleObjectWrap(const Path &pathFromOwner, T &value) { using BaseT = std::decay_t<T>; if constexpr (domTypeIsObjWrap(BaseT::kindValue)) { @@ -651,57 +655,248 @@ public: const Reference &operator*() const { return *this; } bool shouldCache() const; - Reference(Path referredObject = Path(), Path pathFromOwner = Path(), const SourceLocation & loc = SourceLocation()); + Reference(const Path &referredObject = Path(), const Path &pathFromOwner = Path(), + const SourceLocation &loc = SourceLocation()); quintptr id() const override; - bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override; - DomItem field(DomItem &self, QStringView name) const override; - QList<QString> fields(DomItem &self) const override; - index_type indexes(DomItem &) const override { return 0; } - DomItem index(DomItem &, index_type) const override; - QSet<QString> const keys(DomItem &) const override { return {}; } - DomItem key(DomItem &, QString) const override; - - DomItem get(DomItem &self, ErrorHandler h = nullptr, QList<Path> *visitedRefs = nullptr) const; - QList<DomItem> getAll(DomItem &self, ErrorHandler h = nullptr, + bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override; + DomItem field(const DomItem &self, QStringView name) const override; + QList<QString> fields(const DomItem &self) const override; + index_type indexes(const DomItem &) const override { return 0; } + DomItem index(const DomItem &, index_type) const override; + QSet<QString> const keys(const DomItem &) const override { return {}; } + DomItem key(const DomItem &, const QString &) const override; + + DomItem get(const DomItem &self, const ErrorHandler &h = nullptr, + QList<Path> *visitedRefs = nullptr) const; + QList<DomItem> getAll(const DomItem &self, const ErrorHandler &h = nullptr, QList<Path> *visitedRefs = nullptr) const; Path referredObjectPath; }; -using ElementT = std::variant< - Empty, Map, List, ListP, ConstantData, SimpleObjectWrap, Reference, GlobalComponent *, - JsResource *, QmlComponent *, QmltypesComponent *, EnumDecl *, MockObject *, ModuleScope *, - AstComments *, AttachedInfo *, DomEnvironment *, DomUniverse *, ExternalItemInfoBase *, - ExternalItemPairBase *, GlobalScope *, JsFile *, QmlDirectory *, QmlFile *, QmldirFile *, - QmlObject *, QmltypesFile *, LoadInfo *, MockOwner *, ModuleIndex *, ScriptExpression *>; +template<typename Info> +class AttachedInfoT; +class FileLocations; + +/*! + \internal + \brief A common base class for all the script elements. + + This marker class allows to use all the script elements as a ScriptElement*, using virtual + dispatch. For now, it does not add any extra functionality, compared to a DomElement, but allows + to forbid DomElement* at the places where only script elements are required. + */ +// TODO: do we need another marker struct like this one to differentiate expressions from +// statements? This would allow to avoid mismatchs between script expressions and script statements, +// using type-safety. +struct ScriptElement : public DomElement +{ + template<typename T> + using PointerType = std::shared_ptr<T>; + + using DomElement::DomElement; + virtual void createFileLocations( + const std::shared_ptr<AttachedInfoT<FileLocations>> &fileLocationOfOwner) = 0; + + QQmlJSScope::ConstPtr semanticScope(); + void setSemanticScope(const QQmlJSScope::ConstPtr &scope); + +private: + QQmlJSScope::ConstPtr m_scope; +}; + +/*! + \internal + \brief Use this to contain any script element. + */ +class ScriptElementVariant +{ +private: + template<typename... T> + using VariantOfPointer = std::variant<ScriptElement::PointerType<T>...>; + + template<typename T, typename Variant> + struct TypeIsInVariant; + + template<typename T, typename... Ts> + struct TypeIsInVariant<T, std::variant<Ts...>> : public std::disjunction<std::is_same<T, Ts>...> + { + }; + +public: + using ScriptElementT = + VariantOfPointer<ScriptElements::BlockStatement, ScriptElements::IdentifierExpression, + ScriptElements::ForStatement, ScriptElements::BinaryExpression, + ScriptElements::VariableDeclarationEntry, ScriptElements::Literal, + ScriptElements::IfStatement, ScriptElements::GenericScriptElement, + ScriptElements::VariableDeclaration, ScriptElements::ReturnStatement>; + + template<typename T> + static ScriptElementVariant fromElement(const T &element) + { + static_assert(TypeIsInVariant<T, ScriptElementT>::value, + "Cannot construct ScriptElementVariant from T, as it is missing from the " + "ScriptElementT."); + ScriptElementVariant p; + p.m_data = element; + return p; + } + + ScriptElement::PointerType<ScriptElement> base() const; + + operator bool() const { return m_data.has_value(); } + + template<typename F> + void visitConst(F &&visitor) const + { + if (m_data) + std::visit(std::forward<F>(visitor), *m_data); + } + + template<typename F> + void visit(F &&visitor) + { + if (m_data) + std::visit(std::forward<F>(visitor), *m_data); + } + std::optional<ScriptElementT> data() { return m_data; } + void setData(const ScriptElementT &data) { m_data = data; } + +private: + std::optional<ScriptElementT> m_data; +}; + +/*! + \internal + + To avoid cluttering the already unwieldy \l ElementT type below with all the types that the + different script elements can have, wrap them in an extra class. It will behave like an internal + Dom structure (e.g. like a List or a Map) and contain a pointer the the script element. + */ +class ScriptElementDomWrapper +{ +public: + ScriptElementDomWrapper(const ScriptElementVariant &element) : m_element(element) { } + + static constexpr DomType kindValue = DomType::ScriptElementWrap; -using TopT = std::variant<std::shared_ptr<DomEnvironment>, std::shared_ptr<DomUniverse>>; + DomBase *operator->() { return m_element.base().get(); } + const DomBase *operator->() const { return m_element.base().get(); } + DomBase &operator*() { return *m_element.base(); } + const DomBase &operator*() const { return *m_element.base(); } -using OwnerT = - std::variant<std::shared_ptr<ModuleIndex>, std::shared_ptr<MockOwner>, - std::shared_ptr<ExternalItemInfoBase>, std::shared_ptr<ExternalItemPairBase>, - std::shared_ptr<QmlDirectory>, std::shared_ptr<QmldirFile>, - std::shared_ptr<JsFile>, std::shared_ptr<QmlFile>, - std::shared_ptr<QmltypesFile>, std::shared_ptr<GlobalScope>, - std::shared_ptr<ScriptExpression>, std::shared_ptr<AstComments>, - std::shared_ptr<LoadInfo>, std::shared_ptr<AttachedInfo>, - std::shared_ptr<DomEnvironment>, std::shared_ptr<DomUniverse>>; + ScriptElementVariant element() const { return m_element; } -inline bool emptyChildrenVisitor(Path, DomItem &, bool) +private: + ScriptElementVariant m_element; +}; + +// TODO: create more "groups" to simplify this variant? Maybe into Internal, ScriptExpression, ??? +using ElementT = + std::variant< + ConstantData, + Empty, + List, + ListP, + Map, + Reference, + ScriptElementDomWrapper, + SimpleObjectWrap, + const AstComments *, + const AttachedInfo *, + const DomEnvironment *, + const DomUniverse *, + const EnumDecl *, + const ExternalItemInfoBase *, + const ExternalItemPairBase *, + const GlobalComponent *, + const GlobalScope *, + const JsFile *, + const JsResource *, + const LoadInfo *, + const MockObject *, + const MockOwner *, + const ModuleIndex *, + const ModuleScope *, + const QmlComponent *, + const QmlDirectory *, + const QmlFile *, + const QmlObject *, + const QmldirFile *, + const QmltypesComponent *, + const QmltypesFile *, + const ScriptExpression * + >; + +using TopT = std::variant< + std::monostate, + std::shared_ptr<DomEnvironment>, + std::shared_ptr<DomUniverse>>; + +using OwnerT = std::variant< + std::monostate, + std::shared_ptr<ModuleIndex>, + std::shared_ptr<MockOwner>, + std::shared_ptr<ExternalItemInfoBase>, + std::shared_ptr<ExternalItemPairBase>, + std::shared_ptr<QmlDirectory>, + std::shared_ptr<QmldirFile>, + std::shared_ptr<JsFile>, + std::shared_ptr<QmlFile>, + std::shared_ptr<QmltypesFile>, + std::shared_ptr<GlobalScope>, + std::shared_ptr<ScriptExpression>, + std::shared_ptr<AstComments>, + std::shared_ptr<LoadInfo>, + std::shared_ptr<AttachedInfo>, + std::shared_ptr<DomEnvironment>, + std::shared_ptr<DomUniverse>>; + +inline bool emptyChildrenVisitor(Path, const DomItem &, bool) { return true; } class MutableDomItem; +class FileToLoad +{ +public: + struct InMemoryContents + { + QString data; + QDateTime date = QDateTime::currentDateTimeUtc(); + }; + + FileToLoad(const std::weak_ptr<DomEnvironment> &environment, const QString &canonicalPath, + const QString &logicalPath, const std::optional<InMemoryContents> &content); + FileToLoad() = default; + + static FileToLoad fromMemory(const std::weak_ptr<DomEnvironment> &environment, + const QString &path, const QString &data); + static FileToLoad fromFileSystem(const std::weak_ptr<DomEnvironment> &environment, + const QString &canonicalPath); + + std::weak_ptr<DomEnvironment> environment() const { return m_environment; } + QString canonicalPath() const { return m_canonicalPath; } + QString logicalPath() const { return m_logicalPath; } + std::optional<InMemoryContents> content() const { return m_content; } + +private: + std::weak_ptr<DomEnvironment> m_environment; + QString m_canonicalPath; + QString m_logicalPath; + std::optional<InMemoryContents> m_content; +}; + class QMLDOM_EXPORT DomItem { Q_DECLARE_TR_FUNCTIONS(DomItem); public: - using Callback = function<void(Path, DomItem &, DomItem &)>; + using Callback = function<void(const Path &, const DomItem &, const DomItem &)>; using InternalKind = DomType; - using Visitor = function_ref<bool(Path, DomItem &)>; - using ChildrenVisitor = function_ref<bool(Path, DomItem &, bool)>; + using Visitor = function_ref<bool(const Path &, const DomItem &)>; + using ChildrenVisitor = function_ref<bool(const Path &, const DomItem &, bool)>; static ErrorGroup domErrorGroup; static ErrorGroups myErrors(); @@ -711,12 +906,7 @@ public: enum class CopyOption { EnvConnected, EnvDisconnected }; template<typename F> - auto visitMutableEl(F f) - { - return std::visit(f, this->m_element); - } - template<typename F> - auto visitEl(F f) + auto visitEl(F f) const { return std::visit(f, this->m_element); } @@ -734,48 +924,55 @@ public: return kind2domKind(m_kind); } - Path canonicalPath(); + Path canonicalPath() const; - DomItem filterUp(function_ref<bool(DomType k, DomItem &)> filter, FilterUpOptions options); - DomItem containingObject(); - DomItem container(); - DomItem owner(); - DomItem top(); - DomItem environment(); - DomItem universe(); + DomItem filterUp(function_ref<bool(DomType k, const DomItem &)> filter, FilterUpOptions options) const; + DomItem containingObject() const; + DomItem container() const; + DomItem owner() const; + DomItem top() const; + DomItem environment() const; + DomItem universe() const; + DomItem containingFile() const; + DomItem containingScriptExpression() const; + DomItem goToFile(const QString &filePath) const; + DomItem goUp(int) const; + DomItem directParent() const; DomItem qmlObject(GoTo option = GoTo::Strict, - FilterUpOptions options = FilterUpOptions::ReturnOuter); - DomItem fileObject(GoTo option = GoTo::Strict); - DomItem rootQmlObject(GoTo option = GoTo::Strict); - DomItem globalScope(); - DomItem component(GoTo option = GoTo::Strict); - DomItem scope(FilterUpOptions options = FilterUpOptions::ReturnOuter); + FilterUpOptions options = FilterUpOptions::ReturnOuter) const; + DomItem fileObject(GoTo option = GoTo::Strict) const; + DomItem rootQmlObject(GoTo option = GoTo::Strict) const; + DomItem globalScope() const; + DomItem component(GoTo option = GoTo::Strict) const; + DomItem scope(FilterUpOptions options = FilterUpOptions::ReturnOuter) const; + QQmlJSScope::ConstPtr nearestSemanticScope() const; + QQmlJSScope::ConstPtr semanticScope() const; // convenience getters - DomItem get(ErrorHandler h = nullptr, QList<Path> *visitedRefs = nullptr); - QList<DomItem> getAll(ErrorHandler h = nullptr, QList<Path> *visitedRefs = nullptr); - bool isOwningItem() { return domTypeIsOwningItem(internalKind()); } - bool isExternalItem() { return domTypeIsExternalItem(internalKind()); } - bool isTopItem() { return domTypeIsTopItem(internalKind()); } - bool isContainer() { return domTypeIsContainer(internalKind()); } - bool isScope() { return domTypeIsScope(internalKind()); } - bool isCanonicalChild(DomItem &child); - bool hasAnnotations(); - QString name() { return field(Fields::name).value().toString(); } - DomItem pragmas() { return field(Fields::pragmas); } - DomItem ids() { return field(Fields::ids); } - QString idStr() { return field(Fields::idStr).value().toString(); } - DomItem propertyInfos() { return field(Fields::propertyInfos); } - PropertyInfo propertyInfoWithName(QString name); - QSet<QString> propertyInfoNames(); - DomItem propertyDefs() { return field(Fields::propertyDefs); } - DomItem bindings() { return field(Fields::bindings); } - DomItem methods() { return field(Fields::methods); } - DomItem enumerations() { return field(Fields::enumerations); } - DomItem children() { return field(Fields::children); } - DomItem child(index_type i) { return field(Fields::children).index(i); } - DomItem annotations() + DomItem get(const ErrorHandler &h = nullptr, QList<Path> *visitedRefs = nullptr) const; + QList<DomItem> getAll(const ErrorHandler &h = nullptr, QList<Path> *visitedRefs = nullptr) const; + bool isOwningItem() const { return domTypeIsOwningItem(internalKind()); } + bool isExternalItem() const { return domTypeIsExternalItem(internalKind()); } + bool isTopItem() const { return domTypeIsTopItem(internalKind()); } + bool isContainer() const { return domTypeIsContainer(internalKind()); } + bool isScope() const { return domTypeIsScope(internalKind()); } + bool isCanonicalChild(const DomItem &child) const; + bool hasAnnotations() const; + QString name() const { return field(Fields::name).value().toString(); } + DomItem pragmas() const { return field(Fields::pragmas); } + DomItem ids() const { return field(Fields::ids); } + QString idStr() const { return field(Fields::idStr).value().toString(); } + DomItem propertyInfos() const { return field(Fields::propertyInfos); } + PropertyInfo propertyInfoWithName(const QString &name) const; + QSet<QString> propertyInfoNames() const; + DomItem propertyDefs() const { return field(Fields::propertyDefs); } + DomItem bindings() const { return field(Fields::bindings); } + DomItem methods() const { return field(Fields::methods); } + DomItem enumerations() const { return field(Fields::enumerations); } + DomItem children() const { return field(Fields::children); } + DomItem child(index_type i) const { return field(Fields::children).index(i); } + DomItem annotations() const { if (hasAnnotations()) return field(Fields::annotations); @@ -783,200 +980,214 @@ public: return DomItem(); } - bool resolve(Path path, Visitor visitor, ErrorHandler errorHandler, - ResolveOptions options = ResolveOption::None, Path fullPath = Path(), - QList<Path> *visitedRefs = nullptr); + bool resolve(const Path &path, Visitor visitor, const ErrorHandler &errorHandler, + ResolveOptions options = ResolveOption::None, const Path &fullPath = Path(), + QList<Path> *visitedRefs = nullptr) const; - DomItem operator[](Path path); - DomItem operator[](QStringView component); - DomItem operator[](const QString &component); - DomItem operator[](const char16_t *component) + DomItem operator[](const Path &path) const; + DomItem operator[](QStringView component) const; + DomItem operator[](const QString &component) const; + DomItem operator[](const char16_t *component) const { return (*this)[QStringView(component)]; } // to avoid clash with stupid builtin ptrdiff_t[DomItem&], coming from C - DomItem operator[](index_type i) { return index(i); } - DomItem operator[](int i) { return index(i); } - index_type size() { return indexes() + keys().size(); } - index_type length() { return size(); } - - DomItem path(Path p, ErrorHandler h = &defaultErrorHandler); - DomItem path(QString p, ErrorHandler h = &defaultErrorHandler); - DomItem path(QStringView p, ErrorHandler h = &defaultErrorHandler); - - QList<QString> fields(); - DomItem field(QStringView name); - - index_type indexes(); - DomItem index(index_type); - bool visitIndexes(function_ref<bool(DomItem &)> visitor); - - QSet<QString> keys(); - QStringList sortedKeys(); - DomItem key(QString name); - DomItem key(QStringView name) { return key(name.toString()); } - bool visitKeys(function_ref<bool(QString, DomItem &)> visitor); - - QList<DomItem> values(); - void writeOutPre(OutWriter &lw); - void writeOut(OutWriter &lw); - void writeOutPost(OutWriter &lw); - DomItem writeOutForFile(OutWriter &ow, WriteOutChecks extraChecks); - DomItem writeOut(QString path, int nBackups = 2, - const LineWriterOptions &opt = LineWriterOptions(), FileWriter *fw = nullptr, - WriteOutChecks extraChecks = WriteOutCheck::Default); - - bool visitTree(Path basePath, ChildrenVisitor visitor, + DomItem operator[](index_type i) const { return index(i); } + DomItem operator[](int i) const { return index(i); } + index_type size() const { return indexes() + keys().size(); } + index_type length() const { return size(); } + + DomItem path(const Path &p, const ErrorHandler &h = &defaultErrorHandler) const; + DomItem path(const QString &p, const ErrorHandler &h = &defaultErrorHandler) const; + DomItem path(QStringView p, const ErrorHandler &h = &defaultErrorHandler) const; + + QList<QString> fields() const; + DomItem field(QStringView name) const; + + index_type indexes() const; + DomItem index(index_type) const; + bool visitIndexes(function_ref<bool(const DomItem &)> visitor) const; + + QSet<QString> keys() const; + QStringList sortedKeys() const; + DomItem key(const QString &name) const; + DomItem key(QStringView name) const { return key(name.toString()); } + bool visitKeys(function_ref<bool(const QString &, const DomItem &)> visitor) const; + + QList<DomItem> values() const; + void writeOutPre(OutWriter &lw) const; + void writeOut(OutWriter &lw) const; + void writeOutPost(OutWriter &lw) const; + bool writeOutForFile(OutWriter &ow, WriteOutChecks extraChecks) const; + bool writeOut(const QString &path, int nBackups = 2, + const LineWriterOptions &opt = LineWriterOptions(), FileWriter *fw = nullptr, + WriteOutChecks extraChecks = WriteOutCheck::Default) const; + + bool visitTree(const Path &basePath, ChildrenVisitor visitor, VisitOptions options = VisitOption::Default, ChildrenVisitor openingVisitor = emptyChildrenVisitor, - ChildrenVisitor closingVisitor = emptyChildrenVisitor); - bool visitPrototypeChain(function_ref<bool(DomItem &)> visitor, + ChildrenVisitor closingVisitor = emptyChildrenVisitor, + const FieldFilter &filter = FieldFilter::noFilter()) const; + bool visitPrototypeChain(function_ref<bool(const DomItem &)> visitor, VisitPrototypesOptions options = VisitPrototypesOption::Normal, - ErrorHandler h = nullptr, QSet<quintptr> *visited = nullptr, - QList<Path> *visitedRefs = nullptr); - bool visitDirectAccessibleScopes(function_ref<bool(DomItem &)> visitor, + const ErrorHandler &h = nullptr, QSet<quintptr> *visited = nullptr, + QList<Path> *visitedRefs = nullptr) const; + bool visitDirectAccessibleScopes(function_ref<bool(const DomItem &)> visitor, VisitPrototypesOptions options = VisitPrototypesOption::Normal, - ErrorHandler h = nullptr, QSet<quintptr> *visited = nullptr, - QList<Path> *visitedRefs = nullptr); + const ErrorHandler &h = nullptr, QSet<quintptr> *visited = nullptr, + QList<Path> *visitedRefs = nullptr) const; bool - visitStaticTypePrototypeChains(function_ref<bool(DomItem &)> visitor, + visitStaticTypePrototypeChains(function_ref<bool(const DomItem &)> visitor, VisitPrototypesOptions options = VisitPrototypesOption::Normal, - ErrorHandler h = nullptr, QSet<quintptr> *visited = nullptr, - QList<Path> *visitedRefs = nullptr); - bool visitScopeChain(function_ref<bool(DomItem &)> visitor, - LookupOptions = LookupOption::Normal, ErrorHandler h = nullptr, - QSet<quintptr> *visited = nullptr, QList<Path> *visitedRefs = nullptr); - bool visitLocalSymbolsNamed(QString name, function_ref<bool(DomItem &)> visitor); - QSet<QString> localSymbolNames(LocalSymbolsTypes lTypes = LocalSymbolsType::All); - bool visitLookup1(QString symbolName, function_ref<bool(DomItem &)> visitor, - LookupOptions = LookupOption::Normal, ErrorHandler h = nullptr, - QSet<quintptr> *visited = nullptr, QList<Path> *visitedRefs = nullptr); - bool visitLookup(QString symbolName, function_ref<bool(DomItem &)> visitor, - LookupType type = LookupType::Symbol, LookupOptions = LookupOption::Normal, - ErrorHandler errorHandler = nullptr, QSet<quintptr> *visited = nullptr, - QList<Path> *visitedRefs = nullptr); - bool visitSubSymbolsNamed(QString name, function_ref<bool(DomItem &)> visitor); - DomItem proceedToScope(ErrorHandler h = nullptr, QList<Path> *visitedRefs = nullptr); - QList<DomItem> lookup(QString symbolName, LookupType type = LookupType::Symbol, - LookupOptions = LookupOption::Normal, - ErrorHandler errorHandler = nullptr); - DomItem lookupFirst(QString symbolName, LookupType type = LookupType::Symbol, - LookupOptions = LookupOption::Normal, ErrorHandler errorHandler = nullptr); - - quintptr id(); - Path pathFromOwner(); - QString canonicalFilePath(); - DomItem fileLocationsTree(); - DomItem fileLocations(); - MutableDomItem makeCopy(CopyOption option = CopyOption::EnvConnected); - bool commitToBase(std::shared_ptr<DomEnvironment> validPtr = nullptr); - DomItem refreshed() { return top().path(canonicalPath()); } - QCborValue value(); - - void dumpPtr(Sink sink); - void dump(Sink, int indent = 0, - function_ref<bool(DomItem &, const PathEls::PathComponent &, DomItem &)> filter = - noFilter); + const ErrorHandler &h = nullptr, QSet<quintptr> *visited = nullptr, + QList<Path> *visitedRefs = nullptr) const; + + bool visitUp(function_ref<bool(const DomItem &)> visitor) const; + bool visitScopeChain( + function_ref<bool(const DomItem &)> visitor, LookupOptions = LookupOption::Normal, + const ErrorHandler &h = nullptr, QSet<quintptr> *visited = nullptr, + QList<Path> *visitedRefs = nullptr) const; + bool visitLocalSymbolsNamed( + const QString &name, function_ref<bool(const DomItem &)> visitor) const; + bool visitLookup1( + const QString &symbolName, function_ref<bool(const DomItem &)> visitor, + LookupOptions = LookupOption::Normal, const ErrorHandler &h = nullptr, + QSet<quintptr> *visited = nullptr, QList<Path> *visitedRefs = nullptr) const; + bool visitLookup( + const QString &symbolName, function_ref<bool(const DomItem &)> visitor, + LookupType type = LookupType::Symbol, LookupOptions = LookupOption::Normal, + const ErrorHandler &errorHandler = nullptr, QSet<quintptr> *visited = nullptr, + QList<Path> *visitedRefs = nullptr) const; + bool visitSubSymbolsNamed( + const QString &name, function_ref<bool(const DomItem &)> visitor) const; + DomItem proceedToScope( + const ErrorHandler &h = nullptr, QList<Path> *visitedRefs = nullptr) const; + QList<DomItem> lookup( + const QString &symbolName, LookupType type = LookupType::Symbol, + LookupOptions = LookupOption::Normal, const ErrorHandler &errorHandler = nullptr) const; + DomItem lookupFirst( + const QString &symbolName, LookupType type = LookupType::Symbol, + LookupOptions = LookupOption::Normal, const ErrorHandler &errorHandler = nullptr) const; + + quintptr id() const; + Path pathFromOwner() const; + QString canonicalFilePath() const; + DomItem fileLocationsTree() const; + DomItem fileLocations() const; + MutableDomItem makeCopy(CopyOption option = CopyOption::EnvConnected) const; + bool commitToBase(const std::shared_ptr<DomEnvironment> &validPtr = nullptr) const; + DomItem refreshed() const { return top().path(canonicalPath()); } + QCborValue value() const; + + void dumpPtr(const Sink &sink) const; + void dump(const Sink &, int indent = 0, + function_ref<bool(const DomItem &, const PathEls::PathComponent &, const DomItem &)> filter = + noFilter) const; FileWriter::Status - dump(QString path, - function_ref<bool(DomItem &, const PathEls::PathComponent &, DomItem &)> filter = noFilter, - int nBackups = 2, int indent = 0, FileWriter *fw = nullptr); - QString toString(); - QString toString() const - { - DomItem self = *this; - return self.toString(); - } + dump(const QString &path, + function_ref<bool(const DomItem &, const PathEls::PathComponent &, const DomItem &)> filter = noFilter, + int nBackups = 2, int indent = 0, FileWriter *fw = nullptr) const; + QString toString() const; // OwnigItem elements - int derivedFrom(); - int revision(); - QDateTime createdAt(); - QDateTime frozenAt(); - QDateTime lastDataUpdateAt(); + int derivedFrom() const; + int revision() const; + QDateTime createdAt() const; + QDateTime frozenAt() const; + QDateTime lastDataUpdateAt() const; - void addError(ErrorMessage msg); - ErrorHandler errorHandler(); - void clearErrors(ErrorGroups groups = ErrorGroups({}), bool iterate = true); + void addError(ErrorMessage &&msg) const; + ErrorHandler errorHandler() const; + void clearErrors(const ErrorGroups &groups = ErrorGroups({}), bool iterate = true) const; // return false if a quick exit was requested - bool iterateErrors(function_ref<bool(DomItem source, ErrorMessage msg)> visitor, bool iterate, - Path inPath = Path()); + bool iterateErrors( + function_ref<bool (const DomItem &, const ErrorMessage &)> visitor, bool iterate, + Path inPath = Path()) const; - bool iterateSubOwners(function_ref<bool(DomItem &owner)> visitor); - bool iterateDirectSubpaths(DirectVisitor v); + bool iterateSubOwners(function_ref<bool(const DomItem &owner)> visitor) const; + bool iterateDirectSubpaths(DirectVisitor v) const; template<typename T> - DomItem subDataItem(const PathEls::PathComponent &c, T value, - ConstantData::Options options = ConstantData::Options::MapIsMap); + DomItem subDataItem(const PathEls::PathComponent &c, const T &value, + ConstantData::Options options = ConstantData::Options::MapIsMap) const; template<typename T> - DomItem subDataItemField(QStringView f, T value, - ConstantData::Options options = ConstantData::Options::MapIsMap) + DomItem subDataItemField(QStringView f, const T &value, + ConstantData::Options options = ConstantData::Options::MapIsMap) const { return subDataItem(PathEls::Field(f), value, options); } template<typename T> - DomItem subValueItem(const PathEls::PathComponent &c, T value, - ConstantData::Options options = ConstantData::Options::MapIsMap); + DomItem subValueItem(const PathEls::PathComponent &c, const T &value, + ConstantData::Options options = ConstantData::Options::MapIsMap) const; template<typename T> - bool dvValue(DirectVisitor visitor, const PathEls::PathComponent &c, T value, - ConstantData::Options options = ConstantData::Options::MapIsMap); + bool dvValue(DirectVisitor visitor, const PathEls::PathComponent &c, const T &value, + ConstantData::Options options = ConstantData::Options::MapIsMap) const; template<typename T> - bool dvValueField(DirectVisitor visitor, QStringView f, T value, - ConstantData::Options options = ConstantData::Options::MapIsMap) + bool dvValueField(DirectVisitor visitor, QStringView f, const T &value, + ConstantData::Options options = ConstantData::Options::MapIsMap) const { - return this->dvValue<T>(visitor, PathEls::Field(f), value, options); + return this->dvValue<T>(std::move(visitor), PathEls::Field(f), value, options); } template<typename F> bool dvValueLazy(DirectVisitor visitor, const PathEls::PathComponent &c, F valueF, - ConstantData::Options options = ConstantData::Options::MapIsMap); + ConstantData::Options options = ConstantData::Options::MapIsMap) const; template<typename F> bool dvValueLazyField(DirectVisitor visitor, QStringView f, F valueF, - ConstantData::Options options = ConstantData::Options::MapIsMap) + ConstantData::Options options = ConstantData::Options::MapIsMap) const { - return this->dvValueLazy(visitor, PathEls::Field(f), valueF, options); + return this->dvValueLazy(std::move(visitor), PathEls::Field(f), valueF, options); } - DomItem subLocationItem(const PathEls::PathComponent &c, SourceLocation loc, - QStringView code = QStringView()) + DomItem subLocationItem(const PathEls::PathComponent &c, SourceLocation loc) const { - return this->subDataItem(c, locationToData(loc, code)); + return this->subDataItem(c, sourceLocationToQCborValue(loc)); } // bool dvSubReference(DirectVisitor visitor, const PathEls::PathComponent &c, Path // referencedObject); - DomItem subReferencesItem(const PathEls::PathComponent &c, QList<Path> paths); - DomItem subReferenceItem(const PathEls::PathComponent &c, Path referencedObject); - bool dvReference(DirectVisitor visitor, const PathEls::PathComponent &c, Path referencedObject) + DomItem subReferencesItem(const PathEls::PathComponent &c, const QList<Path> &paths) const; + DomItem subReferenceItem(const PathEls::PathComponent &c, const Path &referencedObject) const; + bool dvReference(DirectVisitor visitor, const PathEls::PathComponent &c, const Path &referencedObject) const { - return dvItem(visitor, c, [c, this, referencedObject]() { + return dvItem(std::move(visitor), c, [c, this, referencedObject]() { return this->subReferenceItem(c, referencedObject); }); } - bool dvReferences(DirectVisitor visitor, const PathEls::PathComponent &c, QList<Path> paths) + bool dvReferences( + DirectVisitor visitor, const PathEls::PathComponent &c, const QList<Path> &paths) const { - return dvItem(visitor, c, [c, this, paths]() { return this->subReferencesItem(c, paths); }); + return dvItem(std::move(visitor), c, [c, this, paths]() { + return this->subReferencesItem(c, paths); + }); } - bool dvReferenceField(DirectVisitor visitor, QStringView f, Path referencedObject) + bool dvReferenceField(DirectVisitor visitor, QStringView f, const Path &referencedObject) const { - return dvReference(visitor, PathEls::Field(f), referencedObject); + return dvReference(std::move(visitor), PathEls::Field(f), referencedObject); } - bool dvReferencesField(DirectVisitor visitor, QStringView f, QList<Path> paths) + bool dvReferencesField(DirectVisitor visitor, QStringView f, const QList<Path> &paths) const { - return dvReferences(visitor, PathEls::Field(f), paths); + return dvReferences(std::move(visitor), PathEls::Field(f), paths); } - bool dvItem(DirectVisitor visitor, const PathEls::PathComponent &c, function_ref<DomItem()> it) + bool dvItem(DirectVisitor visitor, const PathEls::PathComponent &c, function_ref<DomItem()> it) const { return visitor(c, it); } - bool dvItemField(DirectVisitor visitor, QStringView f, function_ref<DomItem()> it) + bool dvItemField(DirectVisitor visitor, QStringView f, function_ref<DomItem()> it) const { - return dvItem(visitor, PathEls::Field(f), it); + return dvItem(std::move(visitor), PathEls::Field(f), it); } - DomItem subListItem(const List &list); - DomItem subMapItem(const Map &map); - DomItem subObjectWrapItem(SimpleObjectWrap obj) + DomItem subListItem(const List &list) const; + DomItem subMapItem(const Map &map) const; + DomItem subObjectWrapItem(SimpleObjectWrap obj) const { return DomItem(m_top, m_owner, m_ownerPath, obj); } + + DomItem subScriptElementWrapperItem(const ScriptElementVariant &obj) const + { + Q_ASSERT(obj); + return DomItem(m_top, m_owner, m_ownerPath, ScriptElementDomWrapper(obj)); + } + template<typename Owner> - DomItem subOwnerItem(const PathEls::PathComponent &c, Owner o) + DomItem subOwnerItem(const PathEls::PathComponent &c, Owner o) const { if constexpr (domTypeIsUnattachedOwningItem(Owner::element_type::kindValue)) return DomItem(m_top, o, canonicalPath().appendComponent(c), o.get()); @@ -984,46 +1195,35 @@ public: return DomItem(m_top, o, Path(), o.get()); } template<typename T> - DomItem wrap(const PathEls::PathComponent &c, T &obj); + DomItem wrap(const PathEls::PathComponent &c, const T &obj) const; template<typename T> - DomItem wrapField(QStringView f, T &obj) + DomItem wrapField(QStringView f, const T &obj) const { return wrap<T>(PathEls::Field(f), obj); } template<typename T> - bool dvWrap(DirectVisitor visitor, const PathEls::PathComponent &c, T &obj); + bool dvWrap(DirectVisitor visitor, const PathEls::PathComponent &c, T &obj) const; template<typename T> - bool dvWrapField(DirectVisitor visitor, QStringView f, T &obj) + bool dvWrapField(DirectVisitor visitor, QStringView f, T &obj) const { - return dvWrap<T>(visitor, PathEls::Field(f), obj); + return dvWrap<T>(std::move(visitor), PathEls::Field(f), obj); } DomItem() = default; - DomItem(std::shared_ptr<DomEnvironment>); - DomItem(std::shared_ptr<DomUniverse>); - - static DomItem fromCode(QString code, DomType fileType = DomType::QmlFile); - void loadFile(QString filePath, QString logicalPath, - std::function<void(Path, DomItem &, DomItem &)> callback, LoadOptions loadOptions, - std::optional<DomType> fileType = std::optional<DomType>()); - void loadFile(QString canonicalFilePath, QString logicalPath, QString code, QDateTime codeDate, - std::function<void(Path, DomItem &, DomItem &)> callback, LoadOptions loadOptions, - std::optional<DomType> fileType = std::optional<DomType>()); - void loadModuleDependency(QString uri, Version v, - std::function<void(Path, DomItem &, DomItem &)> callback = nullptr, - ErrorHandler = nullptr); - void loadBuiltins(std::function<void(Path, DomItem &, DomItem &)> callback = nullptr, - ErrorHandler = nullptr); - void loadPendingDependencies(); + DomItem(const std::shared_ptr<DomEnvironment> &); + DomItem(const std::shared_ptr<DomUniverse> &); + + // TODO move to DomEnvironment? + static DomItem fromCode(const QString &code, DomType fileType = DomType::QmlFile); // --- start of potentially dangerous stuff, make private? --- - std::shared_ptr<DomTop> topPtr(); - std::shared_ptr<OwningItem> owningItemPtr(); + std::shared_ptr<DomTop> topPtr() const; + std::shared_ptr<OwningItem> owningItemPtr() const; // keep the DomItem around to ensure that it doesn't get deleted template<typename T, typename std::enable_if<std::is_base_of_v<DomBase, T>, bool>::type = true> - T const *as() + T const *as() const { if (m_kind == T::kindValue) { if constexpr (domTypeIsObjWrap(T::kindValue) || domTypeIsValueWrap(T::kindValue)) @@ -1035,7 +1235,7 @@ public: } template<typename T, typename std::enable_if<!std::is_base_of_v<DomBase, T>, bool>::type = true> - T const *as() + T const *as() const { if (m_kind == T::kindValue) { Q_ASSERT(domTypeIsObjWrap(m_kind) || domTypeIsValueWrap(m_kind)); @@ -1045,67 +1245,54 @@ public: } template<typename T> - std::shared_ptr<T> ownerAs(); + std::shared_ptr<T> ownerAs() const; template<typename Owner, typename T> - DomItem copy(Owner owner, Path ownerPath, T base) + DomItem copy(const Owner &owner, const Path &ownerPath, const T &base) const { - Q_ASSERT(m_top); + Q_ASSERT(!std::holds_alternative<std::monostate>(m_top)); static_assert(IsInlineDom<std::decay_t<T>>::value, "Expected an inline item or pointer"); return DomItem(m_top, owner, ownerPath, base); } template<typename Owner> - DomItem copy(Owner owner, Path ownerPath) + DomItem copy(const Owner &owner, const Path &ownerPath) const { - Q_ASSERT(m_top); + Q_ASSERT(!std::holds_alternative<std::monostate>(m_top)); return DomItem(m_top, owner, ownerPath, owner.get()); } template<typename T> - DomItem copy(T base) + DomItem copy(const T &base) const { - Q_ASSERT(m_top); + Q_ASSERT(!std::holds_alternative<std::monostate>(m_top)); using BaseT = std::decay_t<T>; static_assert(!std::is_same_v<BaseT, ElementT>, "variant not supported, pass in the stored types"); - static_assert(IsInlineDom<BaseT>::value, "expected either a pointer or an inline item"); - if constexpr (IsSharedPointerToDomObject<BaseT>::value) { + static_assert(IsInlineDom<BaseT>::value || std::is_same_v<BaseT, std::monostate>, + "expected either a pointer or an inline item"); + + if constexpr (IsSharedPointerToDomObject<BaseT>::value) return DomItem(m_top, base, Path(), base.get()); - } else { + else if constexpr (IsInlineDom<BaseT>::value) return DomItem(m_top, m_owner, m_ownerPath, base); - } + + Q_UNREACHABLE_RETURN(DomItem(m_top, m_owner, m_ownerPath, nullptr)); } private: - DomBase const *base(); - template <typename T, typename std::enable_if<std::is_base_of<DomBase, T>::value, bool>::type = true> - T *mutableAs() { - if (m_kind == T::kindValue) { - if constexpr (domTypeIsObjWrap(T::kindValue) || domTypeIsValueWrap(T::kindValue)) - return static_cast<SimpleObjectWrapBase *>(mutableBase())->mutableAs<T>(); - else - return static_cast<T *>(mutableBase()); - } - return nullptr; - } + enum class WriteOutCheckResult { Success, Failed }; + WriteOutCheckResult performWriteOutChecks(const DomItem &, const DomItem &, OutWriter &, WriteOutChecks) const; + const DomBase *base() const; - template <typename T, typename std::enable_if<!std::is_base_of<DomBase, T>::value, bool>::type = true> - T *mutableAs() { - if (m_kind == T::kindValue) { - Q_ASSERT(domTypeIsObjWrap(m_kind) || domTypeIsValueWrap(m_kind)); - return static_cast<SimpleObjectWrapBase *>(mutableBase())->mutableAs<T>(); - } - return nullptr; - } - DomBase *mutableBase(); template<typename Env, typename Owner> DomItem(Env, Owner, Path, std::nullptr_t) : DomItem() { } + template<typename Env, typename Owner, typename T, typename = std::enable_if_t<IsInlineDom<std::decay_t<T>>::value>> - DomItem(Env env, Owner owner, Path ownerPath, T el) + DomItem(Env env, Owner owner, const Path &ownerPath, const T &el) : m_top(env), m_owner(owner), m_ownerPath(ownerPath), m_element(el) { using BaseT = std::decay_t<T>; @@ -1113,8 +1300,8 @@ private: if (!el || el->kind() == DomType::Empty) { // avoid null ptr, and allow only a // single kind of Empty m_kind = DomType::Empty; - m_top.reset(); - m_owner.reset(); + m_top = std::monostate(); + m_owner = std::monostate(); m_ownerPath = Path(); m_element = Empty(); } else { @@ -1144,8 +1331,8 @@ private: friend class TestDomItem; friend QMLDOM_EXPORT bool operator==(const DomItem &, const DomItem &); DomType m_kind = DomType::Empty; - std::optional<TopT> m_top; - std::optional<OwnerT> m_owner; + TopT m_top; + OwnerT m_owner; Path m_ownerPath; ElementT m_element = Empty(); }; @@ -1158,123 +1345,179 @@ inline bool operator!=(const DomItem &o1, const DomItem &o2) } template<typename T> -Map Map::fromMultiMapRef(Path pathFromOwner, QMultiMap<QString, T> &mmap) +static DomItem keyMultiMapHelper(const DomItem &self, const QString &key, + const QMultiMap<QString, T> &mmap) +{ + auto it = mmap.find(key); + auto end = mmap.cend(); + if (it == end) + return DomItem(); + else { + // special case single element (++it == end || it.key() != key)? + QList<const T *> values; + while (it != end && it.key() == key) + values.append(&(*it++)); + ListP ll(self.pathFromOwner().appendComponent(PathEls::Key(key)), values, QString(), + ListOptions::Reverse); + return self.copy(ll); + } +} + +template<typename T> +Map Map::fromMultiMapRef(const Path &pathFromOwner, const QMultiMap<QString, T> &mmap) { return Map( pathFromOwner, - [&mmap](DomItem &self, QString key) { - auto it = mmap.find(key); - auto end = mmap.cend(); - if (it == end) - return DomItem(); - else { - // special case single element (++it == end || it.key() != key)? - QList<T *> values; - while (it != end && it.key() == key) - values.append(&(*it++)); - ListP ll(self.pathFromOwner().appendComponent(PathEls::Key(key)), values, - QString(), ListOptions::Reverse); - return self.copy(ll); - } + [&mmap](const DomItem &self, const QString &key) { + return keyMultiMapHelper(self, key, mmap); }, - [&mmap](DomItem &) { return QSet<QString>(mmap.keyBegin(), mmap.keyEnd()); }, + [&mmap](const DomItem &) { return QSet<QString>(mmap.keyBegin(), mmap.keyEnd()); }, QLatin1String(typeid(T).name())); } template<typename T> Map Map::fromMapRef( - Path pathFromOwner, QMap<QString, T> &map, - std::function<DomItem(DomItem &, const PathEls::PathComponent &, T &)> elWrapper) + const Path &pathFromOwner, const QMap<QString, T> &map, + const std::function<DomItem(const DomItem &, const PathEls::PathComponent &, const T &)> &elWrapper) { return Map( pathFromOwner, - [&map, elWrapper](DomItem &self, QString key) { - if (!map.contains(key)) + [&map, elWrapper](const DomItem &self, const QString &key) { + const auto it = map.constFind(key); + if (it == map.constEnd()) return DomItem(); - else { - return elWrapper(self, PathEls::Key(key), map[key]); - } + return elWrapper(self, PathEls::Key(key), it.value()); }, - [&map](DomItem &) { return QSet<QString>(map.keyBegin(), map.keyEnd()); }, + [&map](const DomItem &) { return QSet<QString>(map.keyBegin(), map.keyEnd()); }, QLatin1String(typeid(T).name())); } +template<typename MapT> +QSet<QString> Map::fileRegionKeysFromMap(const MapT &map) +{ + QSet<QString> keys; + std::transform(map.keyBegin(), map.keyEnd(), std::inserter(keys, keys.begin()), fileLocationRegionName); + return keys; +} + +template<typename T> +Map Map::fromFileRegionMap(const Path &pathFromOwner, const QMap<FileLocationRegion, T> &map) +{ + auto result = Map( + pathFromOwner, + [&map](const DomItem &mapItem, const QString &key) -> DomItem { + auto it = map.constFind(fileLocationRegionValue(key)); + if (it == map.constEnd()) + return {}; + + return mapItem.wrap(PathEls::Key(key), *it); + }, + [&map](const DomItem &) { return fileRegionKeysFromMap(map); }, + QString::fromLatin1(typeid(T).name())); + return result; +} + +template<typename T> +Map Map::fromFileRegionListMap(const Path &pathFromOwner, + const QMap<FileLocationRegion, QList<T>> &map) +{ + using namespace Qt::StringLiterals; + auto result = Map( + pathFromOwner, + [&map](const DomItem &mapItem, const QString &key) -> DomItem { + const QList<SourceLocation> locations = map.value(fileLocationRegionValue(key)); + if (locations.empty()) + return {}; + + auto list = List::fromQList<SourceLocation>( + mapItem.pathFromOwner(), locations, + [](const DomItem &self, const PathEls::PathComponent &path, + const SourceLocation &location) { + return self.subLocationItem(path, location); + }); + return mapItem.subListItem(list); + }, + [&map](const DomItem &) { return fileRegionKeysFromMap(map); }, + u"QList<%1>"_s.arg(QString::fromLatin1(typeid(T).name()))); + return result; +} + template<typename T> List List::fromQList( - Path pathFromOwner, QList<T> list, - std::function<DomItem(DomItem &, const PathEls::PathComponent &, T &)> elWrapper, + const Path &pathFromOwner, const QList<T> &list, + const std::function<DomItem(const DomItem &, const PathEls::PathComponent &, const T &)> &elWrapper, ListOptions options) { index_type len = list.size(); if (options == ListOptions::Reverse) { return List( pathFromOwner, - [list, elWrapper](DomItem &self, index_type i) mutable { + [list, elWrapper](const DomItem &self, index_type i) mutable { if (i < 0 || i >= list.size()) return DomItem(); return elWrapper(self, PathEls::Index(i), list[list.size() - i - 1]); }, - [len](DomItem &) { return len; }, nullptr, QLatin1String(typeid(T).name())); + [len](const DomItem &) { return len; }, nullptr, QLatin1String(typeid(T).name())); } else { return List( pathFromOwner, - [list, elWrapper](DomItem &self, index_type i) mutable { + [list, elWrapper](const DomItem &self, index_type i) mutable { if (i < 0 || i >= list.size()) return DomItem(); return elWrapper(self, PathEls::Index(i), list[i]); }, - [len](DomItem &) { return len; }, nullptr, QLatin1String(typeid(T).name())); + [len](const DomItem &) { return len; }, nullptr, QLatin1String(typeid(T).name())); } } template<typename T> List List::fromQListRef( - Path pathFromOwner, QList<T> &list, - std::function<DomItem(DomItem &, const PathEls::PathComponent &, T &)> elWrapper, + const Path &pathFromOwner, const QList<T> &list, + const std::function<DomItem(const DomItem &, const PathEls::PathComponent &, const T &)> &elWrapper, ListOptions options) { if (options == ListOptions::Reverse) { return List( pathFromOwner, - [&list, elWrapper](DomItem &self, index_type i) { + [&list, elWrapper](const DomItem &self, index_type i) { if (i < 0 || i >= list.size()) return DomItem(); return elWrapper(self, PathEls::Index(i), list[list.size() - i - 1]); }, - [&list](DomItem &) { return list.size(); }, nullptr, + [&list](const DomItem &) { return list.size(); }, nullptr, QLatin1String(typeid(T).name())); } else { return List( pathFromOwner, - [&list, elWrapper](DomItem &self, index_type i) { + [&list, elWrapper](const DomItem &self, index_type i) { if (i < 0 || i >= list.size()) return DomItem(); return elWrapper(self, PathEls::Index(i), list[i]); }, - [&list](DomItem &) { return list.size(); }, nullptr, + [&list](const DomItem &) { return list.size(); }, nullptr, QLatin1String(typeid(T).name())); } } class QMLDOM_EXPORT OwningItem: public DomBase { protected: - virtual std::shared_ptr<OwningItem> doCopy(DomItem &self) const = 0; + virtual std::shared_ptr<OwningItem> doCopy(const DomItem &self) const = 0; public: OwningItem(const OwningItem &o); OwningItem(int derivedFrom=0); - OwningItem(int derivedFrom, QDateTime lastDataUpdateAt); + OwningItem(int derivedFrom, const QDateTime &lastDataUpdateAt); OwningItem(const OwningItem &&) = delete; OwningItem &operator=(const OwningItem &&) = delete; static int nextRevision(); - Path canonicalPath(DomItem &self) const override = 0; + Path canonicalPath(const DomItem &self) const override = 0; - bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override; - std::shared_ptr<OwningItem> makeCopy(DomItem &self) const { return doCopy(self); } + bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override; + std::shared_ptr<OwningItem> makeCopy(const DomItem &self) const { return doCopy(self); } Path pathFromOwner() const { return Path(); } - Path pathFromOwner(DomItem &) const override final { return Path(); } - DomItem containingObject(DomItem &self) const override; + Path pathFromOwner(const DomItem &) const override final { return Path(); } + DomItem containingObject(const DomItem &self) const override; int derivedFrom() const; virtual int revision() const; @@ -1287,18 +1530,20 @@ public: virtual bool freeze(); QDateTime frozenAt() const; - virtual void addError(DomItem &self, ErrorMessage msg); - void addErrorLocal(ErrorMessage msg); - void clearErrors(ErrorGroups groups = ErrorGroups({})); + virtual void addError(const DomItem &self, ErrorMessage &&msg); + void addErrorLocal(ErrorMessage &&msg); + void clearErrors(const ErrorGroups &groups = ErrorGroups({})); // return false if a quick exit was requested - bool iterateErrors(DomItem &self, function_ref<bool(DomItem source, ErrorMessage msg)> visitor, - Path inPath = Path()); + bool iterateErrors( + const DomItem &self, + function_ref<bool(const DomItem &source, const ErrorMessage &msg)> visitor, + const Path &inPath = Path()); QMultiMap<Path, ErrorMessage> localErrors() const { QMutexLocker l(mutex()); return m_errors; } - virtual bool iterateSubOwners(DomItem &self, function_ref<bool(DomItem &owner)> visitor); + virtual bool iterateSubOwners(const DomItem &self, function_ref<bool(const DomItem &owner)> visitor); QBasicMutex *mutex() const { return &m_mutex; } private: @@ -1313,25 +1558,25 @@ private: }; template<typename T> -std::shared_ptr<T> DomItem::ownerAs() +std::shared_ptr<T> DomItem::ownerAs() const { if constexpr (domTypeIsOwningItem(T::kindValue)) { - if (m_owner) { + if (!std::holds_alternative<std::monostate>(m_owner)) { if constexpr (T::kindValue == DomType::AttachedInfo) { - if (std::holds_alternative<std::shared_ptr<AttachedInfo>>(*m_owner)) + if (std::holds_alternative<std::shared_ptr<AttachedInfo>>(m_owner)) return std::static_pointer_cast<T>( - std::get<std::shared_ptr<AttachedInfo>>(*m_owner)); + std::get<std::shared_ptr<AttachedInfo>>(m_owner)); } else if constexpr (T::kindValue == DomType::ExternalItemInfo) { - if (std::holds_alternative<std::shared_ptr<ExternalItemInfoBase>>(*m_owner)) + if (std::holds_alternative<std::shared_ptr<ExternalItemInfoBase>>(m_owner)) return std::static_pointer_cast<T>( - std::get<std::shared_ptr<ExternalItemInfoBase>>(*m_owner)); + std::get<std::shared_ptr<ExternalItemInfoBase>>(m_owner)); } else if constexpr (T::kindValue == DomType::ExternalItemPair) { - if (std::holds_alternative<std::shared_ptr<ExternalItemPairBase>>(*m_owner)) + if (std::holds_alternative<std::shared_ptr<ExternalItemPairBase>>(m_owner)) return std::static_pointer_cast<T>( - std::get<std::shared_ptr<ExternalItemPairBase>>(*m_owner)); + std::get<std::shared_ptr<ExternalItemPairBase>>(m_owner)); } else { - if (std::holds_alternative<std::shared_ptr<T>>(*m_owner)) { - return std::get<std::shared_ptr<T>>(*m_owner); + if (std::holds_alternative<std::shared_ptr<T>>(m_owner)) { + return std::get<std::shared_ptr<T>>(m_owner); } } } @@ -1352,26 +1597,26 @@ struct rank<0> }; template<typename T> -auto writeOutWrap(const T &t, DomItem &self, OutWriter &lw, rank<1>) +auto writeOutWrap(const T &t, const DomItem &self, OutWriter &lw, rank<1>) -> decltype(t.writeOut(self, lw)) { t.writeOut(self, lw); } template<typename T> -auto writeOutWrap(const T &, DomItem &, OutWriter &, rank<0>) -> void +auto writeOutWrap(const T &, const DomItem &, OutWriter &, rank<0>) -> void { qCWarning(writeOutLog) << "Ignoring writeout to wrapped object not supporting it (" << typeid(T).name(); } template<typename T> -auto writeOutWrap(const T &t, DomItem &self, OutWriter &lw) -> void +auto writeOutWrap(const T &t, const DomItem &self, OutWriter &lw) -> void { writeOutWrap(t, self, lw, rank<1>()); } template<typename T> -void SimpleObjectWrapT<T>::writeOut(DomItem &self, OutWriter &lw) const +void SimpleObjectWrapT<T>::writeOut(const DomItem &self, OutWriter &lw) const { writeOutWrap<T>(*asT(), self, lw); } @@ -1390,7 +1635,7 @@ public: QString internalKindStr() { return domTypeToString(internalKind()); } DomKind domKind() { return kind2domKind(internalKind()); } - Path canonicalPath() { return m_owner.canonicalPath().path(m_pathFromOwner); } + Path canonicalPath() const { return m_owner.canonicalPath().path(m_pathFromOwner); } MutableDomItem containingObject() { if (m_pathFromOwner) @@ -1458,28 +1703,27 @@ public: MutableDomItem index(index_type i) { return MutableDomItem(item().index(i)); } QSet<QString> const keys() { return item().keys(); } - MutableDomItem key(QString name) { return MutableDomItem(item().key(name)); } + MutableDomItem key(const QString &name) { return MutableDomItem(item().key(name)); } MutableDomItem key(QStringView name) { return key(name.toString()); } void - dump(Sink s, int indent = 0, - function_ref<bool(DomItem &, const PathEls::PathComponent &, DomItem &)> filter = noFilter) + dump(const Sink &s, int indent = 0, + function_ref<bool(const DomItem &, const PathEls::PathComponent &, const DomItem &)> filter = noFilter) { item().dump(s, indent, filter); } FileWriter::Status - dump(QString path, - function_ref<bool(DomItem &, const PathEls::PathComponent &, DomItem &)> filter = noFilter, + dump(const QString &path, + function_ref<bool(const DomItem &, const PathEls::PathComponent &, const DomItem &)> filter = noFilter, int nBackups = 2, int indent = 0, FileWriter *fw = nullptr) { return item().dump(path, filter, nBackups, indent, fw); } void writeOut(OutWriter &lw) { return item().writeOut(lw); } - MutableDomItem writeOut(QString path, int nBackups = 2, - const LineWriterOptions &opt = LineWriterOptions(), - FileWriter *fw = nullptr) + bool writeOut(const QString &path, int nBackups = 2, + const LineWriterOptions &opt = LineWriterOptions(), FileWriter *fw = nullptr) { - return MutableDomItem(item().writeOut(path, nBackups, opt, fw)); + return item().writeOut(path, nBackups, opt, fw); } MutableDomItem fileLocations() { return MutableDomItem(item().fileLocations()); } @@ -1487,11 +1731,11 @@ public: { return item().makeCopy(option); } - bool commitToBase(std::shared_ptr<DomEnvironment> validEnvPtr = nullptr) + bool commitToBase(const std::shared_ptr<DomEnvironment> &validEnvPtr = nullptr) { return item().commitToBase(validEnvPtr); } - QString canonicalFilePath() { return item().canonicalFilePath(); } + QString canonicalFilePath() const { return item().canonicalFilePath(); } MutableDomItem refreshed() { return MutableDomItem(item().refreshed()); } @@ -1518,41 +1762,36 @@ public: QDateTime frozenAt() { return m_owner.frozenAt(); } QDateTime lastDataUpdateAt() { return m_owner.lastDataUpdateAt(); } - void addError(ErrorMessage msg) { item().addError(msg); } + void addError(ErrorMessage &&msg) { item().addError(std::move(msg)); } ErrorHandler errorHandler(); // convenience setters - MutableDomItem addPrototypePath(Path prototypePath); - MutableDomItem setNextScopePath(Path nextScopePath); + MutableDomItem addPrototypePath(const Path &prototypePath); + MutableDomItem setNextScopePath(const Path &nextScopePath); MutableDomItem setPropertyDefs(QMultiMap<QString, PropertyDefinition> propertyDefs); MutableDomItem setBindings(QMultiMap<QString, Binding> bindings); MutableDomItem setMethods(QMultiMap<QString, MethodInfo> functionDefs); - MutableDomItem setChildren(QList<QmlObject> children); - MutableDomItem setAnnotations(QList<QmlObject> annotations); - MutableDomItem setScript(std::shared_ptr<ScriptExpression> exp); - MutableDomItem setCode(QString code); - MutableDomItem addPropertyDef(PropertyDefinition propertyDef, + MutableDomItem setChildren(const QList<QmlObject> &children); + MutableDomItem setAnnotations(const QList<QmlObject> &annotations); + MutableDomItem setScript(const std::shared_ptr<ScriptExpression> &exp); + MutableDomItem setCode(const QString &code); + MutableDomItem addPropertyDef(const PropertyDefinition &propertyDef, AddOption option = AddOption::Overwrite); MutableDomItem addBinding(Binding binding, AddOption option = AddOption::Overwrite); - MutableDomItem addMethod(MethodInfo functionDef, AddOption option = AddOption::Overwrite); + MutableDomItem addMethod( + const MethodInfo &functionDef, AddOption option = AddOption::Overwrite); MutableDomItem addChild(QmlObject child); MutableDomItem addAnnotation(QmlObject child); - MutableDomItem addPreComment(const Comment &comment, QString regionName = QString()); - MutableDomItem addPreComment(const Comment &comment, QStringView regionName) - { - return addPreComment(comment, regionName.toString()); - } - MutableDomItem addPostComment(const Comment &comment, QString regionName = QString()); - MutableDomItem addPostComment(const Comment &comment, QStringView regionName) - { - return addPostComment(comment, regionName.toString()); - } + MutableDomItem addPreComment(const Comment &comment, FileLocationRegion region); + MutableDomItem addPostComment(const Comment &comment, FileLocationRegion region); + QQmlJSScope::ConstPtr semanticScope(); + void setSemanticScope(const QQmlJSScope::ConstPtr &scope); MutableDomItem() = default; - MutableDomItem(DomItem owner, Path pathFromOwner): + MutableDomItem(const DomItem &owner, const Path &pathFromOwner): m_owner(owner), m_pathFromOwner(pathFromOwner) {} - MutableDomItem(DomItem item): + MutableDomItem(const DomItem &item): m_owner(item.owner()), m_pathFromOwner(item.pathFromOwner()) {} @@ -1568,18 +1807,32 @@ public: template <typename T> T *mutableAs() { Q_ASSERT(!m_owner || !m_owner.owningItemPtr()->frozen()); - return item().mutableAs<T>(); + + DomItem self = item(); + if (self.m_kind != T::kindValue) + return nullptr; + + const T *t = nullptr; + if constexpr (domTypeIsObjWrap(T::kindValue) || domTypeIsValueWrap(T::kindValue)) + t = static_cast<const SimpleObjectWrapBase *>(self.base())->as<T>(); + else if constexpr (std::is_base_of<DomBase, T>::value) + t = static_cast<const T *>(self.base()); + else + Q_UNREACHABLE_RETURN(nullptr); + + // Nasty. But since ElementT has to store the const pointers, we allow it in this one place. + return const_cast<T *>(t); } template<typename T> - std::shared_ptr<T> ownerAs() + std::shared_ptr<T> ownerAs() const { return m_owner.ownerAs<T>(); } // it is dangerous to assume it stays valid when updates are preformed... - DomItem item() { return m_owner.path(m_pathFromOwner); } + DomItem item() const { return m_owner.path(m_pathFromOwner); } - friend bool operator==(const MutableDomItem o1, const MutableDomItem &o2) + friend bool operator==(const MutableDomItem &o1, const MutableDomItem &o2) { return o1.m_owner == o2.m_owner && o1.m_pathFromOwner == o2.m_pathFromOwner; } @@ -1596,7 +1849,7 @@ private: QMLDOM_EXPORT QDebug operator<<(QDebug debug, const MutableDomItem &c); template<typename K, typename T> -Path insertUpdatableElementInMultiMap(Path mapPathFromOwner, QMultiMap<K, T> &mmap, K key, +Path insertUpdatableElementInMultiMap(const Path &mapPathFromOwner, QMultiMap<K, T> &mmap, K key, const T &value, AddOption option = AddOption::KeepExisting, T **valuePtr = nullptr) { @@ -1633,7 +1886,7 @@ Path insertUpdatableElementInMultiMap(Path mapPathFromOwner, QMultiMap<K, T> &mm } template<typename T> -Path appendUpdatableElementInQList(Path listPathFromOwner, QList<T> &list, const T &value, +Path appendUpdatableElementInQList(const Path &listPathFromOwner, QList<T> &list, const T &value, T **vPtr = nullptr) { int idx = list.size(); @@ -1647,7 +1900,7 @@ Path appendUpdatableElementInQList(Path listPathFromOwner, QList<T> &list, const } template <typename T, typename K = QString> -void updatePathFromOwnerMultiMap(QMultiMap<K, T> &mmap, Path newPath) +void updatePathFromOwnerMultiMap(QMultiMap<K, T> &mmap, const Path &newPath) { auto it = mmap.begin(); auto end = mmap.end(); @@ -1676,7 +1929,7 @@ void updatePathFromOwnerMultiMap(QMultiMap<K, T> &mmap, Path newPath) } template <typename T> -void updatePathFromOwnerQList(QList<T> &list, Path newPath) +void updatePathFromOwnerQList(QList<T> &list, const Path &newPath) { auto it = list.begin(); auto end = list.end(); @@ -1788,9 +2041,14 @@ constexpr bool domTypeIsUnattachedOwningItem(DomType k) } } +constexpr bool domTypeIsScriptElement(DomType k) +{ + return DomType::ScriptElementStart <= k && k <= DomType::ScriptElementStop; +} + template<typename T> -DomItem DomItem::subValueItem(const PathEls::PathComponent &c, T value, - ConstantData::Options options) +DomItem DomItem::subValueItem(const PathEls::PathComponent &c, const T &value, + ConstantData::Options options) const { using BaseT = std::remove_cv_t<std::remove_reference_t<T>>; if constexpr ( @@ -1805,8 +2063,8 @@ DomItem DomItem::subValueItem(const PathEls::PathComponent &c, T value, } else if constexpr (IsList<T>::value && !std::is_convertible_v<BaseT, QStringView>) { return subListItem(List::fromQList<typename BaseT::value_type>( pathFromOwner().appendComponent(c), value, - [options](DomItem &list, const PathEls::PathComponent &p, - typename T::value_type &v) { return list.subValueItem(p, v, options); })); + [options](const DomItem &list, const PathEls::PathComponent &p, + const typename T::value_type &v) { return list.subValueItem(p, v, options); })); } else if constexpr (IsSharedPointerToDomObject<BaseT>::value) { Q_UNUSED(options); return subOwnerItem(c, value); @@ -1816,8 +2074,8 @@ DomItem DomItem::subValueItem(const PathEls::PathComponent &c, T value, } template<typename T> -DomItem DomItem::subDataItem(const PathEls::PathComponent &c, T value, - ConstantData::Options options) +DomItem DomItem::subDataItem(const PathEls::PathComponent &c, const T &value, + ConstantData::Options options) const { using BaseT = std::remove_cv_t<std::remove_reference_t<T>>; if constexpr (std::is_same_v<BaseT, ConstantData>) { @@ -1833,8 +2091,8 @@ DomItem DomItem::subDataItem(const PathEls::PathComponent &c, T value, } template<typename T> -bool DomItem::dvValue(DirectVisitor visitor, const PathEls::PathComponent &c, T value, - ConstantData::Options options) +bool DomItem::dvValue(DirectVisitor visitor, const PathEls::PathComponent &c, const T &value, + ConstantData::Options options) const { auto lazyWrap = [this, &c, &value, options]() { return this->subValueItem<T>(c, value, options); @@ -1844,7 +2102,7 @@ bool DomItem::dvValue(DirectVisitor visitor, const PathEls::PathComponent &c, T template<typename F> bool DomItem::dvValueLazy(DirectVisitor visitor, const PathEls::PathComponent &c, F valueF, - ConstantData::Options options) + ConstantData::Options options) const { auto lazyWrap = [this, &c, &valueF, options]() { return this->subValueItem<decltype(valueF())>(c, valueF(), options); @@ -1853,7 +2111,7 @@ bool DomItem::dvValueLazy(DirectVisitor visitor, const PathEls::PathComponent &c } template<typename T> -DomItem DomItem::wrap(const PathEls::PathComponent &c, T &obj) +DomItem DomItem::wrap(const PathEls::PathComponent &c, const T &obj) const { using BaseT = std::decay_t<T>; if constexpr (std::is_same_v<QString, BaseT> || std::is_arithmetic_v<BaseT>) { @@ -1904,8 +2162,8 @@ DomItem DomItem::wrap(const PathEls::PathComponent &c, T &obj) if constexpr (std::is_same_v<typename BaseT::key_type, QString>) { return subMapItem(Map::fromMapRef<typename BaseT::mapped_type>( pathFromOwner().appendComponent(c), obj, - [](DomItem &map, const PathEls::PathComponent &p, - typename BaseT::mapped_type &el) { return map.wrap(p, el); })); + [](const DomItem &map, const PathEls::PathComponent &p, + const typename BaseT::mapped_type &el) { return map.wrap(p, el); })); } else { Q_ASSERT_X(false, "DomItem::wrap", "non string keys not supported (try .toString()?)"); } @@ -1913,8 +2171,8 @@ DomItem DomItem::wrap(const PathEls::PathComponent &c, T &obj) if constexpr (IsDomObject<typename BaseT::value_type>::value) { return subListItem(List::fromQListRef<typename BaseT::value_type>( pathFromOwner().appendComponent(c), obj, - [](DomItem &list, const PathEls::PathComponent &p, - typename BaseT::value_type &el) { return list.wrap(p, el); })); + [](const DomItem &list, const PathEls::PathComponent &p, + const typename BaseT::value_type &el) { return list.wrap(p, el); })); } else { Q_ASSERT_X(false, "DomItem::wrap", "Unsupported list type T"); return DomItem(); @@ -1927,14 +2185,14 @@ DomItem DomItem::wrap(const PathEls::PathComponent &c, T &obj) } template<typename T> -bool DomItem::dvWrap(DirectVisitor visitor, const PathEls::PathComponent &c, T &obj) +bool DomItem::dvWrap(DirectVisitor visitor, const PathEls::PathComponent &c, T &obj) const { auto lazyWrap = [this, &c, &obj]() { return this->wrap<T>(c, obj); }; return visitor(c, lazyWrap); } template<typename T> -bool ListPT<T>::iterateDirectSubpaths(DomItem &self, DirectVisitor v) +bool ListPT<T>::iterateDirectSubpaths(const DomItem &self, DirectVisitor v) const { index_type len = index_type(m_pList.size()); for (index_type i = 0; i < len; ++i) { @@ -1945,10 +2203,10 @@ bool ListPT<T>::iterateDirectSubpaths(DomItem &self, DirectVisitor v) } template<typename T> -DomItem ListPT<T>::index(DomItem &self, index_type index) const +DomItem ListPT<T>::index(const DomItem &self, index_type index) const { if (index >= 0 && index < m_pList.size()) - return self.wrap(PathEls::Index(index), *reinterpret_cast<T *>(m_pList.value(index))); + return self.wrap(PathEls::Index(index), *static_cast<const T *>(m_pList.value(index))); return DomItem(); } @@ -1958,13 +2216,13 @@ inline DomKind DomBase::domKind() const return kind2domKind(kind()); } -inline bool DomBase::iterateDirectSubpathsConst(DomItem &self, DirectVisitor visitor) const +inline bool DomBase::iterateDirectSubpathsConst(const DomItem &self, DirectVisitor visitor) const { Q_ASSERT(self.base() == this); - return self.iterateDirectSubpaths(visitor); + return self.iterateDirectSubpaths(std::move(visitor)); } -inline DomItem DomBase::containingObject(DomItem &self) const +inline DomItem DomBase::containingObject(const DomItem &self) const { Path path = pathFromOwner(self); DomItem base = self.owner(); @@ -1986,7 +2244,7 @@ inline QString DomBase::typeName() const return domTypeToString(kind()); } -inline QList<QString> DomBase::fields(DomItem &self) const +inline QList<QString> DomBase::fields(const DomItem &self) const { QList<QString> res; self.iterateDirectSubpaths([&res](const PathEls::PathComponent &c, function_ref<DomItem()>) { @@ -1997,7 +2255,7 @@ inline QList<QString> DomBase::fields(DomItem &self) const return res; } -inline DomItem DomBase::field(DomItem &self, QStringView name) const +inline DomItem DomBase::field(const DomItem &self, QStringView name) const { DomItem res; self.iterateDirectSubpaths( @@ -2011,7 +2269,7 @@ inline DomItem DomBase::field(DomItem &self, QStringView name) const return res; } -inline index_type DomBase::indexes(DomItem &self) const +inline index_type DomBase::indexes(const DomItem &self) const { index_type res = 0; self.iterateDirectSubpaths([&res](const PathEls::PathComponent &c, function_ref<DomItem()>) { @@ -2025,7 +2283,7 @@ inline index_type DomBase::indexes(DomItem &self) const return res; } -inline DomItem DomBase::index(DomItem &self, qint64 index) const +inline DomItem DomBase::index(const DomItem &self, qint64 index) const { DomItem res; self.iterateDirectSubpaths( @@ -2039,7 +2297,7 @@ inline DomItem DomBase::index(DomItem &self, qint64 index) const return res; } -inline QSet<QString> const DomBase::keys(DomItem &self) const +inline QSet<QString> const DomBase::keys(const DomItem &self) const { QSet<QString> res; self.iterateDirectSubpaths([&res](const PathEls::PathComponent &c, function_ref<DomItem()>) { @@ -2050,7 +2308,7 @@ inline QSet<QString> const DomBase::keys(DomItem &self) const return res; } -inline DomItem DomBase::key(DomItem &self, QString name) const +inline DomItem DomBase::key(const DomItem &self, const QString &name) const { DomItem res; self.iterateDirectSubpaths( @@ -2064,12 +2322,12 @@ inline DomItem DomBase::key(DomItem &self, QString name) const return res; } -inline DomItem DomItem::subListItem(const List &list) +inline DomItem DomItem::subListItem(const List &list) const { return DomItem(m_top, m_owner, m_ownerPath, list); } -inline DomItem DomItem::subMapItem(const Map &map) +inline DomItem DomItem::subMapItem(const Map &map) const { return DomItem(m_top, m_owner, m_ownerPath, map); } |