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 =
82 self.dvItemField(visitor, 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 =
97 self.dvItemField(visitor, 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.dvValueField(visitor, 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.dvValueField(visitor, 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([&cont, &visitor,
175 &self](auto &&e) { cont &= self.dvValueField(visitor, Fields::value, e); },
176 m_value);
177 return cont;
178}
179
180bool IfStatement::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
181{
182 // TODO: test me
183 bool cont = true;
184 cont &= wrap(self, visitor, Fields::condition, m_condition);
185 cont &= wrap(self, visitor, Fields::consequence, m_consequence);
186 cont &= wrap(self, visitor, Fields::alternative, m_alternative);
187 return cont;
188}
189
190void IfStatement::updatePathFromOwner(const Path &p)
191{
192 BaseT::updatePathFromOwner(p);
193 if (auto ptr = m_condition.base())
194 ptr->updatePathFromOwner(p.withField(Fields::condition));
195 if (auto ptr = m_consequence.base())
196 ptr->updatePathFromOwner(p.withField(Fields::consequence));
197 if (auto ptr = m_alternative.base())
198 ptr->updatePathFromOwner(p.withField(Fields::alternative));
199}
200
201void IfStatement::createFileLocations(const FileLocations::Tree &base)
202{
203 BaseT::createFileLocations(base);
204 if (auto ptr = m_condition.base())
205 ptr->createFileLocations(base);
206 if (auto ptr = m_consequence.base())
207 ptr->createFileLocations(base);
208 if (auto ptr = m_alternative.base())
209 ptr->createFileLocations(base);
210}
211
212bool ForStatement::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
213{
214 bool cont = true;
215 cont &= wrap(self, visitor, Fields::initializer, m_initializer);
216 cont &= wrap(self, visitor, Fields::declarations, m_declarations);
217 cont &= wrap(self, visitor, Fields::condition, m_condition);
218 cont &= wrap(self, visitor, Fields::expression, m_expression);
219 cont &= wrap(self, visitor, Fields::body, m_body);
220 return cont;
221}
222
223void ForStatement::updatePathFromOwner(const Path &p)
224{
225 BaseT::updatePathFromOwner(p);
226 if (auto ptr = m_initializer.base())
227 ptr->updatePathFromOwner(p.withField(Fields::initializer));
228 if (auto ptr = m_declarations.base())
229 ptr->updatePathFromOwner(p.withField(Fields::declarations));
230 if (auto ptr = m_condition.base())
231 ptr->updatePathFromOwner(p.withField(Fields::condition));
232 if (auto ptr = m_expression.base())
233 ptr->updatePathFromOwner(p.withField(Fields::expression));
234 if (auto ptr = m_body.base())
235 ptr->updatePathFromOwner(p.withField(Fields::body));
236}
237
238void ForStatement::createFileLocations(const FileLocations::Tree &base)
239{
240 BaseT::createFileLocations(base);
241 if (auto ptr = m_initializer.base())
242 ptr->createFileLocations(base);
243 if (auto ptr = m_declarations.base())
244 ptr->createFileLocations(base);
245 if (auto ptr = m_condition.base())
246 ptr->createFileLocations(base);
247 if (auto ptr = m_expression.base())
248 ptr->createFileLocations(base);
249 if (auto ptr = m_body.base())
250 ptr->createFileLocations(base);
251}
252
253bool BinaryExpression::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
254{
255 bool cont = true;
256 cont &= wrap(self, visitor, Fields::left, m_left);
257 cont &= self.dvValueField(visitor, Fields::operation, m_operator);
258 cont &= wrap(self, visitor, Fields::right, m_right);
259 return cont;
260}
261
262void BinaryExpression::updatePathFromOwner(const Path &p)
263{
264 BaseT::updatePathFromOwner(p);
265 if (auto ptr = m_left.base())
266 ptr->updatePathFromOwner(p.withField(Fields::left));
267 if (auto ptr = m_right.base())
268 ptr->updatePathFromOwner(p.withField(Fields::right));
269}
270
271void BinaryExpression::createFileLocations(const FileLocations::Tree &base)
272{
273 BaseT::createFileLocations(base);
274 if (auto ptr = m_left.base())
275 ptr->createFileLocations(base);
276 if (auto ptr = m_right.base())
277 ptr->createFileLocations(base);
278}
279
280bool VariableDeclarationEntry::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
281{
282 bool cont = true;
283 cont &= self.dvValueField(visitor, Fields::scopeType, m_scopeType);
284 cont &= wrap(self, visitor, Fields::identifier, m_identifier);
285 cont &= wrap(self, visitor, Fields::initializer, m_initializer);
286 return cont;
287}
288
289void VariableDeclarationEntry::updatePathFromOwner(const Path &p)
290{
291 BaseT::updatePathFromOwner(p);
292 if (auto ptr = m_identifier.base())
293 ptr->updatePathFromOwner(p.withField(Fields::identifier));
294 if (auto ptr = m_initializer.base())
295 ptr->updatePathFromOwner(p.withField(Fields::initializer));
296}
297
298void VariableDeclarationEntry::createFileLocations(const FileLocations::Tree &base)
299{
300 BaseT::createFileLocations(base);
301 if (auto ptr = m_identifier.base())
302 ptr->createFileLocations(base);
303 if (auto ptr = m_initializer.base())
304 ptr->createFileLocations(base);
305}
306
307bool VariableDeclaration::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
308{
309 bool cont = true;
310 cont &= wrap(self, visitor, Fields::declarations, m_declarations);
311 return cont;
312}
313
314void VariableDeclaration::updatePathFromOwner(const Path &p)
315{
316 BaseT::updatePathFromOwner(p);
317 m_declarations.updatePathFromOwner(p.withField(Fields::declarations));
318}
319
320void VariableDeclaration::createFileLocations(const FileLocations::Tree &base)
321{
322 BaseT::createFileLocations(base);
323 m_declarations.createFileLocations(base);
324}
325
326bool ReturnStatement::iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const
327{
328 bool cont = true;
329 cont &= wrap(self, visitor, Fields::expression, m_expression);
330 return cont;
331}
332
333void ReturnStatement::updatePathFromOwner(const Path &p)
334{
335 BaseT::updatePathFromOwner(p);
336 if (auto ptr = m_expression.base())
337 ptr->updatePathFromOwner(p.withField(Fields::expression));
338}
339
340void ReturnStatement::createFileLocations(const FileLocations::Tree &base)
341{
342 BaseT::createFileLocations(base);
343 if (auto ptr = m_expression.base())
344 ptr->createFileLocations(base);
345}
346
347void ScriptList::replaceKindForGenericChildren(DomType oldType, DomType newType)
348{
349 for (auto &it : m_list) {
350 if (auto current = it.data()) {
351 if (auto genericElement =
352 std::get_if<std::shared_ptr<ScriptElements::GenericScriptElement>>(
353 &*current)) {
354 if ((*genericElement)->kind() == oldType)
355 (*genericElement)->setKind(newType);
356 }
357 }
358 }
359}
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)