Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qqmldomastcreator_p.h
Go to the documentation of this file.
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 QQMLDOMASTCREATOR_P_H
5#define QQMLDOMASTCREATOR_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 "qqmldomelements_p.h"
19#include "qqmldomitem_p.h"
20#include "qqmldompath_p.h"
22
23#include <QtQmlCompiler/private/qqmljsimportvisitor_p.h>
24
25#include <QtQml/private/qqmljsastvisitor_p.h>
26#include <memory>
27#include <type_traits>
28#include <variant>
29
31
32namespace QQmlJS {
33namespace Dom {
34
35class QQmlDomAstCreator final : public AST::Visitor
36{
38 using AST::Visitor::endVisit;
39 using AST::Visitor::visit;
40
41 static constexpr const auto className = "QmlDomAstCreator";
42
43 class DomValue
44 {
45 public:
46 template<typename T>
47 DomValue(const T &obj) : kind(T::kindValue), value(obj)
48 {
49 }
50 DomType kind;
53 value;
54 };
55
56 class QmlStackElement
57 {
58 public:
59 Path path;
60 DomValue item;
61 FileLocations::Tree fileLocations;
62 };
63
77 class ScriptStackElement
78 {
79 public:
80 template<typename T>
81 static ScriptStackElement from(const T &obj)
82 {
83 if constexpr (std::is_same_v<T, ScriptElements::ScriptList>) {
84 ScriptStackElement s{ ScriptElements::ScriptList::kindValue, obj };
85 return s;
86 } else {
87 ScriptStackElement s{ obj->kind(), ScriptElementVariant::fromElement(obj) };
88 return s;
89 }
90 Q_UNREACHABLE();
91 }
92
93 DomType kind;
94 using Variant = std::variant<ScriptElementVariant, ScriptElements::ScriptList>;
96
97 ScriptElementVariant takeVariant()
98 {
99 Q_ASSERT_X(std::holds_alternative<ScriptElementVariant>(value), "takeVariant",
100 "Should be a variant, did the parser change?");
101 return std::get<ScriptElementVariant>(std::move(value));
102 }
103
104 bool isList() const { return std::holds_alternative<ScriptElements::ScriptList>(value); };
105
107 {
108 Q_ASSERT_X(std::holds_alternative<ScriptElements::ScriptList>(value), "takeList",
109 "Should be a List, did the parser change?");
110 return std::get<ScriptElements::ScriptList>(std::move(value));
111 }
112
113 void setSemanticScope(const QQmlJSScope::Ptr &scope)
114 {
115 if (auto x = std::get_if<ScriptElementVariant>(&value)) {
116 x->base()->setSemanticScope(scope);
117 return;
118 } else if (auto x = std::get_if<ScriptElements::ScriptList>(&value)) {
119 x->setSemanticScope(scope);
120 return;
121 }
122 Q_UNREACHABLE();
123 }
124 };
125
126public:
127 void enableScriptExpressions(bool enable = true) { m_enableScriptExpressions = enable; }
128
129private:
130
131 MutableDomItem qmlFile;
132 std::shared_ptr<QmlFile> qmlFilePtr;
133 QVector<QmlStackElement> nodeStack;
134 QList<ScriptStackElement> scriptNodeStack;
135 QVector<int> arrayBindingLevels;
136 FileLocations::Tree rootMap;
137 bool m_enableScriptExpressions;
138
139 template<typename T>
140 QmlStackElement &currentEl(int idx = 0)
141 {
142 Q_ASSERT_X(idx < nodeStack.size() && idx >= 0, "currentQmlObjectOrComponentEl",
143 "Stack does not contain enough elements!");
144 int i = nodeStack.size() - idx;
145 while (i-- > 0) {
146 DomType k = nodeStack.at(i).item.kind;
147 if (k == T::kindValue)
148 return nodeStack[i];
149 }
150 Q_ASSERT_X(false, "currentEl", "Stack does not contan object of type ");
151 return nodeStack.last();
152 }
153
154 template<typename T>
155 ScriptStackElement &currentScriptEl(int idx = 0)
156 {
157 Q_ASSERT_X(m_enableScriptExpressions, "currentScriptEl",
158 "Cannot access script elements when they are disabled!");
159
160 Q_ASSERT_X(idx < scriptNodeStack.size() && idx >= 0, "currentQmlObjectOrComponentEl",
161 "Stack does not contain enough elements!");
162 int i = scriptNodeStack.size() - idx;
163 while (i-- > 0) {
164 DomType k = scriptNodeStack.at(i).kind;
165 if (k == T::element_type::kindValue)
166 return scriptNodeStack[i];
167 }
168 Q_ASSERT_X(false, "currentEl", "Stack does not contain object of type ");
169 return scriptNodeStack.last();
170 }
171
172 template<typename T>
173 T &current(int idx = 0)
174 {
175 return std::get<T>(currentEl<T>(idx).item.value);
176 }
177
178 index_type currentIndex() { return currentNodeEl().path.last().headIndex(); }
179
180 QmlStackElement &currentQmlObjectOrComponentEl(int idx = 0);
181
182 QmlStackElement &currentNodeEl(int i = 0);
183 ScriptStackElement &currentScriptNodeEl(int i = 0);
184
185 DomValue &currentNode(int i = 0);
186
187 void removeCurrentNode(std::optional<DomType> expectedType);
188 void removeCurrentScriptNode(std::optional<DomType> expectedType);
189
190 void pushEl(Path p, DomValue it, AST::Node *n)
191 {
192 nodeStack.append({ p, it, createMap(it.kind, p, n) });
193 }
194
195 FileLocations::Tree createMap(FileLocations::Tree base, Path p, AST::Node *n);
196
197 FileLocations::Tree createMap(DomType k, Path p, AST::Node *n);
198
199 const ScriptElementVariant &finalizeScriptExpression(const ScriptElementVariant &element,
200 Path pathFromOwner,
202
203 const ScriptElementVariant &finalizeScriptList(AST::Node *ast, FileLocations::Tree base);
204 void setScriptExpression (const std::shared_ptr<ScriptExpression>& value);
205
206 Path pathOfLastScriptNode() const;
207
212 template<typename AstNodeT>
213 static std::shared_ptr<ScriptElements::Literal> makeStringLiteral(QStringView value,
214 AstNodeT *ast)
215 {
216 auto myExp = std::make_shared<ScriptElements::Literal>(ast->firstSourceLocation(),
217 ast->lastSourceLocation());
218 myExp->setLiteralValue(value.toString());
219 return myExp;
220 }
221
222 static std::shared_ptr<ScriptElements::Literal> makeStringLiteral(QStringView value,
224 {
225 auto myExp = std::make_shared<ScriptElements::Literal>(loc);
226 myExp->setLiteralValue(value.toString());
227 return myExp;
228 }
229
236 template<typename ScriptElementT, typename AstNodeT,
237 typename Enable =
238 std::enable_if_t<!std::is_same_v<ScriptElementT, ScriptElements::ScriptList>>>
239 static decltype(auto) makeScriptElement(AstNodeT *ast)
240 {
241 auto myExp = std::make_shared<ScriptElementT>(ast->firstSourceLocation(),
242 ast->lastSourceLocation());
243 return myExp;
244 }
245
251 template<typename AstNodeT>
252 static std::shared_ptr<ScriptElements::GenericScriptElement>
253 makeGenericScriptElement(AstNodeT *ast, DomType kind)
254 {
255 auto myExp = std::make_shared<ScriptElements::GenericScriptElement>(
256 ast->firstSourceLocation(), ast->lastSourceLocation());
257 myExp->setKind(kind);
258 return myExp;
259 }
260
261 static std::shared_ptr<ScriptElements::GenericScriptElement>
262 makeGenericScriptElement(SourceLocation location, DomType kind)
263 {
264 auto myExp = std::make_shared<ScriptElements::GenericScriptElement>(location);
265 myExp->setKind(kind);
266 return myExp;
267 }
268
274 template<typename AstNodeT>
275 static decltype(auto) makeScriptList(AstNodeT *ast)
276 {
277 auto myExp =
278 ScriptElements::ScriptList(ast->firstSourceLocation(), ast->lastSourceLocation());
279 return myExp;
280 }
281
282 template<typename ScriptElementT>
283 void pushScriptElement(ScriptElementT element)
284 {
285 Q_ASSERT_X(m_enableScriptExpressions, "pushScriptElement",
286 "Cannot create script elements when they are disabled!");
287 scriptNodeStack.append(ScriptStackElement::from(element));
288 }
289
290 void disableScriptElements()
291 {
292 m_enableScriptExpressions = false;
293 scriptNodeStack.clear();
294 }
295
296 ScriptElementVariant scriptElementForQualifiedId(AST::UiQualifiedId *expression);
297
298public:
299 QQmlDomAstCreator(MutableDomItem qmlFile);
300
301 bool visit(AST::UiProgram *program) override;
302 void endVisit(AST::UiProgram *) override;
303
304 bool visit(AST::UiPragma *el) override;
305
306 bool visit(AST::UiImport *el) override;
307
308 bool visit(AST::UiPublicMember *el) override;
309 void endVisit(AST::UiPublicMember *el) override;
310
311 bool visit(AST::UiSourceElement *el) override;
312 void endVisit(AST::UiSourceElement *) override;
313
315
316 bool visit(AST::UiObjectDefinition *el) override;
317 void endVisit(AST::UiObjectDefinition *) override;
318
319 bool visit(AST::UiObjectBinding *el) override;
320 void endVisit(AST::UiObjectBinding *) override;
321
322 bool visit(AST::UiScriptBinding *el) override;
323 void endVisit(AST::UiScriptBinding *) override;
324
325 bool visit(AST::UiArrayBinding *el) override;
326 void endVisit(AST::UiArrayBinding *) override;
327
328 bool visit(AST::UiQualifiedId *) override;
329
330 bool visit(AST::UiEnumDeclaration *el) override;
331 void endVisit(AST::UiEnumDeclaration *) override;
332
333 bool visit(AST::UiEnumMemberList *el) override;
334 void endVisit(AST::UiEnumMemberList *el) override;
335
336 bool visit(AST::UiInlineComponent *el) override;
337 void endVisit(AST::UiInlineComponent *) override;
338
339 bool visit(AST::UiRequired *el) override;
340
341 bool visit(AST::UiAnnotation *el) override;
342 void endVisit(AST::UiAnnotation *) override;
343
344 // for Script elements:
345 bool visit(AST::BinaryExpression *exp) override;
346 void endVisit(AST::BinaryExpression *exp) override;
347
348 bool visit(AST::Block *block) override;
349 void endVisit(AST::Block *) override;
350
351 bool visit(AST::ReturnStatement *block) override;
352 void endVisit(AST::ReturnStatement *) override;
353
354 bool visit(AST::ForStatement *forStatement) override;
355 void endVisit(AST::ForStatement *forStatement) override;
356
357 bool visit(AST::PatternElement *pe) override;
358 void endVisit(AST::PatternElement *pe) override;
360 const std::shared_ptr<ScriptElements::GenericScriptElement> &element);
361
362 bool visit(AST::IfStatement *) override;
363 void endVisit(AST::IfStatement *) override;
364
365 bool visit(AST::FieldMemberExpression *) override;
366 void endVisit(AST::FieldMemberExpression *) override;
367
368 bool visit(AST::ArrayMemberExpression *) override;
369 void endVisit(AST::ArrayMemberExpression *) override;
370
371 bool visit(AST::CallExpression *) override;
372 void endVisit(AST::CallExpression *) override;
373
374 bool visit(AST::ArrayPattern *) override;
375 void endVisit(AST::ArrayPattern *) override;
376
377 bool visit(AST::ObjectPattern *) override;
378 void endVisit(AST::ObjectPattern *) override;
379
380 bool visit(AST::PatternProperty *) override;
381 void endVisit(AST::PatternProperty *) override;
382
383 bool visit(AST::VariableStatement *) override;
384 void endVisit(AST::VariableStatement *) override;
385
386 bool visit(AST::Type *expression) override;
387 void endVisit(AST::Type *expression) override;
388
389 bool visit(AST::DefaultClause *) override;
390 void endVisit(AST::DefaultClause *) override;
391
392 bool visit(AST::CaseClause *) override;
393 void endVisit(AST::CaseClause *) override;
394
395 bool visit(AST::CaseClauses *) override;
396 void endVisit(AST::CaseClauses *) override;
397
398 bool visit(AST::CaseBlock *) override;
399 void endVisit(AST::CaseBlock *) override;
400
401 bool visit(AST::SwitchStatement *) override;
402 void endVisit(AST::SwitchStatement *) override;
403
404 bool visit(AST::WhileStatement *) override;
405 void endVisit(AST::WhileStatement *) override;
406
407 bool visit(AST::DoWhileStatement *) override;
408 void endVisit(AST::DoWhileStatement *) override;
409
410 bool visit(AST::ForEachStatement *) override;
411 void endVisit(AST::ForEachStatement *) override;
412
413 // lists of stuff whose children do not need a qqmljsscope: visitation order can be custom
414 bool visit(AST::ArgumentList *) override;
415 bool visit(AST::UiParameterList *) override;
416 bool visit(AST::PatternElementList *) override;
417 bool visit(AST::PatternPropertyList *) override;
418 bool visit(AST::VariableDeclarationList *vdl) override;
419 bool visit(AST::Elision *elision) override;
420
421 // lists of stuff whose children need a qqmljsscope: visitation order cannot be custom
422 bool visit(AST::StatementList *list) override;
423 void endVisit(AST::StatementList *list) override;
424
425 // literals and ids
426 bool visit(AST::IdentifierExpression *expression) override;
427 bool visit(AST::NumericLiteral *expression) override;
428 bool visit(AST::StringLiteral *expression) override;
429 bool visit(AST::NullExpression *expression) override;
430 bool visit(AST::TrueLiteral *expression) override;
431 bool visit(AST::FalseLiteral *expression) override;
432 bool visit(AST::ComputedPropertyName *expression) override;
433 bool visit(AST::IdentifierPropertyName *expression) override;
434 bool visit(AST::NumericLiteralPropertyName *expression) override;
435 bool visit(AST::StringLiteralPropertyName *expression) override;
436 bool visit(AST::TypeAnnotation *expression) override;
437
438 void throwRecursionDepthError() override;
439
440public:
442};
443
445{
446public:
448
449#define X(name) \
450 bool visit(AST::name *) override; \
451 void endVisit(AST::name *) override;
453#undef X
454
455 virtual void throwRecursionDepthError() override;
462 {
463 m_enableScriptExpressions = enable;
464 m_domCreator.enableScriptExpressions(enable);
465 }
466
467 QQmlJSImporter &importer() { return m_importer; }
468 QQmlJSImportVisitor &scopeCreator() { return m_scopeCreator; }
469
470private:
471 void setScopeInDomAfterEndvisit();
472 void setScopeInDomBeforeEndvisit();
473
474 template<typename U, typename... V>
475 using IsInList = std::disjunction<std::is_same<U, V>...>;
476 template<typename U>
477 using RequiresCustomIteration = IsInList<U, AST::PatternElementList, AST::PatternPropertyList,
479
480 template<typename T>
481 void customListIteration(T *t)
482 {
483 static_assert(RequiresCustomIteration<T>::value);
484 for (auto it = t; it; it = it->next) {
485 if constexpr (std::is_same_v<T, AST::PatternElementList>) {
486 AST::Node::accept(it->elision, this);
487 AST::Node::accept(it->element, this);
488 } else if constexpr (std::is_same_v<T, AST::PatternPropertyList>) {
489 AST::Node::accept(it->property, this);
490 } else if constexpr (std::is_same_v<T, AST::FormalParameterList>) {
491 AST::Node::accept(it->element, this);
492 } else {
493 Q_UNREACHABLE();
494 }
495 }
496 }
497
498 template<typename T>
499 bool visitT(T *t)
500 {
501 if (m_marker && m_marker->nodeKind == t->kind) {
502 m_marker->count += 1;
503 }
504
505 // first case: no marker, both can visit
506 if (!m_marker) {
507 bool continueForDom = m_domCreator.visit(t);
508 bool continueForScope = m_scopeCreator.visit(t);
509 if (!continueForDom && !continueForScope)
510 return false;
511 else if (continueForDom ^ continueForScope) {
512 m_marker.emplace();
513 m_marker->inactiveVisitor = continueForDom ? ScopeCreator : DomCreator;
514 m_marker->count = 1;
515 m_marker->nodeKind = AST::Node::Kind(t->kind);
516
517 if constexpr (RequiresCustomIteration<T>::value) {
518 customListIteration(t);
519 return false;
520 } else {
521 return true;
522 }
523 } else {
524 Q_ASSERT(continueForDom && continueForScope);
525
526 if constexpr (RequiresCustomIteration<T>::value) {
527 customListIteration(t);
528 return false;
529 } else {
530 return true;
531 }
532 }
533 Q_UNREACHABLE();
534 }
535
536 // second case: a marker, just one visit
537 switch (m_marker->inactiveVisitor) {
538 case DomCreator: {
539 const bool continueForScope = m_scopeCreator.visit(t);
540 if (continueForScope) {
541 if constexpr (RequiresCustomIteration<T>::value) {
542 customListIteration(t);
543 return false;
544 }
545 }
546 return continueForScope;
547 }
548 case ScopeCreator: {
549 const bool continueForDom = m_domCreator.visit(t);
550 if (continueForDom) {
551 if constexpr (RequiresCustomIteration<T>::value) {
552 customListIteration(t);
553 return false;
554 }
555 }
556 return continueForDom;
557 }
558 };
559 Q_UNREACHABLE();
560 }
561
562 template<typename T>
563 void endVisitT(T *t)
564 {
565 if (m_marker && m_marker->nodeKind == t->kind) {
566 m_marker->count -= 1;
567 if (m_marker->count == 0)
568 m_marker.reset();
569 }
570
571 if (m_marker) {
572 switch (m_marker->inactiveVisitor) {
573 case DomCreator: {
574 m_scopeCreator.endVisit(t);
575 return;
576 }
577 case ScopeCreator: {
578 m_domCreator.endVisit(t);
579 return;
580 }
581 };
582 Q_UNREACHABLE();
583 }
584
585 setScopeInDomBeforeEndvisit();
586 m_domCreator.endVisit(t);
587 setScopeInDomAfterEndvisit();
588 m_scopeCreator.endVisit(t);
589 }
590
591 QQmlJSScope::Ptr m_root;
592 QQmlJSLogger *m_logger;
593 QQmlJSImporter m_importer;
594 QString m_implicitImportDirectory;
595 QQmlJSImportVisitor m_scopeCreator;
596 QQmlDomAstCreator m_domCreator;
597
598 enum InactiveVisitor : bool { DomCreator, ScopeCreator };
599 struct Marker
600 {
602 AST::Node::Kind nodeKind;
603 InactiveVisitor inactiveVisitor;
604 };
605 std::optional<Marker> m_marker;
606 bool m_enableScriptExpressions;
607};
608
609} // end namespace Dom
610} // end namespace QQmlJS
611
613#endif // QQMLDOMASTCREATOR_P_H
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
T & last()
Definition qlist.h:631
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
void append(parameter_type t)
Definition qlist.h:441
void clear()
Definition qlist.h:417
void endVisit(QQmlJS::AST::ExpressionStatement *ast) override
bool visit(QQmlJS::AST::StringLiteral *) override
void accept(BaseVisitor *visitor)
std::shared_ptr< AttachedInfoT< FileLocations > > Tree
virtual QQmlJSASTClassListToVisit void throwRecursionDepthError() override
void endVisit(AST::UiProgram *) override
void endVisitHelper(AST::PatternElement *pe, const std::shared_ptr< ScriptElements::GenericScriptElement > &element)
QQmlDomAstCreator(MutableDomItem qmlFile)
void enableScriptExpressions(bool enable=true)
bool visit(AST::UiProgram *program) override
void loadAnnotations(AST::UiObjectMember *el)
Use this to contain any script element.
static ScriptElementVariant fromElement(T element)
\inmodule QtCore
Definition qstringview.h:76
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
QSet< QString >::iterator it
qint64 index_type
Combined button and popup list for selecting options.
#define Q_DECLARE_TR_FUNCTIONS(context)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
GLint location
GLint GLint GLint GLint GLint x
[0]
GLenum GLenum GLsizei count
GLboolean enable
GLuint program
GLfloat n
GLhandleARB obj
[2]
GLdouble GLdouble t
Definition qopenglext.h:243
GLsizei const GLchar *const * path
GLdouble s
[6]
Definition qopenglext.h:235
GLfloat GLfloat p
[1]
#define QQmlJSASTClassListToVisit
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
ptrdiff_t qsizetype
Definition qtypes.h:70
QList< int > list
[14]
QGraphicsItem * item
QStringView el