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"
21#include "qqmldomscriptelements_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
30QT_BEGIN_NAMESPACE
31
32namespace QQmlJS {
33namespace Dom {
34
35class QQmlDomAstCreator final : public AST::Visitor
36{
37 Q_DECLARE_TR_FUNCTIONS(QQmlDomAstCreator)
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;
51 std::variant<QmlObject, MethodInfo, QmlComponent, PropertyDefinition, Binding, EnumDecl,
52 EnumItem, ConstantData, Id>
53 value;
54 };
55
56 class QmlStackElement
57 {
58 public:
59 Path path;
60 DomValue item;
61 FileLocations::Tree fileLocations;
62 };
63
64 /*!
65 \internal
66 Contains a ScriptElementVariant, that can be used everywhere in the DOM representation, or a
67 List that should always be inside of something else, e.g., that cannot be the root of the
68 script element DOM representation.
69
70 Also, it makes sure you do not mistreat a list as a regular script element and vice versa.
71
72 The reason for this is that Lists can get pretty unintuitive, as a List could be a Block of
73 statements or a list of variable declarations (let i = 3, j = 4, ...) or something completely
74 different. Instead, always put lists inside named construct (BlockStatement,
75 VariableDeclaration, ...).
76 */
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>;
95 Variant value;
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>(v: std::move(value));
102 }
103
104 bool isList() const { return std::holds_alternative<ScriptElements::ScriptList>(v: value); };
105
106 ScriptElements::ScriptList takeList()
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>(v: std::move(value));
111 }
112
113 void setSemanticScope(const QQmlJSScope::ConstPtr &scope)
114 {
115 if (auto x = std::get_if<ScriptElementVariant>(ptr: &value)) {
116 x->base()->setSemanticScope(scope);
117 return;
118 } else if (auto x = std::get_if<ScriptElements::ScriptList>(ptr: &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 void enableLoadFileLazily(bool enable = true) { m_loadFileLazily = enable; }
129
130private:
131
132 MutableDomItem qmlFile;
133 std::shared_ptr<QmlFile> qmlFilePtr;
134 QVector<QmlStackElement> nodeStack;
135 QList<ScriptStackElement> scriptNodeStack;
136 QVector<int> arrayBindingLevels;
137 FileLocations::Tree rootMap;
138 int m_nestedFunctionDepth = 0;
139 bool m_enableScriptExpressions = false;
140 bool m_loadFileLazily = false;
141
142 // A Binding inside a UiPublicMember (= a Property definition) will shadow the
143 // propertydefinition's binding identifiers with its own binding identifiers. Therefore, disable
144 // bindingIdentifiers for the Binding inside a Property definition by using this flag.
145 bool m_skipBindingIdentifiers = false;
146
147 void setBindingIdentifiers(const Path &pathFromOwner, const AST::UiQualifiedId *identifiers,
148 Binding *bindingPtr);
149 template<typename T>
150 QmlStackElement &currentEl(int idx = 0)
151 {
152 Q_ASSERT_X(idx < nodeStack.size() && idx >= 0, "currentQmlObjectOrComponentEl",
153 "Stack does not contain enough elements!");
154 int i = nodeStack.size() - idx;
155 while (i-- > 0) {
156 DomType k = nodeStack.at(i).item.kind;
157 if (k == T::kindValue)
158 return nodeStack[i];
159 }
160 Q_ASSERT_X(false, "currentEl", "Stack does not contan object of type ");
161 return nodeStack.last();
162 }
163
164 template<typename T>
165 ScriptStackElement &currentScriptEl(int idx = 0)
166 {
167 Q_ASSERT_X(m_enableScriptExpressions, "currentScriptEl",
168 "Cannot access script elements when they are disabled!");
169
170 Q_ASSERT_X(idx < scriptNodeStack.size() && idx >= 0, "currentQmlObjectOrComponentEl",
171 "Stack does not contain enough elements!");
172 int i = scriptNodeStack.size() - idx;
173 while (i-- > 0) {
174 DomType k = scriptNodeStack.at(i).kind;
175 if (k == T::element_type::kindValue)
176 return scriptNodeStack[i];
177 }
178 Q_ASSERT_X(false, "currentEl", "Stack does not contain object of type ");
179 return scriptNodeStack.last();
180 }
181
182 template<typename T>
183 T &current(int idx = 0)
184 {
185 return std::get<T>(currentEl<T>(idx).item.value);
186 }
187
188 index_type currentIndex() { return currentNodeEl().path.last().headIndex(); }
189
190 QmlStackElement &currentQmlObjectOrComponentEl(int idx = 0);
191
192 QmlStackElement &currentNodeEl(int i = 0);
193 ScriptStackElement &currentScriptNodeEl(int i = 0);
194
195 DomValue &currentNode(int i = 0);
196
197 void removeCurrentNode(std::optional<DomType> expectedType);
198 void removeCurrentScriptNode(std::optional<DomType> expectedType);
199
200 void pushEl(const Path &p, const DomValue &it, AST::Node *n)
201 {
202 nodeStack.append(t: { .path: p, .item: it, .fileLocations: createMap(k: it.kind, p, n) });
203 }
204
205 FileLocations::Tree createMap(const FileLocations::Tree &base, const Path &p, AST::Node *n);
206
207 FileLocations::Tree createMap(DomType k, const Path &p, AST::Node *n);
208
209 const ScriptElementVariant &
210 finalizeScriptExpression(const ScriptElementVariant &element, const Path &pathFromOwner,
211 const FileLocations::Tree &ownerFileLocations);
212
213 void setScriptExpression (const std::shared_ptr<ScriptExpression>& value);
214
215 Path pathOfLastScriptNode() const;
216
217 /*!
218 \internal
219 Helper to create string literals from AST nodes.
220 */
221 template<typename AstNodeT>
222 static std::shared_ptr<ScriptElements::Literal> makeStringLiteral(QStringView value,
223 AstNodeT *ast)
224 {
225 auto myExp = std::make_shared<ScriptElements::Literal>(ast->firstSourceLocation(),
226 ast->lastSourceLocation());
227 myExp->setLiteralValue(value.toString());
228 return myExp;
229 }
230
231 static std::shared_ptr<ScriptElements::Literal> makeStringLiteral(QStringView value,
232 QQmlJS::SourceLocation loc)
233 {
234 auto myExp = std::make_shared<ScriptElements::Literal>(args&: loc);
235 myExp->setLiteralValue(value.toString());
236 return myExp;
237 }
238
239 /*!
240 \internal
241 Helper to create script elements from AST nodes, as the DOM classes should be completely
242 dependency-free from AST and parser classes. Using the AST classes in qqmldomastcreator is
243 fine because it needs them for the construction/visit. \sa makeScriptList
244 */
245 template<typename ScriptElementT, typename AstNodeT,
246 typename Enable =
247 std::enable_if_t<!std::is_same_v<ScriptElementT, ScriptElements::ScriptList>>>
248 static decltype(auto) makeScriptElement(AstNodeT *ast)
249 {
250 auto myExp = std::make_shared<ScriptElementT>(ast->firstSourceLocation(),
251 ast->lastSourceLocation());
252 return myExp;
253 }
254
255 /*!
256 \internal
257 Helper to create generic script elements from AST nodes.
258 \sa makeScriptElement
259 */
260 template<typename AstNodeT>
261 static std::shared_ptr<ScriptElements::GenericScriptElement>
262 makeGenericScriptElement(AstNodeT *ast, DomType kind)
263 {
264 auto myExp = std::make_shared<ScriptElements::GenericScriptElement>(
265 ast->firstSourceLocation(), ast->lastSourceLocation());
266 myExp->setKind(kind);
267 return myExp;
268 }
269
270 enum UnaryExpressionKind { Prefix, Postfix };
271 std::shared_ptr<ScriptElements::GenericScriptElement>
272 makeUnaryExpression(AST::Node *expression, QQmlJS::SourceLocation operatorToken,
273 bool hasExpression, UnaryExpressionKind type);
274
275 static std::shared_ptr<ScriptElements::GenericScriptElement>
276 makeGenericScriptElement(SourceLocation location, DomType kind)
277 {
278 auto myExp = std::make_shared<ScriptElements::GenericScriptElement>(args&: location);
279 myExp->setKind(kind);
280 return myExp;
281 }
282
283 /*!
284 \internal
285 Helper to create script lists from AST nodes.
286 \sa makeScriptElement
287 */
288 template<typename AstNodeT>
289 static decltype(auto) makeScriptList(AstNodeT *ast)
290 {
291 auto myExp =
292 ScriptElements::ScriptList(ast->firstSourceLocation(), ast->lastSourceLocation());
293 return myExp;
294 }
295
296 template<typename ScriptElementT>
297 void pushScriptElement(const ScriptElementT &element)
298 {
299 Q_ASSERT_X(m_enableScriptExpressions, "pushScriptElement",
300 "Cannot create script elements when they are disabled!");
301 scriptNodeStack.append(ScriptStackElement::from(element));
302 }
303
304 void disableScriptElements()
305 {
306 m_enableScriptExpressions = false;
307 scriptNodeStack.clear();
308 }
309
310 ScriptElementVariant scriptElementForQualifiedId(AST::UiQualifiedId *expression);
311
312public:
313 explicit QQmlDomAstCreator(const MutableDomItem &qmlFile);
314
315 bool visit(AST::UiProgram *program) override;
316 void endVisit(AST::UiProgram *) override;
317
318 bool visit(AST::UiPragma *el) override;
319
320 bool visit(AST::UiImport *el) override;
321
322 bool visit(AST::UiPublicMember *el) override;
323 void endVisit(AST::UiPublicMember *el) override;
324
325private:
326 ScriptElementVariant prepareBodyForFunction(AST::FunctionExpression *fExpression);
327
328public:
329 bool visit(AST::FunctionExpression *el) override;
330 void endVisit(AST::FunctionExpression *) override;
331
332 bool visit(AST::FunctionDeclaration *el) override;
333 void endVisit(AST::FunctionDeclaration *) override;
334
335 bool visit(AST::UiSourceElement *el) override;
336 void endVisit(AST::UiSourceElement *) override;
337
338 void loadAnnotations(AST::UiObjectMember *el) { AST::Node::accept(node: el->annotations, visitor: this); }
339
340 bool visit(AST::UiObjectDefinition *el) override;
341 void endVisit(AST::UiObjectDefinition *) override;
342
343 bool visit(AST::UiObjectBinding *el) override;
344 void endVisit(AST::UiObjectBinding *) override;
345
346 bool visit(AST::UiScriptBinding *el) override;
347 void endVisit(AST::UiScriptBinding *) override;
348
349 bool visit(AST::UiArrayBinding *el) override;
350 void endVisit(AST::UiArrayBinding *) override;
351
352 bool visit(AST::UiQualifiedId *) override;
353
354 bool visit(AST::UiEnumDeclaration *el) override;
355 void endVisit(AST::UiEnumDeclaration *) override;
356
357 bool visit(AST::UiEnumMemberList *el) override;
358 void endVisit(AST::UiEnumMemberList *el) override;
359
360 bool visit(AST::UiInlineComponent *el) override;
361 void endVisit(AST::UiInlineComponent *) override;
362
363 bool visit(AST::UiRequired *el) override;
364
365 bool visit(AST::UiAnnotation *el) override;
366 void endVisit(AST::UiAnnotation *) override;
367
368 // for Script elements:
369 bool visit(AST::BinaryExpression *exp) override;
370 void endVisit(AST::BinaryExpression *exp) override;
371
372 bool visit(AST::Block *block) override;
373 void endVisit(AST::Block *) override;
374
375 bool visit(AST::YieldExpression *block) override;
376 void endVisit(AST::YieldExpression *) override;
377
378 bool visit(AST::ReturnStatement *block) override;
379 void endVisit(AST::ReturnStatement *) override;
380
381 bool visit(AST::ForStatement *forStatement) override;
382 void endVisit(AST::ForStatement *forStatement) override;
383
384 bool visit(AST::PatternElement *pe) override;
385 void endVisit(AST::PatternElement *pe) override;
386 void endVisitHelper(AST::PatternElement *pe,
387 const std::shared_ptr<ScriptElements::GenericScriptElement> &element);
388
389 bool visit(AST::IfStatement *) override;
390 void endVisit(AST::IfStatement *) override;
391
392 bool visit(AST::FieldMemberExpression *) override;
393 void endVisit(AST::FieldMemberExpression *) override;
394
395 bool visit(AST::ArrayMemberExpression *) override;
396 void endVisit(AST::ArrayMemberExpression *) override;
397
398 bool visit(AST::CallExpression *) override;
399 void endVisit(AST::CallExpression *) override;
400
401 bool visit(AST::ArrayPattern *) override;
402 void endVisit(AST::ArrayPattern *) override;
403
404 bool visit(AST::ObjectPattern *) override;
405 void endVisit(AST::ObjectPattern *) override;
406
407 bool visit(AST::PatternProperty *) override;
408 void endVisit(AST::PatternProperty *) override;
409
410 bool visit(AST::VariableStatement *) override;
411 void endVisit(AST::VariableStatement *) override;
412
413 bool visit(AST::Type *expression) override;
414 void endVisit(AST::Type *expression) override;
415
416 bool visit(AST::DefaultClause *) override;
417 void endVisit(AST::DefaultClause *) override;
418
419 bool visit(AST::CaseClause *) override;
420 void endVisit(AST::CaseClause *) override;
421
422 bool visit(AST::CaseClauses *) override;
423 void endVisit(AST::CaseClauses *) override;
424
425 bool visit(AST::CaseBlock *) override;
426 void endVisit(AST::CaseBlock *) override;
427
428 bool visit(AST::SwitchStatement *) override;
429 void endVisit(AST::SwitchStatement *) override;
430
431 bool visit(AST::WhileStatement *) override;
432 void endVisit(AST::WhileStatement *) override;
433
434 bool visit(AST::DoWhileStatement *) override;
435 void endVisit(AST::DoWhileStatement *) override;
436
437 bool visit(AST::ForEachStatement *) override;
438 void endVisit(AST::ForEachStatement *) override;
439
440 bool visit(AST::ClassExpression *) override;
441 void endVisit(AST::ClassExpression *) override;
442
443 bool visit(AST::TryStatement *) override;
444 void endVisit(AST::TryStatement *) override;
445
446 bool visit(AST::Catch *) override;
447 void endVisit(AST::Catch *) override;
448
449 bool visit(AST::Finally *) override;
450 void endVisit(AST::Finally *) override;
451
452 bool visit(AST::ThrowStatement *) override;
453 void endVisit(AST::ThrowStatement *) override;
454
455 bool visit(AST::LabelledStatement *) override;
456 void endVisit(AST::LabelledStatement *) override;
457
458 bool visit(AST::ContinueStatement *) override;
459 void endVisit(AST::ContinueStatement *) override;
460
461 bool visit(AST::BreakStatement *) override;
462 void endVisit(AST::BreakStatement *) override;
463
464 bool visit(AST::Expression *) override;
465 void endVisit(AST::Expression *) override;
466
467 bool visit(AST::ConditionalExpression *) override;
468 void endVisit(AST::ConditionalExpression *) override;
469
470 bool visit(AST::UnaryMinusExpression *) override;
471 void endVisit(AST::UnaryMinusExpression *) override;
472
473 bool visit(AST::UnaryPlusExpression *) override;
474 void endVisit(AST::UnaryPlusExpression *) override;
475
476 bool visit(AST::TildeExpression *) override;
477 void endVisit(AST::TildeExpression *) override;
478
479 bool visit(AST::NotExpression *) override;
480 void endVisit(AST::NotExpression *) override;
481
482 bool visit(AST::TypeOfExpression *) override;
483 void endVisit(AST::TypeOfExpression *) override;
484
485 bool visit(AST::DeleteExpression *) override;
486 void endVisit(AST::DeleteExpression *) override;
487
488 bool visit(AST::VoidExpression *) override;
489 void endVisit(AST::VoidExpression *) override;
490
491 bool visit(AST::PostDecrementExpression *) override;
492 void endVisit(AST::PostDecrementExpression *) override;
493
494 bool visit(AST::PostIncrementExpression *) override;
495 void endVisit(AST::PostIncrementExpression *) override;
496
497 bool visit(AST::PreDecrementExpression *) override;
498 void endVisit(AST::PreDecrementExpression *) override;
499
500 bool visit(AST::PreIncrementExpression *) override;
501 void endVisit(AST::PreIncrementExpression *) override;
502
503 bool visit(AST::EmptyStatement *) override;
504 void endVisit(AST::EmptyStatement *) override;
505
506 bool visit(AST::NestedExpression *) override;
507 void endVisit(AST::NestedExpression *) override;
508
509 bool visit(AST::NewExpression *) override;
510 void endVisit(AST::NewExpression *) override;
511
512 bool visit(AST::NewMemberExpression *) override;
513 void endVisit(AST::NewMemberExpression *) override;
514
515 // lists of stuff whose children don't need a qqmljsscope: visitation order can be custom
516 bool visit(AST::UiParameterList *) override;
517 bool visit(AST::Elision *elision) override;
518
519
520 // lists of stuff whose children need a qqmljsscope: visitation order cannot be custom
521 void endVisit(AST::StatementList *list) override;
522 void endVisit(AST::VariableDeclarationList *vdl) override;
523 void endVisit(AST::ArgumentList *) override;
524 void endVisit(AST::PatternElementList *) override;
525 void endVisit(AST::PatternPropertyList *) override;
526 void endVisit(AST::FormalParameterList *el) override;
527 void endVisit(AST::TemplateLiteral *) override;
528 void endVisit(AST::TaggedTemplate *) override;
529
530
531 // literals and ids
532 bool visit(AST::IdentifierExpression *expression) override;
533 bool visit(AST::NumericLiteral *expression) override;
534 bool visit(AST::StringLiteral *expression) override;
535 bool visit(AST::NullExpression *expression) override;
536 bool visit(AST::TrueLiteral *expression) override;
537 bool visit(AST::FalseLiteral *expression) override;
538 bool visit(AST::ComputedPropertyName *expression) override;
539 bool visit(AST::IdentifierPropertyName *expression) override;
540 bool visit(AST::NumericLiteralPropertyName *expression) override;
541 bool visit(AST::StringLiteralPropertyName *expression) override;
542 bool visit(AST::TypeAnnotation *expression) override;
543 bool visit(AST::RegExpLiteral *) override;
544 bool visit(AST::ThisExpression *) override;
545 bool visit(AST::SuperLiteral *) override;
546
547 void throwRecursionDepthError() override;
548
549 bool stackHasScriptVariant() const
550 {
551 return !scriptNodeStack.isEmpty() && !scriptNodeStack.last().isList();
552 }
553 bool stackHasScriptList() const
554 {
555 return !scriptNodeStack.isEmpty() && scriptNodeStack.last().isList();
556 }
557
558private:
559 template<typename T>
560 void endVisitForLists(T *list, const std::function<int(T *)> &scriptElementsPerEntry = {});
561
562public:
563 friend class QQmlDomAstCreatorWithQQmlJSScope;
564};
565
566class QQmlDomAstCreatorWithQQmlJSScope : public AST::Visitor
567{
568public:
569 QQmlDomAstCreatorWithQQmlJSScope(const QQmlJSScope::Ptr &current, MutableDomItem &qmlFile,
570 QQmlJSLogger *logger, QQmlJSImporter *importer);
571
572#define X(name) \
573 bool visit(AST::name *) override; \
574 void endVisit(AST::name *) override;
575 QQmlJSASTClassListToVisit
576#undef X
577
578 virtual void throwRecursionDepthError() override;
579 /*!
580 \internal
581 Disable the DOM for scriptexpressions, as not yet unimplemented script elements might crash
582 the construction.
583 */
584 void enableScriptExpressions(bool enable = true)
585 {
586 m_enableScriptExpressions = enable;
587 m_domCreator.enableScriptExpressions(enable);
588 }
589
590 void enableLoadFileLazily(bool enable = true)
591 {
592 m_loadFileLazily = enable;
593 m_domCreator.enableLoadFileLazily(enable);
594 }
595
596 QQmlJSImportVisitor &scopeCreator() { return m_scopeCreator; }
597
598private:
599 void setScopeInDomAfterEndvisit();
600 void setScopeInDomBeforeEndvisit();
601
602 template<typename U, typename... V>
603 using IsInList = std::disjunction<std::is_same<U, V>...>;
604 template<typename U>
605 using RequiresCustomIteration =
606 IsInList<U, AST::PatternElementList, AST::PatternPropertyList, AST::FormalParameterList,
607 AST::VariableDeclarationList, AST::TemplateLiteral>;
608
609 enum VisitorKind : bool { DomCreator, ScopeCreator };
610 /*! \internal
611 \brief Holds the information to reactivate a visitor
612 This struct tracks a visitor during its inactive phases
613 and holds the information needed to reactivate the visitor.
614 */
615 struct InactiveVisitorMarker
616 {
617 qsizetype count;
618 AST::Node::Kind nodeKind;
619 VisitorKind inactiveVisitorKind;
620
621 VisitorKind stillActiveVisitorKind() const
622 {
623 return inactiveVisitorKind == DomCreator ? ScopeCreator : DomCreator;
624 }
625 };
626
627 template<typename T>
628 void customListIteration(T *t)
629 {
630 static_assert(RequiresCustomIteration<T>::value);
631 for (T* it = t; it; it = it->next) {
632 if constexpr (std::is_same_v<T, AST::PatternElementList>) {
633 AST::Node::accept(it->elision, this);
634 AST::Node::accept(it->element, this);
635 } else if constexpr (std::is_same_v<T, AST::PatternPropertyList>) {
636 AST::Node::accept(it->property, this);
637 } else if constexpr (std::is_same_v<T, AST::FormalParameterList>) {
638 AST::Node::accept(it->element, this);
639 } else if constexpr (std::is_same_v<T, AST::VariableDeclarationList>) {
640 AST::Node::accept(it->declaration, this);
641 } else if constexpr (std::is_same_v<T, AST::ArgumentList>) {
642 AST::Node::accept(it->expression, this);
643 } else if constexpr (std::is_same_v<T, AST::PatternElementList>) {
644 AST::Node::accept(it->elision, this);
645 AST::Node::accept(it->element, this);
646 } else if constexpr (std::is_same_v<T, AST::TemplateLiteral>) {
647 AST::Node::accept(it->expression, this);
648 } else {
649 Q_UNREACHABLE();
650 }
651 }
652 }
653
654 static void initMarkerForActiveVisitor(std::optional<InactiveVisitorMarker> &inactiveVisitorMarker,
655 AST::Node::Kind nodeKind, bool continueForDom)
656 {
657 inactiveVisitorMarker.emplace();
658 inactiveVisitorMarker->inactiveVisitorKind = continueForDom ? ScopeCreator : DomCreator;
659 inactiveVisitorMarker->count = 1;
660 inactiveVisitorMarker->nodeKind = nodeKind;
661 };
662
663 template<typename T>
664 bool performListIterationIfRequired(T *t)
665 {
666 if constexpr (RequiresCustomIteration<T>::value) {
667 customListIteration(t);
668 return false;
669 }
670 Q_UNUSED(t);
671 return true;
672 }
673
674 template<typename T>
675 bool visitT(T *t)
676 {
677 const auto handleVisitResult = [this, t](const bool continueVisit) {
678 if (m_inactiveVisitorMarker && m_inactiveVisitorMarker->nodeKind == t->kind)
679 m_inactiveVisitorMarker->count += 1;
680
681 if (continueVisit)
682 return performListIterationIfRequired(t);
683 return continueVisit;
684 };
685
686 // first case: no marker, both can visit
687 if (!m_inactiveVisitorMarker) {
688 bool continueForDom = m_domCreator.visit(t);
689 bool continueForScope = m_scopeCreator.visit(t);
690 if (!continueForDom && !continueForScope)
691 return false;
692 else if (continueForDom ^ continueForScope) {
693 initMarkerForActiveVisitor(inactiveVisitorMarker&: m_inactiveVisitorMarker, nodeKind: AST::Node::Kind(t->kind),
694 continueForDom);
695 return performListIterationIfRequired(t);
696 } else {
697 Q_ASSERT(continueForDom && continueForScope);
698 return performListIterationIfRequired(t);
699 }
700 Q_UNREACHABLE();
701 }
702
703 // second case: a marker, just one visit
704 switch (m_inactiveVisitorMarker->stillActiveVisitorKind()) {
705 case DomCreator:
706 return handleVisitResult(m_domCreator.visit(t));
707 case ScopeCreator:
708 return handleVisitResult(m_scopeCreator.visit(t));
709 };
710 Q_UNREACHABLE();
711 }
712
713 template<typename T>
714 void endVisitT(T *t)
715 {
716 if (m_inactiveVisitorMarker && m_inactiveVisitorMarker->nodeKind == t->kind) {
717 m_inactiveVisitorMarker->count -= 1;
718 if (m_inactiveVisitorMarker->count == 0)
719 m_inactiveVisitorMarker.reset();
720 }
721 if (m_inactiveVisitorMarker) {
722 switch (m_inactiveVisitorMarker->stillActiveVisitorKind()) {
723 case DomCreator:
724 m_domCreator.endVisit(t);
725 return;
726 case ScopeCreator:
727 m_scopeCreator.endVisit(t);
728 return;
729 };
730 Q_UNREACHABLE();
731 }
732
733 setScopeInDomBeforeEndvisit();
734 m_domCreator.endVisit(t);
735 setScopeInDomAfterEndvisit();
736 m_scopeCreator.endVisit(t);
737 }
738
739 QQmlJSScope::Ptr m_root;
740 QQmlJSLogger *m_logger = nullptr;
741 QQmlJSImporter *m_importer = nullptr;
742 QString m_implicitImportDirectory;
743 QQmlJSImportVisitor m_scopeCreator;
744 QQmlDomAstCreator m_domCreator;
745
746 std::optional<InactiveVisitorMarker> m_inactiveVisitorMarker;
747 bool m_enableScriptExpressions = false;
748 bool m_loadFileLazily = false;
749};
750
751} // end namespace Dom
752} // end namespace QQmlJS
753
754QT_END_NAMESPACE
755#endif // QQMLDOMASTCREATOR_P_H
756

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtdeclarative/src/qmldom/qqmldomastcreator_p.h