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