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 | template<typename TreePtr> |
29 | class AttachedInfoLookupResult |
30 | { |
31 | public: |
32 | TreePtr foundTree; |
33 | Path lookupPath; // relative path used to reach result |
34 | std::optional<Path> rootTreePath; // path of the root TreePath |
35 | std::optional<Path> foundTreePath; |
36 | operator bool() { return bool(foundTree); } |
37 | template<typename T> |
38 | AttachedInfoLookupResult<std::shared_ptr<T>> as() const |
39 | { |
40 | AttachedInfoLookupResult<std::shared_ptr<T>> res; |
41 | res.foundTree = std::static_pointer_cast<T>(foundTree); |
42 | res.lookupPath = lookupPath; |
43 | res.rootTreePath = rootTreePath; |
44 | return res; |
45 | } |
46 | }; |
47 | |
48 | class QMLDOM_EXPORT AttachedInfo : public OwningItem { |
49 | Q_GADGET |
50 | public: |
51 | enum class PathType { |
52 | Relative, |
53 | Canonical |
54 | }; |
55 | Q_ENUM(PathType) |
56 | enum class FindOption { |
57 | None = 0, |
58 | SetRootTreePath = 0x1, |
59 | SetFoundTreePath = 0x2, |
60 | Default = 0x3 |
61 | }; |
62 | Q_DECLARE_FLAGS(FindOptions, FindOption) |
63 | Q_FLAG(FindOptions) |
64 | |
65 | constexpr static DomType kindValue = DomType::AttachedInfo; |
66 | using Ptr = std::shared_ptr<AttachedInfo>; |
67 | |
68 | DomType kind() const override { return kindValue; } |
69 | Path canonicalPath(DomItem &self) const override { return self.m_ownerPath; } |
70 | bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) override; |
71 | |
72 | AttachedInfo::Ptr makeCopy(DomItem &self) const |
73 | { |
74 | return std::static_pointer_cast<AttachedInfo>(r: doCopy(self)); |
75 | } |
76 | |
77 | Ptr parent() const { return m_parent.lock(); } |
78 | Path path() const { return m_path; } |
79 | void setPath(Path p) { m_path = p; } |
80 | |
81 | AttachedInfo(Ptr parent = nullptr, Path p = Path()) : m_path(p), m_parent(parent) {} |
82 | AttachedInfo(const AttachedInfo &o); |
83 | |
84 | static Ptr ensure(Ptr self, Path path, PathType pType = PathType::Relative); |
85 | static Ptr find(Ptr self, Path p, PathType pType = PathType::Relative); |
86 | static AttachedInfoLookupResult<Ptr> |
87 | findAttachedInfo(DomItem &item, QStringView treeFieldName, |
88 | FindOptions options = AttachedInfo::FindOption::None); |
89 | static Ptr treePtr(DomItem &item, QStringView fieldName) |
90 | { |
91 | return findAttachedInfo(item, treeFieldName: fieldName, options: FindOption::None).foundTree; |
92 | } |
93 | |
94 | DomItem itemAtPath(DomItem &self, Path p, PathType pType = PathType::Relative) const |
95 | { |
96 | if (Ptr resPtr = find(self: self.ownerAs<AttachedInfo>(), p, pType)) { |
97 | if (pType == PathType::Canonical) |
98 | p = p.mid(offset: m_path.length()); |
99 | Path resPath = self.canonicalPath(); |
100 | for (Path pEl : p) { |
101 | resPath = resPath.field(name: Fields::subItems).key(name: pEl.toString()); |
102 | } |
103 | return self.copy(owner: resPtr, ownerPath: resPath); |
104 | } |
105 | return DomItem(); |
106 | } |
107 | |
108 | DomItem infoAtPath(DomItem &self, Path p, PathType pType = PathType::Relative) const |
109 | { |
110 | return itemAtPath(self, p, pType).field(name: Fields::infoItem); |
111 | } |
112 | |
113 | MutableDomItem ensureItemAtPath(MutableDomItem &self, Path p, |
114 | PathType pType = PathType::Relative) |
115 | { |
116 | if (Ptr resPtr = ensure(self: self.ownerAs<AttachedInfo>(), path: p, pType)) { |
117 | if (pType == PathType::Canonical) |
118 | p = p.mid(offset: m_path.length()); |
119 | Path resPath = self.canonicalPath(); |
120 | for (Path pEl : p) { |
121 | resPath = resPath.field(name: Fields::subItems).key(name: pEl.toString()); |
122 | } |
123 | return MutableDomItem(self.item().copy(owner: resPtr, ownerPath: resPath)); |
124 | } |
125 | return MutableDomItem(); |
126 | } |
127 | |
128 | MutableDomItem ensureInfoAtPath(MutableDomItem &self, Path p, |
129 | PathType pType = PathType::Relative) |
130 | { |
131 | return ensureItemAtPath(self, p, pType).field(name: Fields::infoItem); |
132 | } |
133 | |
134 | virtual AttachedInfo::Ptr instantiate(AttachedInfo::Ptr parent, Path p = Path()) const = 0; |
135 | virtual DomItem infoItem(DomItem &self) = 0; |
136 | DomItem infoItem(DomItem &self) const |
137 | { |
138 | return const_cast<AttachedInfo *>(this)->infoItem(self); |
139 | } |
140 | QMap<Path, Ptr> subItems() const { |
141 | return m_subItems; |
142 | } |
143 | void setSubItems(QMap<Path, Ptr> v) { |
144 | m_subItems = v; |
145 | } |
146 | protected: |
147 | Path m_path; |
148 | std::weak_ptr<AttachedInfo> m_parent; |
149 | QMap<Path, Ptr> m_subItems; |
150 | }; |
151 | Q_DECLARE_OPERATORS_FOR_FLAGS(AttachedInfo::FindOptions) |
152 | |
153 | template<typename Info> |
154 | class QMLDOM_EXPORT AttachedInfoT final : public AttachedInfo |
155 | { |
156 | public: |
157 | constexpr static DomType kindValue = DomType::AttachedInfo; |
158 | using Ptr = std::shared_ptr<AttachedInfoT>; |
159 | using InfoType = Info; |
160 | |
161 | AttachedInfoT(Ptr parent = nullptr, Path p = Path()) : AttachedInfo(parent, p) {} |
162 | AttachedInfoT(const AttachedInfoT &o): |
163 | AttachedInfo(o), |
164 | m_info(o.m_info) |
165 | { |
166 | auto end = o.m_subItems.end(); |
167 | auto i = o.m_subItems.begin(); |
168 | while (i != end) { |
169 | m_subItems.insert(i.key(), Ptr( |
170 | new AttachedInfoT(*std::static_pointer_cast<AttachedInfoT>(i.value()).get()))); |
171 | } |
172 | } |
173 | |
174 | static Ptr createTree(Path p = Path()) { |
175 | return Ptr(new AttachedInfoT(nullptr, p)); |
176 | } |
177 | |
178 | static Ptr ensure(Ptr self, Path path, PathType pType = PathType::Relative){ |
179 | return std::static_pointer_cast<AttachedInfoT>(AttachedInfo::ensure(self, path, pType)); |
180 | } |
181 | |
182 | static Ptr find(Ptr self, Path p, PathType pType = PathType::Relative){ |
183 | return std::static_pointer_cast<AttachedInfoT>(AttachedInfo::find(self, p, pType)); |
184 | } |
185 | |
186 | static AttachedInfoLookupResult<Ptr> findAttachedInfo(DomItem &item, QStringView fieldName, |
187 | AttachedInfo::FindOptions options) |
188 | { |
189 | return AttachedInfo::findAttachedInfo(item, treeFieldName: fieldName, options) |
190 | .template as<AttachedInfoT>(); |
191 | } |
192 | static Ptr treePtr(DomItem &item, QStringView fieldName) |
193 | { |
194 | return std::static_pointer_cast<AttachedInfoT>(AttachedInfo::treePtr(item, fieldName)); |
195 | } |
196 | static bool visitTree(Ptr base, function_ref<bool(Path, Ptr)>visitor, Path basePath = Path()) { |
197 | if (base) { |
198 | Path pNow = basePath.path(toAdd: base->path()); |
199 | if (visitor(pNow, base)) { |
200 | auto it = base->m_subItems.cbegin(); |
201 | auto end = base->m_subItems.cend(); |
202 | while (it != end) { |
203 | if (!visitTree(base: std::static_pointer_cast<AttachedInfoT>(it.value()), visitor, basePath: pNow)) |
204 | return false; |
205 | ++it; |
206 | } |
207 | } else { |
208 | return false; |
209 | } |
210 | } |
211 | return true; |
212 | } |
213 | |
214 | AttachedInfo::Ptr instantiate(AttachedInfo::Ptr parent, Path p = Path()) const override { |
215 | return Ptr(new AttachedInfoT(std::static_pointer_cast<AttachedInfoT>(parent), p)); |
216 | } |
217 | DomItem infoItem(DomItem &self) override { return self.wrapField(Fields::infoItem, m_info); } |
218 | |
219 | Ptr makeCopy(DomItem &self) const |
220 | { |
221 | return std::static_pointer_cast<AttachedInfoT>(doCopy(self)); |
222 | } |
223 | |
224 | Ptr parent() const { return std::static_pointer_cast<AttachedInfoT>(AttachedInfo::parent()); } |
225 | |
226 | const Info &info() const { return m_info; } |
227 | Info &info() { return m_info; } |
228 | protected: |
229 | std::shared_ptr<OwningItem> doCopy(DomItem &) const override |
230 | { |
231 | return Ptr(new AttachedInfoT(*this)); |
232 | } |
233 | |
234 | private: |
235 | Info m_info; |
236 | }; |
237 | |
238 | class QMLDOM_EXPORT FileLocations { |
239 | public: |
240 | using Tree = std::shared_ptr<AttachedInfoT<FileLocations>>; |
241 | constexpr static DomType kindValue = DomType::FileLocations; |
242 | DomType kind() const { return kindValue; } |
243 | bool iterateDirectSubpaths(DomItem &self, DirectVisitor); |
244 | void (QList<QString> keys); |
245 | |
246 | static Tree createTree(Path basePath); |
247 | static Tree ensure(Tree base, Path basePath, |
248 | AttachedInfo::PathType pType = AttachedInfo::PathType::Relative); |
249 | static Tree find(Tree self, Path p, |
250 | AttachedInfo::PathType pType = AttachedInfo::PathType::Relative) |
251 | { |
252 | return AttachedInfoT<FileLocations>::find(self, p, pType); |
253 | } |
254 | |
255 | // returns the path looked up and the found tree when looking for the info attached to item |
256 | static AttachedInfoLookupResult<Tree> |
257 | findAttachedInfo(DomItem &item, |
258 | AttachedInfo::FindOptions options = AttachedInfo::FindOption::Default); |
259 | static FileLocations::Tree treeOf(DomItem &); |
260 | static const FileLocations *fileLocationsOf(DomItem &); |
261 | |
262 | static void updateFullLocation(Tree fLoc, SourceLocation loc); |
263 | static void addRegion(Tree fLoc, QString locName, SourceLocation loc); |
264 | static void addRegion(Tree fLoc, QStringView locName, SourceLocation loc); |
265 | |
266 | SourceLocation fullRegion; |
267 | QMap<QString, SourceLocation> regions; |
268 | QMap<QString, QList<SourceLocation>> ; |
269 | QMap<QString, QList<SourceLocation>> ; |
270 | }; |
271 | |
272 | class QMLDOM_EXPORT UpdatedScriptExpression |
273 | { |
274 | Q_GADGET |
275 | public: |
276 | using Tree = std::shared_ptr<AttachedInfoT<UpdatedScriptExpression>>; |
277 | constexpr static DomType kindValue = DomType::UpdatedScriptExpression; |
278 | DomType kind() const { return kindValue; } |
279 | bool iterateDirectSubpaths(DomItem &self, DirectVisitor); |
280 | |
281 | static Tree createTree(Path basePath); |
282 | static Tree ensure(Tree base, Path basePath, AttachedInfo::PathType pType); |
283 | |
284 | // returns the path looked up and the found tree when looking for the info attached to item |
285 | static AttachedInfoLookupResult<Tree> |
286 | findAttachedInfo(DomItem &item, |
287 | AttachedInfo::FindOptions options = AttachedInfo::FindOption::Default); |
288 | // convenience: find FileLocations::Tree attached to the given item |
289 | static Tree treePtr(DomItem &); |
290 | // convenience: find FileLocations* attached to the given item (if there is one) |
291 | static const UpdatedScriptExpression *exprPtr(DomItem &); |
292 | |
293 | static bool visitTree(Tree base, function_ref<bool(Path, Tree)> visitor, |
294 | Path basePath = Path()); |
295 | |
296 | std::shared_ptr<ScriptExpression> expr; |
297 | }; |
298 | |
299 | } // end namespace Dom |
300 | } // end namespace QQmlJS |
301 | |
302 | QT_END_NAMESPACE |
303 | #endif // QMLDOMATTACHEDINFO_P_H |
304 | |