| 1 | // Copyright (C) 2021 The Qt Company Ltd. | 
|---|
| 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only | 
|---|
| 3 |  | 
|---|
| 4 | #ifndef QMLDOMATTACHEDINFO_P_H | 
|---|
| 5 | #define QMLDOMATTACHEDINFO_P_H | 
|---|
| 6 |  | 
|---|
| 7 | // | 
|---|
| 8 | //  W A R N I N G | 
|---|
| 9 | //  ------------- | 
|---|
| 10 | // | 
|---|
| 11 | // This file is not part of the Qt API.  It exists purely as an | 
|---|
| 12 | // implementation detail.  This header file may change from version to | 
|---|
| 13 | // version without notice, or even be removed. | 
|---|
| 14 | // | 
|---|
| 15 | // We mean it. | 
|---|
| 16 | // | 
|---|
| 17 |  | 
|---|
| 18 | #include "qqmldom_global.h" | 
|---|
| 19 | #include "qqmldomitem_p.h" | 
|---|
| 20 |  | 
|---|
| 21 | #include <memory> | 
|---|
| 22 | #include <optional> | 
|---|
| 23 |  | 
|---|
| 24 | QT_BEGIN_NAMESPACE | 
|---|
| 25 |  | 
|---|
| 26 | namespace QQmlJS { | 
|---|
| 27 | namespace Dom { | 
|---|
| 28 | struct AttachedInfoLookupResultBase | 
|---|
| 29 | { | 
|---|
| 30 | Path lookupPath; | 
|---|
| 31 | Path rootTreePath; | 
|---|
| 32 | Path foundTreePath; | 
|---|
| 33 | }; | 
|---|
| 34 | template<typename TreePtr> | 
|---|
| 35 | class AttachedInfoLookupResult: public AttachedInfoLookupResultBase | 
|---|
| 36 | { | 
|---|
| 37 | public: | 
|---|
| 38 | TreePtr foundTree; | 
|---|
| 39 |  | 
|---|
| 40 | operator bool() { return bool(foundTree); } | 
|---|
| 41 | template<typename T> | 
|---|
| 42 | AttachedInfoLookupResult<std::shared_ptr<T>> as() const | 
|---|
| 43 | { | 
|---|
| 44 | AttachedInfoLookupResult<std::shared_ptr<T>> res; | 
|---|
| 45 | res.AttachedInfoLookupResultBase::operator=(*this); | 
|---|
| 46 | res.foundTree = std::static_pointer_cast<T>(foundTree); | 
|---|
| 47 | return res; | 
|---|
| 48 | } | 
|---|
| 49 | }; | 
|---|
| 50 |  | 
|---|
| 51 | class QMLDOM_EXPORT AttachedInfo : public OwningItem  { | 
|---|
| 52 | Q_GADGET | 
|---|
| 53 | public: | 
|---|
| 54 | enum class PathType { | 
|---|
| 55 | Relative, | 
|---|
| 56 | Canonical | 
|---|
| 57 | }; | 
|---|
| 58 | Q_ENUM(PathType) | 
|---|
| 59 |  | 
|---|
| 60 | constexpr static DomType kindValue = DomType::AttachedInfo; | 
|---|
| 61 | using Ptr = std::shared_ptr<AttachedInfo>; | 
|---|
| 62 |  | 
|---|
| 63 | DomType kind() const override { return kindValue; } | 
|---|
| 64 | Path canonicalPath(const DomItem &self) const override { return self.m_ownerPath; } | 
|---|
| 65 | bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override; | 
|---|
| 66 |  | 
|---|
| 67 | AttachedInfo::Ptr makeCopy(const DomItem &self) const | 
|---|
| 68 | { | 
|---|
| 69 | return std::static_pointer_cast<AttachedInfo>(r: doCopy(self)); | 
|---|
| 70 | } | 
|---|
| 71 |  | 
|---|
| 72 | Ptr parent() const { return m_parent.lock(); } | 
|---|
| 73 | Path path() const { return m_path; } | 
|---|
| 74 | void setPath(const Path &p) { m_path = p; } | 
|---|
| 75 |  | 
|---|
| 76 | AttachedInfo(const Ptr &parent = nullptr, const Path &p = Path()) | 
|---|
| 77 | : m_path(p), m_parent(parent) | 
|---|
| 78 | {} | 
|---|
| 79 |  | 
|---|
| 80 | AttachedInfo(const AttachedInfo &o); | 
|---|
| 81 |  | 
|---|
| 82 | static Ptr ensure(const Ptr &self, const Path &path, PathType pType = PathType::Relative); | 
|---|
| 83 | static Ptr find(const Ptr &self, const Path &p, PathType pType = PathType::Relative); | 
|---|
| 84 | static AttachedInfoLookupResult<Ptr> findAttachedInfo(const DomItem &item, | 
|---|
| 85 | QStringView treeFieldName); | 
|---|
| 86 | static Ptr treePtr(const DomItem &item, QStringView fieldName) | 
|---|
| 87 | { | 
|---|
| 88 | return findAttachedInfo(item, treeFieldName: fieldName).foundTree; | 
|---|
| 89 | } | 
|---|
| 90 |  | 
|---|
| 91 | DomItem itemAtPath(const DomItem &self, const Path &p, PathType pType = PathType::Relative) const | 
|---|
| 92 | { | 
|---|
| 93 | if (Ptr resPtr = find(self: self.ownerAs<AttachedInfo>(), p, pType)) { | 
|---|
| 94 | const Path relative = (pType == PathType::Canonical) ? p.mid(offset: m_path.length()) : p; | 
|---|
| 95 | Path resPath = self.canonicalPath(); | 
|---|
| 96 | for (const Path &pEl : relative) { | 
|---|
| 97 | resPath = resPath.field(name: Fields::subItems).key(name: pEl.toString()); | 
|---|
| 98 | } | 
|---|
| 99 | return self.copy(owner: resPtr, ownerPath: resPath); | 
|---|
| 100 | } | 
|---|
| 101 | return DomItem(); | 
|---|
| 102 | } | 
|---|
| 103 |  | 
|---|
| 104 | DomItem infoAtPath(const DomItem &self, const Path &p, PathType pType = PathType::Relative) const | 
|---|
| 105 | { | 
|---|
| 106 | return itemAtPath(self, p, pType).field(name: Fields::infoItem); | 
|---|
| 107 | } | 
|---|
| 108 |  | 
|---|
| 109 | MutableDomItem ensureItemAtPath(MutableDomItem &self, const Path &p, | 
|---|
| 110 | PathType pType = PathType::Relative) | 
|---|
| 111 | { | 
|---|
| 112 | if (Ptr resPtr = ensure(self: self.ownerAs<AttachedInfo>(), path: p, pType)) { | 
|---|
| 113 | const Path relative = (pType == PathType::Canonical) ? p.mid(offset: m_path.length()) : p; | 
|---|
| 114 | Path resPath = self.canonicalPath(); | 
|---|
| 115 | for (const Path &pEl : relative) { | 
|---|
| 116 | resPath = resPath.field(name: Fields::subItems).key(name: pEl.toString()); | 
|---|
| 117 | } | 
|---|
| 118 | return MutableDomItem(self.item().copy(owner: resPtr, ownerPath: resPath)); | 
|---|
| 119 | } | 
|---|
| 120 | return MutableDomItem(); | 
|---|
| 121 | } | 
|---|
| 122 |  | 
|---|
| 123 | MutableDomItem ensureInfoAtPath(MutableDomItem &self, const Path &p, | 
|---|
| 124 | PathType pType = PathType::Relative) | 
|---|
| 125 | { | 
|---|
| 126 | return ensureItemAtPath(self, p, pType).field(name: Fields::infoItem); | 
|---|
| 127 | } | 
|---|
| 128 |  | 
|---|
| 129 | virtual AttachedInfo::Ptr instantiate( | 
|---|
| 130 | const AttachedInfo::Ptr &parent, const Path &p = Path()) const = 0; | 
|---|
| 131 | virtual DomItem infoItem(const DomItem &self) const = 0; | 
|---|
| 132 | QMap<Path, Ptr> subItems() const { | 
|---|
| 133 | return m_subItems; | 
|---|
| 134 | } | 
|---|
| 135 | void setSubItems(QMap<Path, Ptr> v) { | 
|---|
| 136 | m_subItems = v; | 
|---|
| 137 | } | 
|---|
| 138 | protected: | 
|---|
| 139 | Path m_path; | 
|---|
| 140 | std::weak_ptr<AttachedInfo> m_parent; | 
|---|
| 141 | QMap<Path, Ptr> m_subItems; | 
|---|
| 142 | }; | 
|---|
| 143 |  | 
|---|
| 144 | template<typename Info> | 
|---|
| 145 | class QMLDOM_EXPORT AttachedInfoT final : public AttachedInfo | 
|---|
| 146 | { | 
|---|
| 147 | public: | 
|---|
| 148 | constexpr static DomType kindValue = DomType::AttachedInfo; | 
|---|
| 149 | using Ptr = std::shared_ptr<AttachedInfoT>; | 
|---|
| 150 | using InfoType = Info; | 
|---|
| 151 |  | 
|---|
| 152 | AttachedInfoT(const Ptr &parent = nullptr, const Path &p = Path()) : AttachedInfo(parent, p) {} | 
|---|
| 153 | AttachedInfoT(const AttachedInfoT &o): | 
|---|
| 154 | AttachedInfo(o), | 
|---|
| 155 | m_info(o.m_info) | 
|---|
| 156 | { | 
|---|
| 157 | auto end = o.m_subItems.end(); | 
|---|
| 158 | auto i = o.m_subItems.begin(); | 
|---|
| 159 | while (i != end) { | 
|---|
| 160 | m_subItems.insert(i.key(), Ptr( | 
|---|
| 161 | new AttachedInfoT(*std::static_pointer_cast<AttachedInfoT>(i.value()).get()))); | 
|---|
| 162 | } | 
|---|
| 163 | } | 
|---|
| 164 |  | 
|---|
| 165 | static Ptr createTree(const Path &p = Path()) { | 
|---|
| 166 | return Ptr(new AttachedInfoT(nullptr, p)); | 
|---|
| 167 | } | 
|---|
| 168 |  | 
|---|
| 169 | static Ptr ensure(const Ptr &self, const Path &path, PathType pType = PathType::Relative) | 
|---|
| 170 | { | 
|---|
| 171 | return std::static_pointer_cast<AttachedInfoT>(AttachedInfo::ensure(self, path, pType)); | 
|---|
| 172 | } | 
|---|
| 173 |  | 
|---|
| 174 | static Ptr find(const Ptr &self, const Path &p, PathType pType = PathType::Relative) | 
|---|
| 175 | { | 
|---|
| 176 | return std::static_pointer_cast<AttachedInfoT>(AttachedInfo::find(self, p, pType)); | 
|---|
| 177 | } | 
|---|
| 178 |  | 
|---|
| 179 | static AttachedInfoLookupResult<Ptr> findAttachedInfo(const DomItem &item, | 
|---|
| 180 | QStringView fieldName) | 
|---|
| 181 | { | 
|---|
| 182 | return AttachedInfo::findAttachedInfo(item, treeFieldName: fieldName).template as<AttachedInfoT>(); | 
|---|
| 183 | } | 
|---|
| 184 | static Ptr treePtr(const DomItem &item, QStringView fieldName) | 
|---|
| 185 | { | 
|---|
| 186 | return std::static_pointer_cast<AttachedInfoT>(AttachedInfo::treePtr(item, fieldName)); | 
|---|
| 187 | } | 
|---|
| 188 | static bool visitTree( | 
|---|
| 189 | const Ptr &base, function_ref<bool(const Path &, const Ptr &)> visitor, | 
|---|
| 190 | const Path &basePath = Path()) { | 
|---|
| 191 | if (base) { | 
|---|
| 192 | Path pNow = basePath.path(toAdd: base->path()); | 
|---|
| 193 | if (visitor(pNow, base)) { | 
|---|
| 194 | auto it = base->m_subItems.cbegin(); | 
|---|
| 195 | auto end = base->m_subItems.cend(); | 
|---|
| 196 | while (it != end) { | 
|---|
| 197 | if (!visitTree(base: std::static_pointer_cast<AttachedInfoT>(it.value()), visitor, basePath: pNow)) | 
|---|
| 198 | return false; | 
|---|
| 199 | ++it; | 
|---|
| 200 | } | 
|---|
| 201 | } else { | 
|---|
| 202 | return false; | 
|---|
| 203 | } | 
|---|
| 204 | } | 
|---|
| 205 | return true; | 
|---|
| 206 | } | 
|---|
| 207 |  | 
|---|
| 208 | AttachedInfo::Ptr instantiate( | 
|---|
| 209 | const AttachedInfo::Ptr &parent, const Path &p = Path()) const override | 
|---|
| 210 | { | 
|---|
| 211 | return Ptr(new AttachedInfoT(std::static_pointer_cast<AttachedInfoT>(parent), p)); | 
|---|
| 212 | } | 
|---|
| 213 |  | 
|---|
| 214 | DomItem infoItem(const DomItem &self) const override { return self.wrapField(Fields::infoItem, m_info); } | 
|---|
| 215 |  | 
|---|
| 216 | Ptr makeCopy(const DomItem &self) const | 
|---|
| 217 | { | 
|---|
| 218 | return std::static_pointer_cast<AttachedInfoT>(doCopy(self)); | 
|---|
| 219 | } | 
|---|
| 220 |  | 
|---|
| 221 | Ptr parent() const { return std::static_pointer_cast<AttachedInfoT>(AttachedInfo::parent()); } | 
|---|
| 222 |  | 
|---|
| 223 | const Info &info() const { return m_info; } | 
|---|
| 224 | Info &info() { return m_info; } | 
|---|
| 225 |  | 
|---|
| 226 | QString canonicalPathForTesting() const | 
|---|
| 227 | { | 
|---|
| 228 | QString result; | 
|---|
| 229 | for (auto *it = this; it; it = it->parent().get()) { | 
|---|
| 230 | result.prepend(it->path().toString()); | 
|---|
| 231 | } | 
|---|
| 232 | return result; | 
|---|
| 233 | } | 
|---|
| 234 |  | 
|---|
| 235 | protected: | 
|---|
| 236 | std::shared_ptr<OwningItem> doCopy(const DomItem &) const override | 
|---|
| 237 | { | 
|---|
| 238 | return Ptr(new AttachedInfoT(*this)); | 
|---|
| 239 | } | 
|---|
| 240 |  | 
|---|
| 241 | private: | 
|---|
| 242 | Info m_info; | 
|---|
| 243 | }; | 
|---|
| 244 |  | 
|---|
| 245 | class QMLDOM_EXPORT FileLocations { | 
|---|
| 246 | public: | 
|---|
| 247 | using Tree = std::shared_ptr<AttachedInfoT<FileLocations>>; | 
|---|
| 248 | constexpr static DomType kindValue = DomType::FileLocations; | 
|---|
| 249 | DomType kind() const {  return kindValue; } | 
|---|
| 250 | bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const; | 
|---|
| 251 |  | 
|---|
| 252 | static Tree createTree(const Path &basePath); | 
|---|
| 253 | static Tree ensure(const Tree &base, const Path &basePath, | 
|---|
| 254 | AttachedInfo::PathType pType = AttachedInfo::PathType::Relative); | 
|---|
| 255 | static Tree find(const Tree &self, const Path &p, | 
|---|
| 256 | AttachedInfo::PathType pType = AttachedInfo::PathType::Relative) | 
|---|
| 257 | { | 
|---|
| 258 | return AttachedInfoT<FileLocations>::find(self, p, pType); | 
|---|
| 259 | } | 
|---|
| 260 |  | 
|---|
| 261 | // returns the path looked up and the found tree when looking for the info attached to item | 
|---|
| 262 | static AttachedInfoLookupResult<Tree> findAttachedInfo(const DomItem &item); | 
|---|
| 263 | static FileLocations::Tree treeOf(const DomItem &); | 
|---|
| 264 | static const FileLocations *fileLocationsOf(const DomItem &); | 
|---|
| 265 |  | 
|---|
| 266 | static void updateFullLocation(const Tree &fLoc, SourceLocation loc); | 
|---|
| 267 | static void addRegion(const Tree &fLoc, FileLocationRegion region, SourceLocation loc); | 
|---|
| 268 | static QQmlJS::SourceLocation region(const Tree &fLoc, FileLocationRegion region); | 
|---|
| 269 |  | 
|---|
| 270 | private: | 
|---|
| 271 | static QMetaEnum regionEnum; | 
|---|
| 272 |  | 
|---|
| 273 | public: | 
|---|
| 274 | SourceLocation fullRegion; | 
|---|
| 275 | QMap<FileLocationRegion, SourceLocation> regions; | 
|---|
| 276 | QMap<FileLocationRegion, QList<SourceLocation>> ; | 
|---|
| 277 | QMap<FileLocationRegion, QList<SourceLocation>> ; | 
|---|
| 278 | }; | 
|---|
| 279 |  | 
|---|
| 280 | class QMLDOM_EXPORT UpdatedScriptExpression | 
|---|
| 281 | { | 
|---|
| 282 | Q_GADGET | 
|---|
| 283 | public: | 
|---|
| 284 | using Tree = std::shared_ptr<AttachedInfoT<UpdatedScriptExpression>>; | 
|---|
| 285 | constexpr static DomType kindValue = DomType::UpdatedScriptExpression; | 
|---|
| 286 | DomType kind() const { return kindValue; } | 
|---|
| 287 | bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const; | 
|---|
| 288 |  | 
|---|
| 289 | static Tree createTree(const Path &basePath); | 
|---|
| 290 | static Tree ensure(const Tree &base, const Path &basePath, AttachedInfo::PathType pType); | 
|---|
| 291 |  | 
|---|
| 292 | // returns the path looked up and the found tree when looking for the info attached to item | 
|---|
| 293 | static AttachedInfoLookupResult<Tree> | 
|---|
| 294 | findAttachedInfo(const DomItem &item); | 
|---|
| 295 | // convenience: find FileLocations::Tree attached to the given item | 
|---|
| 296 | static Tree treePtr(const DomItem &); | 
|---|
| 297 | // convenience: find FileLocations* attached to the given item (if there is one) | 
|---|
| 298 | static const UpdatedScriptExpression *exprPtr(const DomItem &); | 
|---|
| 299 |  | 
|---|
| 300 | static bool visitTree( | 
|---|
| 301 | const Tree &base, function_ref<bool(const Path &, const Tree &)> visitor, | 
|---|
| 302 | const Path &basePath = Path()); | 
|---|
| 303 |  | 
|---|
| 304 | std::shared_ptr<ScriptExpression> expr; | 
|---|
| 305 | }; | 
|---|
| 306 |  | 
|---|
| 307 | } // end namespace Dom | 
|---|
| 308 | } // end namespace QQmlJS | 
|---|
| 309 |  | 
|---|
| 310 | QT_END_NAMESPACE | 
|---|
| 311 | #endif // QMLDOMATTACHEDINFO_P_H | 
|---|
| 312 |  | 
|---|