Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqmldomscriptelements.cpp
Go to the documentation of this file.
1// Copyright (C) 2023 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
8#include <memory>
9#include <utility>
10#include <variant>
11
12using namespace QQmlJS::Dom::ScriptElements;
13using QQmlJS::Dom::DomType;
14using QQmlJS::Dom::ScriptElement;
15using QQmlJS::Dom::ScriptElementVariant;
16
17/*!
18 \internal
19 \class ScriptElementBase
20
21 The base class for all script elements.
22
23 Derived classes should implement createFileLocations, DomElement::updatePathFromOwner and
24 DomBase::iterateDirectSubpaths. Furthermore, they need their own DomType enum.
25
26 updatePathFromOwner and createFileLocations should be called on the script element root node
27 after it was constructed for the DomItem-wrapping to work correctly. Without it, methods like
28 iterateDirectSubpaths and all the stuff in DomItem will not work.
29
30 createFileLocations does not work without having the pathFromOwner set
31 first via updatePathFromOwner.
32
33 In derived classes, the updatePathFromOwner-implementation should call the base implementation
34 and also call recursively updatePathFromOwner on the derived class's children.
35
36 See \l ScriptElementBase::createFileLocations for the createFileLocations implementation in
37 derived classes.
38
39 Derived classes need to implement iterateDirectSubpaths to comply with the DomItem interface.
40*/
41
42/*!
43 \internal
44 \fn ScriptElementBase::createFileLocations
45
46 Usually, all the visits/recursive calls to DOM elements can be done using the DomItem interface,
47 once all the DOM has been constructed.
48
49 During construction, createFileLocations can be used to annotate the DOM representation with the
50 corresponding source locations, which are needed, e.g., to find the corresponding DOM element
51 from a certain text position. When called, createFileLocations sets an entry for itself in the
52 FileLocationsTree.
53
54 Derived classes should call the base implemenatation and recursively call createFileLocations on
55 all their children.
56
57 Usually, only the root of the script DOM element requires one createFileLocations call after
58 construction \b{and} after a pathFromOwner was set using updatePathFromOwner.
59
60*/
61
62/*!
63 \internal
64 \class ScriptList
65
66 A Helper class for writing script elements that contain lists, helps for implementing the
67 recursive calls of iterateDirectSubpaths, updatePathFromOwner and createFileLocations.
68*/
69
70/*!
71 \internal
72 Helper for fields with elements in iterateDirectSubpaths.
73 */
74static bool wrap(const QQmlJS::Dom::DomItem &self, QQmlJS::Dom::DirectVisitor visitor, QStringView field,
75 const ScriptElementVariant &value)
76{
77 if (!value)
78 return true;
79
80 const bool b =
81 self.dvItemField(visitor, field, [&self, field, &value]() -> QQmlJS::Dom::DomItem {
82 const QQmlJS::Dom::Path pathFromOwner{ self.pathFromOwner().field(field) };
83 return self.subScriptElementWrapperItem(value);
84 });
85 return b;
86}
87
88/*!
89 \internal
90 Helper for fields with lists in iterateDirectSubpaths.
91 */
92static bool wrap(const QQmlJS::Dom::DomItem &self, QQmlJS::Dom::DirectVisitor visitor, QStringView field,
93 const ScriptList &value)
94{
95 const bool b =
96 self.dvItemField(visitor, field, [&self, field, &value]() -> QQmlJS::Dom::DomItem {
97 const QQmlJS::Dom::Path pathFromOwner{ self.pathFromOwner().field(field) };
98 return self.subListItem(value.asList(pathFromOwner));
99 });
100 return b;
101}
102
103bool GenericScriptElement::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
104{
105 bool cont = true;
106 for (auto it = m_children.begin(); it != m_children.end(); ++it) {
107 cont &= std::visit(
108 [&self, &visitor, &it](auto &&e) { return wrap(self, visitor, it->first, e); },
109 it->second);
110 }
111 for (auto it = m_values.begin(); it != m_values.end(); ++it) {
112 cont &= self.dvValueField(visitor, it->first, it->second);
113 }
114 return cont;
115}
116
117void GenericScriptElement::updatePathFromOwner(const Path &p)
118{
119 BaseT::updatePathFromOwner(p);
120 for (auto it = m_children.begin(); it != m_children.end(); ++it) {
121 std::visit(qOverloadedVisitor{ [&p, &it](ScriptElementVariant &e) {
122 e.base()->updatePathFromOwner(p.field(it->first));
123 },
124 [&p, &it](ScriptList &list) {
125 list.updatePathFromOwner(p.field(it->first));
126 } },
127 it->second);
128 }
129}
130
131void GenericScriptElement::createFileLocations(const FileLocations::Tree &base)
132{
133 BaseT::createFileLocations(base);
134 for (auto it = m_children.begin(); it != m_children.end(); ++it) {
135 std::visit(
136 qOverloadedVisitor{
137 [&base](ScriptElementVariant &e) { e.base()->createFileLocations(base); },
138 [&base](ScriptList &list) { list.createFileLocations(base); } },
139 it->second);
140 }
141}
142
143bool BlockStatement::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
144{
145 // TODO: test me
146 bool cont = true;
147 cont &= wrap(self, visitor, Fields::statements, m_statements);
148 return cont;
149}
150
151void BlockStatement::updatePathFromOwner(const Path &p)
152{
153 BaseT::updatePathFromOwner(p);
154 m_statements.updatePathFromOwner(p.field(Fields::statements));
155}
156
157void BlockStatement::createFileLocations(const FileLocations::Tree &base)
158{
159 BaseT::createFileLocations(base);
160 m_statements.createFileLocations(base);
161}
162
163bool IdentifierExpression::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
164{
165 bool cont = true;
166 cont &= self.dvValueField(visitor, Fields::identifier, m_name);
167 return cont;
168}
169
170bool Literal::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
171{
172 bool cont = true;
173 std::visit([&cont, &visitor,
174 &self](auto &&e) { cont &= self.dvValueField(visitor, Fields::value, e); },
175 m_value);
176 return cont;
177}
178
179bool IfStatement::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
180{
181 // TODO: test me
182 bool cont = true;
183 cont &= wrap(self, visitor, Fields::condition, m_condition);
184 cont &= wrap(self, visitor, Fields::consequence, m_consequence);
185 cont &= wrap(self, visitor, Fields::alternative, m_alternative);
186 return cont;
187}
188
189void IfStatement::updatePathFromOwner(const Path &p)
190{
191 BaseT::updatePathFromOwner(p);
192 if (auto ptr = m_condition.base())
193 ptr->updatePathFromOwner(p.field(Fields::condition));
194 if (auto ptr = m_consequence.base())
195 ptr->updatePathFromOwner(p.field(Fields::consequence));
196 if (auto ptr = m_alternative.base())
197 ptr->updatePathFromOwner(p.field(Fields::alternative));
198}
199
200void IfStatement::createFileLocations(const FileLocations::Tree &base)
201{
202 BaseT::createFileLocations(base);
203 if (auto ptr = m_condition.base())
204 ptr->createFileLocations(base);
205 if (auto ptr = m_consequence.base())
206 ptr->createFileLocations(base);
207 if (auto ptr = m_alternative.base())
208 ptr->createFileLocations(base);
209}
210
211bool ForStatement::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
212{
213 bool cont = true;
214 cont &= wrap(self, visitor, Fields::initializer, m_initializer);
215 cont &= wrap(self, visitor, Fields::declarations, m_declarations);
216 cont &= wrap(self, visitor, Fields::condition, m_condition);
217 cont &= wrap(self, visitor, Fields::expression, m_expression);
218 cont &= wrap(self, visitor, Fields::body, m_body);
219 return cont;
220}
221
222void ForStatement::updatePathFromOwner(const Path &p)
223{
224 BaseT::updatePathFromOwner(p);
225 if (auto ptr = m_initializer.base())
226 ptr->updatePathFromOwner(p.field(Fields::initializer));
227 if (auto ptr = m_declarations.base())
228 ptr->updatePathFromOwner(p.field(Fields::declarations));
229 if (auto ptr = m_condition.base())
230 ptr->updatePathFromOwner(p.field(Fields::condition));
231 if (auto ptr = m_expression.base())
232 ptr->updatePathFromOwner(p.field(Fields::expression));
233 if (auto ptr = m_body.base())
234 ptr->updatePathFromOwner(p.field(Fields::body));
235}
236
237void ForStatement::createFileLocations(const FileLocations::Tree &base)
238{
239 BaseT::createFileLocations(base);
240 if (auto ptr = m_initializer.base())
241 ptr->createFileLocations(base);
242 if (auto ptr = m_declarations.base())
243 ptr->createFileLocations(base);
244 if (auto ptr = m_condition.base())
245 ptr->createFileLocations(base);
246 if (auto ptr = m_expression.base())
247 ptr->createFileLocations(base);
248 if (auto ptr = m_body.base())
249 ptr->createFileLocations(base);
250}
251
252bool BinaryExpression::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
253{
254 bool cont = true;
255 cont &= wrap(self, visitor, Fields::left, m_left);
256 cont &= self.dvValueField(visitor, Fields::operation, m_operator);
257 cont &= wrap(self, visitor, Fields::right, m_right);
258 return cont;
259}
260
261void BinaryExpression::updatePathFromOwner(const Path &p)
262{
263 BaseT::updatePathFromOwner(p);
264 if (auto ptr = m_left.base())
265 ptr->updatePathFromOwner(p.field(Fields::left));
266 if (auto ptr = m_right.base())
267 ptr->updatePathFromOwner(p.field(Fields::right));
268}
269
270void BinaryExpression::createFileLocations(const FileLocations::Tree &base)
271{
272 BaseT::createFileLocations(base);
273 if (auto ptr = m_left.base())
274 ptr->createFileLocations(base);
275 if (auto ptr = m_right.base())
276 ptr->createFileLocations(base);
277}
278
279bool VariableDeclarationEntry::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
280{
281 bool cont = true;
282 cont &= self.dvValueField(visitor, Fields::scopeType, m_scopeType);
283 cont &= wrap(self, visitor, Fields::identifier, m_identifier);
284 cont &= wrap(self, visitor, Fields::initializer, m_initializer);
285 return cont;
286}
287
288void VariableDeclarationEntry::updatePathFromOwner(const Path &p)
289{
290 BaseT::updatePathFromOwner(p);
291 if (auto ptr = m_identifier.base())
292 ptr->updatePathFromOwner(p.field(Fields::identifier));
293 if (auto ptr = m_initializer.base())
294 ptr->updatePathFromOwner(p.field(Fields::initializer));
295}
296
297void VariableDeclarationEntry::createFileLocations(const FileLocations::Tree &base)
298{
299 BaseT::createFileLocations(base);
300 if (auto ptr = m_identifier.base())
301 ptr->createFileLocations(base);
302 if (auto ptr = m_initializer.base())
303 ptr->createFileLocations(base);
304}
305
306bool VariableDeclaration::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
307{
308 bool cont = true;
309 cont &= wrap(self, visitor, Fields::declarations, m_declarations);
310 return cont;
311}
312
313void VariableDeclaration::updatePathFromOwner(const Path &p)
314{
315 BaseT::updatePathFromOwner(p);
316 m_declarations.updatePathFromOwner(p.field(Fields::declarations));
317}
318
319void VariableDeclaration::createFileLocations(const FileLocations::Tree &base)
320{
321 BaseT::createFileLocations(base);
322 m_declarations.createFileLocations(base);
323}
324
325bool ReturnStatement::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
326{
327 bool cont = true;
328 cont &= wrap(self, visitor, Fields::expression, m_expression);
329 return cont;
330}
331
332void ReturnStatement::updatePathFromOwner(const Path &p)
333{
334 BaseT::updatePathFromOwner(p);
335 if (auto ptr = m_expression.base())
336 ptr->updatePathFromOwner(p.field(Fields::expression));
337}
338
339void ReturnStatement::createFileLocations(const FileLocations::Tree &base)
340{
341 BaseT::createFileLocations(base);
342 if (auto ptr = m_expression.base())
343 ptr->createFileLocations(base);
344}
345
346void ScriptList::replaceKindForGenericChildren(DomType oldType, DomType newType)
347{
348 for (auto &it : m_list) {
349 if (auto current = it.data()) {
350 if (auto genericElement =
351 std::get_if<std::shared_ptr<ScriptElements::GenericScriptElement>>(
352 &*current)) {
353 if ((*genericElement)->kind() == oldType)
354 (*genericElement)->setKind(newType);
355 }
356 }
357 }
358}
Path pathFromOwner() const
DomItem subListItem(const List &list) const
DomItem subScriptElementWrapperItem(const ScriptElementVariant &obj) const
Use this to contain any script element.
static bool wrap(const QQmlJS::Dom::DomItem &self, QQmlJS::Dom::DirectVisitor visitor, QStringView field, const ScriptList &value)
static bool wrap(const QQmlJS::Dom::DomItem &self, QQmlJS::Dom::DirectVisitor visitor, QStringView field, const ScriptElementVariant &value)