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