• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef ES2PANDA_IR_AST_NODE_H
17 #define ES2PANDA_IR_AST_NODE_H
18 
19 #include "es2panda.h"
20 #include "astNodeFlags.h"
21 #include "astNodeMapping.h"
22 #include "ir/visitor/AstVisitor.h"
23 #include "lexer/token/sourceLocation.h"
24 #include "util/es2pandaMacros.h"
25 
26 namespace ark::es2panda::compiler {
27 class PandaGen;
28 class ETSGen;
29 }  // namespace ark::es2panda::compiler
30 
31 namespace ark::es2panda::checker {
32 class TSChecker;
33 class ETSChecker;
34 class Type;
35 class VerifiedType;
36 }  // namespace ark::es2panda::checker
37 
38 namespace ark::es2panda::varbinder {
39 class Variable;
40 class Scope;
41 }  // namespace ark::es2panda::varbinder
42 
43 namespace ark::es2panda::ir {
44 // NOLINTBEGIN(modernize-avoid-c-arrays)
45 inline constexpr char const CLONE_ALLOCATION_ERROR[] = "Unsuccessful allocation during cloning.";
46 // NOLINTEND(modernize-avoid-c-arrays)
47 
48 class AstNode;
49 class TypeNode;
50 
51 using NodeTransformer = std::function<AstNode *(AstNode *)>;
52 using NodeTraverser = std::function<void(AstNode *)>;
53 using NodePredicate = std::function<bool(AstNode *)>;
54 
55 enum class AstNodeType {
56 /* CC-OFFNXT(G.PRE.02,G.PRE.09) name part*/
57 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
58 #define DECLARE_NODE_TYPES(nodeType, className) nodeType,
59     AST_NODE_MAPPING(DECLARE_NODE_TYPES)
60 #undef DECLARE_NODE_TYPES
61 /* CC-OFFNXT(G.PRE.02,G.PRE.09) name part*/
62 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
63 #define DECLARE_NODE_TYPES(nodeType1, nodeType2, baseClass, reinterpretClass) nodeType1, nodeType2,
64         AST_NODE_REINTERPRET_MAPPING(DECLARE_NODE_TYPES)
65 #undef DECLARE_NODE_TYPES
66 };
67 
68 // CC-OFFNXT(G.PRE.02) code generation
69 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
70 #define STRING_FROM_NODE_TYPE(nodeType, className)                          \
71     case AstNodeType::nodeType: { /* CC-OFF(G.PRE.02) qualified name part*/ \
72         return #nodeType;         /* CC-OFF(G.PRE.05) function gen */       \
73     }
74 // CC-OFFNXT(G.PRE.02) code generation
75 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
76 #define STRING_FROM_NODE_TYPE_REINTERPRET(nodeType1, nodeType2, baseClass, reinterpretClass) \
77     case AstNodeType::nodeType1: { /* CC-OFF(G.PRE.02) qualified name part*/                 \
78         return #nodeType1;         /* CC-OFF(G.PRE.05) function gen */                       \
79     }                                                                                        \
80     case AstNodeType::nodeType2: { /* CC-OFF(G.PRE.02) qualified name part*/                 \
81         return #nodeType2;         /* CC-OFF(G.PRE.05) function gen */                       \
82     }
83 
ToString(AstNodeType nodeType)84 inline std::string_view ToString(AstNodeType nodeType)
85 {
86     switch (nodeType) {
87         AST_NODE_MAPPING(STRING_FROM_NODE_TYPE)
88         AST_NODE_REINTERPRET_MAPPING(STRING_FROM_NODE_TYPE_REINTERPRET)
89         default:
90             LOG(FATAL, ES2PANDA) << "Invalid 'AstNodeType'";
91             ES2PANDA_UNREACHABLE();
92     }
93 }
94 
95 #undef STRING_FROM_NODE_TYPE
96 #undef STRING_FROM_NODE_TYPE
97 
98 // Forward declarations
99 class AstDumper;
100 class Expression;
101 class SrcDumper;
102 class Statement;
103 class ClassElement;
104 template <typename T>
105 class Typed;
106 
107 /* CC-OFFNXT(G.PRE.02) name part*/
108 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
109 #define DECLARE_CLASSES(nodeType, className) class className; /* CC-OFF(G.PRE.09) code gen*/
110 AST_NODE_MAPPING(DECLARE_CLASSES)
111 #undef DECLARE_CLASSES
112 
113 /* CC-OFFNXT(G.PRE.02,G.PRE.09) name part code gen*/
114 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
115 #define DECLARE_CLASSES(nodeType1, nodeType2, baseClass, reinterpretClass) class baseClass;
AST_NODE_REINTERPRET_MAPPING(DECLARE_CLASSES)116 AST_NODE_REINTERPRET_MAPPING(DECLARE_CLASSES)
117 #undef DECLARE_CLASSES
118 
119 class AstNode {
120 public:
121     explicit AstNode(AstNodeType type) : type_(type) {};
122     explicit AstNode(AstNodeType type, ModifierFlags flags) : type_(type), flags_(flags) {};
123     virtual ~AstNode() = default;
124 
125     AstNode() = delete;
126     NO_MOVE_SEMANTIC(AstNode);
127 
128     bool IsProgram() const
129     {
130         return parent_ == nullptr;
131     }
132 
133 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
134 #define DECLARE_IS_CHECKS(nodeType, className)                                               \
135     bool Is##className() const                                                               \
136     {                                                                                        \
137         /* CC-OFFNXT(G.PRE.02) name part*/                                                   \
138         /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed */ \
139         return type_ == AstNodeType::nodeType; /* CC-OFF(G.PRE.02) name part*/               \
140     }
141     AST_NODE_MAPPING(DECLARE_IS_CHECKS)
142 #undef DECLARE_IS_CHECKS
143 
144 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
145 #define DECLARE_IS_CHECKS(nodeType1, nodeType2, baseClass, reinterpretClass)                 \
146     bool Is##baseClass() const                                                               \
147     {                                                                                        \
148         /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed */ \
149         return type_ == AstNodeType::nodeType1; /* CC-OFF(G.PRE.02) name part*/              \
150     }                                                                                        \
151     bool Is##reinterpretClass() const                                                        \
152     {                                                                                        \
153         /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed */ \
154         return type_ == AstNodeType::nodeType2; /* CC-OFF(G.PRE.02) name part*/              \
155     }
156     AST_NODE_REINTERPRET_MAPPING(DECLARE_IS_CHECKS)
157 #undef DECLARE_IS_CHECKS
158 
159     [[nodiscard]] virtual bool IsStatement() const noexcept
160     {
161         return false;
162     }
163 
164     [[nodiscard]] virtual bool IsExpression() const noexcept
165     {
166         return false;
167     }
168 
169     virtual bool IsTyped() const
170     {
171         return false;
172     }
173 
174     Typed<AstNode> *AsTyped()
175     {
176         ES2PANDA_ASSERT(IsTyped());
177         return reinterpret_cast<Typed<AstNode> *>(this);
178     }
179 
180     Typed<AstNode> const *AsTyped() const
181     {
182         ES2PANDA_ASSERT(IsTyped());
183         return reinterpret_cast<Typed<AstNode> const *>(this);
184     }
185 
186     bool IsBrokenStatement() const
187     {
188         return IsEmptyStatement();
189     }
190 
191 /* CC-OFFNXT(G.PRE.06) solid logic */
192 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
193 #define DECLARE_AS_CASTS(nodeType, className)                                                         \
194     /* CC-OFFNXT(G.PRE.02) name part*/                                                                \
195     className *As##className()                                                                        \
196     {                                                                                                 \
197         ES2PANDA_ASSERT(Is##className());                                                             \
198         /* CC-OFFNXT(G.PRE.05,G.PRE.02) The macro is used to generate a function. Return is needed */ \
199         return reinterpret_cast<className *>(this);                                                   \
200     }                                                                                                 \
201     const className *As##className() const                                                            \
202     {                                                                                                 \
203         ES2PANDA_ASSERT(Is##className());                                                             \
204         /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed */          \
205         return reinterpret_cast<const className *>(this);                                             \
206     }
207     AST_NODE_MAPPING(DECLARE_AS_CASTS)
208 #undef DECLARE_AS_CASTS
209 
210 /* CC-OFFNXT(G.PRE.06) solid logic */
211 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
212 #define DECLARE_AS_CASTS(nodeType1, nodeType2, baseClass, reinterpretClass)                           \
213     /* CC-OFFNXT(G.PRE.02) name part*/                                                                \
214     baseClass *As##baseClass()                                                                        \
215     {                                                                                                 \
216         ES2PANDA_ASSERT(Is##baseClass());                                                             \
217         /* CC-OFFNXT(G.PRE.05,G.PRE.02) The macro is used to generate a function. Return is needed */ \
218         return reinterpret_cast<baseClass *>(this);                                                   \
219     }                                                                                                 \
220     /* CC-OFFNXT(G.PRE.02) name part*/                                                                \
221     baseClass *As##reinterpretClass()                                                                 \
222     {                                                                                                 \
223         ES2PANDA_ASSERT(Is##reinterpretClass());                                                      \
224         /* CC-OFFNXT(G.PRE.05,G.PRE.02) The macro is used to generate a function. Return is needed */ \
225         return reinterpret_cast<baseClass *>(this);                                                   \
226     }                                                                                                 \
227     const baseClass *As##baseClass() const                                                            \
228     {                                                                                                 \
229         ES2PANDA_ASSERT(Is##baseClass());                                                             \
230         /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed */          \
231         return reinterpret_cast<const baseClass *>(this);                                             \
232     }                                                                                                 \
233     const baseClass *As##reinterpretClass() const                                                     \
234     {                                                                                                 \
235         ES2PANDA_ASSERT(Is##reinterpretClass());                                                      \
236         /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed */          \
237         return reinterpret_cast<const baseClass *>(this);                                             \
238     }
239     AST_NODE_REINTERPRET_MAPPING(DECLARE_AS_CASTS)
240 #undef DECLARE_AS_CASTS
241 
242     Expression *AsExpression()
243     {
244         ES2PANDA_ASSERT(IsExpression());
245         return reinterpret_cast<Expression *>(this);
246     }
247 
248     const Expression *AsExpression() const
249     {
250         ES2PANDA_ASSERT(IsExpression());
251         return reinterpret_cast<const Expression *>(this);
252     }
253 
254     Statement *AsStatement()
255     {
256         ES2PANDA_ASSERT(IsStatement());
257         return reinterpret_cast<Statement *>(this);
258     }
259 
260     const Statement *AsStatement() const
261     {
262         ES2PANDA_ASSERT(IsStatement());
263         return reinterpret_cast<const Statement *>(this);
264     }
265 
266     void SetRange(const lexer::SourceRange &loc) noexcept
267     {
268         range_ = loc;
269     }
270 
271     void SetStart(const lexer::SourcePosition &start) noexcept
272     {
273         range_.start = start;
274     }
275 
276     void SetEnd(const lexer::SourcePosition &end) noexcept
277     {
278         range_.end = end;
279     }
280 
281     [[nodiscard]] const lexer::SourcePosition &Start() const noexcept
282     {
283         return range_.start;
284     }
285 
286     [[nodiscard]] const lexer::SourcePosition &End() const noexcept
287     {
288         return range_.end;
289     }
290 
291     [[nodiscard]] const lexer::SourceRange &Range() const noexcept
292     {
293         return range_;
294     }
295 
296     [[nodiscard]] AstNodeType Type() const noexcept
297     {
298         return type_;
299     }
300 
301     [[nodiscard]] AstNode *Parent() noexcept
302     {
303         return parent_;
304     }
305 
306     [[nodiscard]] const AstNode *Parent() const noexcept
307     {
308         return parent_;
309     }
310 
311     void SetParent(AstNode *const parent) noexcept
312     {
313         parent_ = parent;
314     }
315 
316     [[nodiscard]] varbinder::Variable *Variable() const noexcept
317     {
318         return variable_;
319     }
320 
321     void SetVariable(varbinder::Variable *variable) noexcept
322     {
323         variable_ = variable;
324     }
325 
326     // When no decorators are allowed, we cannot return a reference to an empty vector.
327     virtual const ArenaVector<ir::Decorator *> *DecoratorsPtr() const
328     {
329         return nullptr;
330     }
331 
332     virtual void AddDecorators([[maybe_unused]] ArenaVector<ir::Decorator *> &&decorators)
333     {
334         ES2PANDA_UNREACHABLE();
335     }
336 
337     virtual bool CanHaveDecorator([[maybe_unused]] bool inTs) const
338     {
339         return false;
340     }
341 
342     [[nodiscard]] bool IsReadonly() const noexcept;
343 
344     // NOTE: For readonly parameter type
345     [[nodiscard]] bool IsReadonlyType() const noexcept;
346 
347     [[nodiscard]] bool IsOptionalDeclaration() const noexcept;
348 
349     [[nodiscard]] bool IsDefinite() const noexcept;
350 
351     [[nodiscard]] bool IsConstructor() const noexcept;
352 
353     [[nodiscard]] bool IsOverride() const noexcept;
354 
355     void SetOverride() noexcept
356     {
357         flags_ |= ModifierFlags::OVERRIDE;
358     }
359 
360     [[nodiscard]] bool IsAsync() const noexcept
361     {
362         return (flags_ & ModifierFlags::ASYNC) != 0;
363     }
364 
365     [[nodiscard]] bool IsSynchronized() const noexcept
366     {
367         return (flags_ & ModifierFlags::SYNCHRONIZED) != 0;
368     }
369 
370     [[nodiscard]] bool IsNative() const noexcept
371     {
372         return (flags_ & ModifierFlags::NATIVE) != 0;
373     }
374 
375     [[nodiscard]] bool IsConst() const noexcept
376     {
377         return (flags_ & ModifierFlags::CONST) != 0;
378     }
379 
380     [[nodiscard]] bool IsStatic() const noexcept
381     {
382         return (flags_ & ModifierFlags::STATIC) != 0;
383     }
384 
385     [[nodiscard]] bool IsFinal() const noexcept
386     {
387         return (flags_ & ModifierFlags::FINAL) != 0U;
388     }
389 
390     [[nodiscard]] bool IsAbstract() const noexcept
391     {
392         return (flags_ & ModifierFlags::ABSTRACT) != 0;
393     }
394 
395     [[nodiscard]] bool IsPublic() const noexcept
396     {
397         return (flags_ & ModifierFlags::PUBLIC) != 0;
398     }
399 
400     [[nodiscard]] bool IsProtected() const noexcept
401     {
402         return (flags_ & ModifierFlags::PROTECTED) != 0;
403     }
404 
405     [[nodiscard]] bool IsPrivate() const noexcept
406     {
407         return (flags_ & ModifierFlags::PRIVATE) != 0;
408     }
409 
410     [[nodiscard]] bool IsInternal() const noexcept
411     {
412         return (flags_ & ModifierFlags::INTERNAL) != 0;
413     }
414 
415     [[nodiscard]] bool IsExported() const noexcept;
416 
417     [[nodiscard]] bool IsDefaultExported() const noexcept;
418 
419     [[nodiscard]] bool IsExportedType() const noexcept;
420 
421     [[nodiscard]] bool IsDeclare() const noexcept
422     {
423         return (flags_ & ModifierFlags::DECLARE) != 0;
424     }
425 
426     [[nodiscard]] bool IsIn() const noexcept
427     {
428         return (flags_ & ModifierFlags::IN) != 0;
429     }
430 
431     [[nodiscard]] bool IsOut() const noexcept
432     {
433         return (flags_ & ModifierFlags::OUT) != 0;
434     }
435 
436     [[nodiscard]] bool IsSetter() const noexcept
437     {
438         return (flags_ & ModifierFlags::SETTER) != 0;
439     }
440 
441     void AddModifier(ModifierFlags const flags) noexcept
442     {
443         flags_ |= flags;
444     }
445 
446     void ClearModifier(ModifierFlags const flags) noexcept
447     {
448         flags_ &= ~flags;
449     }
450 
451     [[nodiscard]] ModifierFlags Modifiers() noexcept
452     {
453         return flags_;
454     }
455 
456     [[nodiscard]] ModifierFlags Modifiers() const noexcept
457     {
458         return flags_;
459     }
460 
461     [[nodiscard]] bool HasExportAlias() const noexcept;
462     // CC-OFFNXT(G.PRE.06) solid logic
463     // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
464 #define DECLARE_FLAG_OPERATIONS(flag_type, member_name)                                     \
465     void Set##flag_type(flag_type flags) const noexcept                                     \
466     {                                                                                       \
467         (member_name) = flags;                                                              \
468     }                                                                                       \
469                                                                                             \
470     void Add##flag_type(flag_type flag) const noexcept                                      \
471     {                                                                                       \
472         (member_name) |= flag;                                                              \
473     }                                                                                       \
474                                                                                             \
475     [[nodiscard]] flag_type Get##flag_type() const noexcept                                 \
476     {                                                                                       \
477         /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed*/ \
478         return (member_name);                                                               \
479     }                                                                                       \
480                                                                                             \
481     bool Has##flag_type(flag_type flag) const noexcept                                      \
482     {                                                                                       \
483         /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed*/ \
484         return ((member_name)&flag) != 0U;                                                  \
485     }                                                                                       \
486     void Remove##flag_type(flag_type flag) const noexcept                                   \
487     {                                                                                       \
488         (member_name) &= ~flag;                                                             \
489     }
490 
491     DECLARE_FLAG_OPERATIONS(BoxingUnboxingFlags, boxingUnboxingFlags_);
492     DECLARE_FLAG_OPERATIONS(AstNodeFlags, astNodeFlags_);
493 #undef DECLARE_FLAG_OPERATIONS
494 
495     ir::ClassElement *AsClassElement();
496     const ir::ClassElement *AsClassElement() const;
497 
498     [[nodiscard]] static varbinder::Scope *EnclosingScope(const ir::AstNode *expr) noexcept;
499 
500     [[nodiscard]] virtual bool IsScopeBearer() const noexcept;
501     [[nodiscard]] virtual varbinder::Scope *Scope() const noexcept;
502 
503     virtual void ClearScope() noexcept;
504 
505     [[nodiscard]] ir::BlockStatement *GetTopStatement();
506     [[nodiscard]] const ir::BlockStatement *GetTopStatement() const;
507 
508     [[nodiscard]] virtual AstNode *Clone(ArenaAllocator *const allocator, AstNode *const parent);
509 
510     virtual void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) = 0;
511     virtual void Iterate(const NodeTraverser &cb) const = 0;
512 
513     void TransformChildrenRecursively(const NodeTransformer &cb, std::string_view transformationName);
514     void TransformChildrenRecursivelyPreorder(const NodeTransformer &cb, std::string_view transformationName);
515     void TransformChildrenRecursivelyPostorder(const NodeTransformer &cb, std::string_view transformationName);
516 
517     void IterateRecursively(const NodeTraverser &cb) const;
518     void IterateRecursivelyPreorder(const NodeTraverser &cb) const;
519     void IterateRecursivelyPostorder(const NodeTraverser &cb) const;
520 
521     bool IsAnyChild(const NodePredicate &cb) const;
522     AstNode *FindChild(const NodePredicate &cb) const;
523 
524     std::string DumpJSON() const;
525     std::string DumpEtsSrc() const;
526     std::string DumpDecl() const;
527     std::string IsolatedDumpDecl() const;
528 
529     virtual void Dump(ir::AstDumper *dumper) const = 0;
530     virtual void Dump(ir::SrcDumper *dumper) const = 0;
531     virtual void Compile([[maybe_unused]] compiler::PandaGen *pg) const = 0;
532     virtual void Compile([[maybe_unused]] compiler::ETSGen *etsg) const {};
533     virtual checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) = 0;
534     virtual checker::VerifiedType Check([[maybe_unused]] checker::ETSChecker *checker) = 0;
535 
536     void SetTransformedNode(std::string_view transformationName, AstNode *transformedNode);
537 
538     using ASTVisitorT = visitor::ASTAbstractVisitor;
539 
540     virtual void Accept(ASTVisitorT *v) = 0;
541 
542     /**
543      * On each node you should implement:
544      *  void accept(AV* v) override {
545      *      ASTVisitorT::accept(this, v);
546      *  }
547      */
548     void SetOriginalNode(AstNode *originalNode) noexcept;
549     AstNode *OriginalNode() const noexcept;
550 
551     virtual void CleanUp();
552 
553     AstNode *ShallowClone(ArenaAllocator *allocator);
554 
555 protected:
556     AstNode(AstNode const &other);
557 
558     virtual AstNode *Construct([[maybe_unused]] ArenaAllocator *allocator);
559 
560     virtual void CopyTo(AstNode *other) const;
561 
562     void SetType(AstNodeType const type) noexcept
563     {
564         type_ = type;
565     }
566 
567     friend class SizeOfNodeTest;
568     // NOLINTBEGIN(misc-non-private-member-variables-in-classes)
569     AstNode *parent_ {};
570     lexer::SourceRange range_ {};
571     AstNodeType type_;
572     ModifierFlags flags_ {};
573     mutable AstNodeFlags astNodeFlags_ {};
574     mutable BoxingUnboxingFlags boxingUnboxingFlags_ {};
575     // NOLINTEND(misc-non-private-member-variables-in-classes)
576 
577 private:
578     AstNode &operator=(const AstNode &) = default;
579 
580     varbinder::Variable *variable_ {};
581     AstNode *originalNode_ = nullptr;
582     // {lowering_phase_name, new_generated_node}
583     std::optional<std::pair<std::string_view, AstNode *>> transformedNode_ = std::nullopt;
584 };
585 
586 template <typename T>
587 class Annotated : public T {
588 public:
589     Annotated() = delete;
590     ~Annotated() override = default;
591 
592     Annotated &operator=(const Annotated &) = delete;
593     NO_MOVE_SEMANTIC(Annotated);
594 
TypeAnnotation()595     [[nodiscard]] TypeNode *TypeAnnotation() const noexcept
596     {
597         return typeAnnotation_;
598     }
599 
SetTsTypeAnnotation(TypeNode * const typeAnnotation)600     void SetTsTypeAnnotation(TypeNode *const typeAnnotation) noexcept
601     {
602         typeAnnotation_ = typeAnnotation;
603     }
604 
CopyTo(AstNode * other)605     void CopyTo(AstNode *other) const override
606     {
607         auto otherImpl = reinterpret_cast<Annotated<T> *>(other);
608 
609         otherImpl->typeAnnotation_ = typeAnnotation_;
610 
611         T::CopyTo(other);
612     }
613 
614 protected:
Annotated(AstNodeType const type,TypeNode * const typeAnnotation)615     explicit Annotated(AstNodeType const type, TypeNode *const typeAnnotation)
616         : T(type), typeAnnotation_(typeAnnotation)
617     {
618     }
Annotated(AstNodeType const type)619     explicit Annotated(AstNodeType const type) : T(type) {}
Annotated(AstNodeType const type,ModifierFlags const flags)620     explicit Annotated(AstNodeType const type, ModifierFlags const flags) : T(type, flags) {}
621 
Annotated(Annotated const & other)622     Annotated(Annotated const &other) : T(static_cast<T const &>(other)) {}
623 
624 private:
625     friend class SizeOfNodeTest;
626     TypeNode *typeAnnotation_ {};
627 };
628 
629 /**
630  * This class is a wrapper for vector and ensures that vector does not invalidate iterators during iteration.
631  */
632 template <typename T>
633 class VectorIterationGuard {
634 public:
635     using ValueType = typename T::value_type;
636     static_assert(std::is_same_v<std::remove_const_t<T>, ArenaVector<ValueType>>);
637 
VectorIterationGuard(T & vector)638     explicit VectorIterationGuard(T &vector) : vector_(vector), data_(vector_.data(), vector_.size()) {}
639     NO_COPY_SEMANTIC(VectorIterationGuard);
640     NO_MOVE_SEMANTIC(VectorIterationGuard);
641 
~VectorIterationGuard()642     ~VectorIterationGuard()
643     {
644         // check that `begin` iterator remained valid
645         ES2PANDA_ASSERT(data_.begin() == vector_.data());
646         // check that there were no `push_back`s or other expansions which potentially cause reallocation
647         ES2PANDA_ASSERT(data_.size() == vector_.size());
648     }
649 
begin()650     auto begin()  // NOLINT(readability-identifier-naming)
651     {
652         return vector_.begin();
653     }
654 
end()655     auto end()  // NOLINT(readability-identifier-naming)
656     {
657         return vector_.end();
658     }
659 
660 private:
661     T &vector_;
662     Span<const ValueType> data_;
663 };
664 
665 }  // namespace ark::es2panda::ir
666 #endif
667