1 //===--- ASTNodeTraverser.h - Traversal of AST nodes ----------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file implements the AST traversal facilities. Other users
10 // of this class may make use of the same traversal logic by inheriting it,
11 // similar to RecursiveASTVisitor.
13 //===----------------------------------------------------------------------===//
15 #ifndef LLVM_CLANG_AST_ASTNODETRAVERSER_H
16 #define LLVM_CLANG_AST_ASTNODETRAVERSER_H
18 #include "clang/AST/AttrVisitor.h"
19 #include "clang/AST/CommentVisitor.h"
20 #include "clang/AST/DeclVisitor.h"
21 #include "clang/AST/LocInfoType.h"
22 #include "clang/AST/StmtVisitor.h"
23 #include "clang/AST/TemplateArgumentVisitor.h"
24 #include "clang/AST/TypeVisitor.h"
30 ASTNodeTraverser traverses the Clang AST for dumping purposes.
32 The `Derived::doGetNodeDelegate()` method is required to be an accessible member
33 which returns a reference of type `NodeDelegateType &` which implements the
37 template <typename Fn> void AddChild(Fn DoAddChild);
38 template <typename Fn> void AddChild(StringRef Label, Fn DoAddChild);
40 void Visit(const comments::Comment *C, const comments::FullComment *FC);
41 void Visit(const Attr *A);
42 void Visit(const TemplateArgument &TA, SourceRange R = {},
43 const Decl *From = nullptr, StringRef Label = {});
44 void Visit(const Stmt *Node);
45 void Visit(const Type *T);
46 void Visit(QualType T);
47 void Visit(const Decl *D);
48 void Visit(const CXXCtorInitializer *Init);
49 void Visit(const OMPClause *C);
50 void Visit(const BlockDecl::Capture &C);
51 void Visit(const GenericSelectionExpr::ConstAssociation &A);
54 template <typename Derived, typename NodeDelegateType>
55 class ASTNodeTraverser
56 : public ConstDeclVisitor<Derived>,
57 public ConstStmtVisitor<Derived>,
58 public comments::ConstCommentVisitor<Derived, void,
59 const comments::FullComment *>,
60 public TypeVisitor<Derived>,
61 public ConstAttrVisitor<Derived>,
62 public ConstTemplateArgumentVisitor<Derived> {
64 /// Indicates whether we should trigger deserialization of nodes that had
65 /// not already been loaded.
66 bool Deserialize = false;
68 ast_type_traits::TraversalKind Traversal =
69 ast_type_traits::TraversalKind::TK_AsIs;
71 NodeDelegateType &getNodeDelegate() {
72 return getDerived().doGetNodeDelegate();
74 Derived &getDerived() { return *static_cast<Derived *>(this); }
77 void setDeserialize(bool D) { Deserialize = D; }
78 bool getDeserialize() const { return Deserialize; }
80 void SetTraversalKind(ast_type_traits::TraversalKind TK) { Traversal = TK; }
82 void Visit(const Decl *D) {
83 getNodeDelegate().AddChild([=] {
84 getNodeDelegate().Visit(D);
88 ConstDeclVisitor<Derived>::Visit(D);
90 for (const auto &A : D->attrs())
93 if (const comments::FullComment *Comment =
94 D->getASTContext().getLocalCommentForDeclUncached(D))
95 Visit(Comment, Comment);
97 // Decls within functions are visited by the body.
98 if (!isa<FunctionDecl>(*D) && !isa<ObjCMethodDecl>(*D)) {
99 if (const auto *DC = dyn_cast<DeclContext>(D))
105 void Visit(const Stmt *Node, StringRef Label = {}) {
106 getNodeDelegate().AddChild(Label, [=] {
107 const Stmt *S = Node;
109 if (auto *E = dyn_cast_or_null<Expr>(S)) {
111 case ast_type_traits::TK_AsIs:
113 case ast_type_traits::TK_IgnoreImplicitCastsAndParentheses:
114 S = E->IgnoreParenImpCasts();
116 case ast_type_traits::TK_IgnoreUnlessSpelledInSource:
117 S = E->IgnoreUnlessSpelledInSource();
122 getNodeDelegate().Visit(S);
128 ConstStmtVisitor<Derived>::Visit(S);
130 // Some statements have custom mechanisms for dumping their children.
131 if (isa<DeclStmt>(S) || isa<GenericSelectionExpr>(S))
134 if (isa<LambdaExpr>(S) &&
135 Traversal == ast_type_traits::TK_IgnoreUnlessSpelledInSource)
138 for (const Stmt *SubStmt : S->children())
143 void Visit(QualType T) {
144 SplitQualType SQT = T.split();
145 if (!SQT.Quals.hasQualifiers())
146 return Visit(SQT.Ty);
148 getNodeDelegate().AddChild([=] {
149 getNodeDelegate().Visit(T);
154 void Visit(const Type *T) {
155 getNodeDelegate().AddChild([=] {
156 getNodeDelegate().Visit(T);
159 TypeVisitor<Derived>::Visit(T);
161 QualType SingleStepDesugar =
162 T->getLocallyUnqualifiedSingleStepDesugaredType();
163 if (SingleStepDesugar != QualType(T, 0))
164 Visit(SingleStepDesugar);
168 void Visit(const Attr *A) {
169 getNodeDelegate().AddChild([=] {
170 getNodeDelegate().Visit(A);
171 ConstAttrVisitor<Derived>::Visit(A);
175 void Visit(const CXXCtorInitializer *Init) {
176 getNodeDelegate().AddChild([=] {
177 getNodeDelegate().Visit(Init);
178 Visit(Init->getInit());
182 void Visit(const TemplateArgument &A, SourceRange R = {},
183 const Decl *From = nullptr, const char *Label = nullptr) {
184 getNodeDelegate().AddChild([=] {
185 getNodeDelegate().Visit(A, R, From, Label);
186 ConstTemplateArgumentVisitor<Derived>::Visit(A);
190 void Visit(const BlockDecl::Capture &C) {
191 getNodeDelegate().AddChild([=] {
192 getNodeDelegate().Visit(C);
194 Visit(C.getCopyExpr());
198 void Visit(const OMPClause *C) {
199 getNodeDelegate().AddChild([=] {
200 getNodeDelegate().Visit(C);
201 for (const auto *S : C->children())
206 void Visit(const GenericSelectionExpr::ConstAssociation &A) {
207 getNodeDelegate().AddChild([=] {
208 getNodeDelegate().Visit(A);
209 if (const TypeSourceInfo *TSI = A.getTypeSourceInfo())
210 Visit(TSI->getType());
211 Visit(A.getAssociationExpr());
215 void Visit(const comments::Comment *C, const comments::FullComment *FC) {
216 getNodeDelegate().AddChild([=] {
217 getNodeDelegate().Visit(C, FC);
221 comments::ConstCommentVisitor<Derived, void,
222 const comments::FullComment *>::visit(C,
224 for (comments::Comment::child_iterator I = C->child_begin(),
231 void Visit(const ast_type_traits::DynTypedNode &N) {
232 // FIXME: Improve this with a switch or a visitor pattern.
233 if (const auto *D = N.get<Decl>())
235 else if (const auto *S = N.get<Stmt>())
237 else if (const auto *QT = N.get<QualType>())
239 else if (const auto *T = N.get<Type>())
241 else if (const auto *C = N.get<CXXCtorInitializer>())
243 else if (const auto *C = N.get<OMPClause>())
245 else if (const auto *T = N.get<TemplateArgument>())
249 void dumpDeclContext(const DeclContext *DC) {
253 for (const auto *D : (Deserialize ? DC->decls() : DC->noload_decls()))
257 void dumpTemplateParameters(const TemplateParameterList *TPL) {
261 for (const auto &TP : *TPL)
264 if (const Expr *RC = TPL->getRequiresClause())
269 dumpASTTemplateArgumentListInfo(const ASTTemplateArgumentListInfo *TALI) {
273 for (const auto &TA : TALI->arguments())
274 dumpTemplateArgumentLoc(TA);
277 void dumpTemplateArgumentLoc(const TemplateArgumentLoc &A,
278 const Decl *From = nullptr,
279 const char *Label = nullptr) {
280 Visit(A.getArgument(), A.getSourceRange(), From, Label);
283 void dumpTemplateArgumentList(const TemplateArgumentList &TAL) {
284 for (unsigned i = 0, e = TAL.size(); i < e; ++i)
288 void dumpObjCTypeParamList(const ObjCTypeParamList *typeParams) {
292 for (const auto &typeParam : *typeParams) {
297 void VisitComplexType(const ComplexType *T) { Visit(T->getElementType()); }
298 void VisitLocInfoType(const LocInfoType *T) {
299 Visit(T->getTypeSourceInfo()->getType());
301 void VisitPointerType(const PointerType *T) { Visit(T->getPointeeType()); }
302 void VisitBlockPointerType(const BlockPointerType *T) {
303 Visit(T->getPointeeType());
305 void VisitReferenceType(const ReferenceType *T) {
306 Visit(T->getPointeeType());
308 void VisitMemberPointerType(const MemberPointerType *T) {
309 Visit(T->getClass());
310 Visit(T->getPointeeType());
312 void VisitArrayType(const ArrayType *T) { Visit(T->getElementType()); }
313 void VisitVariableArrayType(const VariableArrayType *T) {
315 Visit(T->getSizeExpr());
317 void VisitDependentSizedArrayType(const DependentSizedArrayType *T) {
318 Visit(T->getElementType());
319 Visit(T->getSizeExpr());
321 void VisitDependentSizedExtVectorType(const DependentSizedExtVectorType *T) {
322 Visit(T->getElementType());
323 Visit(T->getSizeExpr());
325 void VisitVectorType(const VectorType *T) { Visit(T->getElementType()); }
326 void VisitFunctionType(const FunctionType *T) { Visit(T->getReturnType()); }
327 void VisitFunctionProtoType(const FunctionProtoType *T) {
328 VisitFunctionType(T);
329 for (const QualType &PT : T->getParamTypes())
332 void VisitTypeOfExprType(const TypeOfExprType *T) {
333 Visit(T->getUnderlyingExpr());
335 void VisitDecltypeType(const DecltypeType *T) {
336 Visit(T->getUnderlyingExpr());
338 void VisitUnaryTransformType(const UnaryTransformType *T) {
339 Visit(T->getBaseType());
341 void VisitAttributedType(const AttributedType *T) {
343 Visit(T->getModifiedType());
345 void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) {
346 Visit(T->getReplacedParameter());
349 VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T) {
350 Visit(T->getReplacedParameter());
351 Visit(T->getArgumentPack());
353 void VisitTemplateSpecializationType(const TemplateSpecializationType *T) {
354 for (const auto &Arg : *T)
356 if (T->isTypeAlias())
357 Visit(T->getAliasedType());
359 void VisitObjCObjectPointerType(const ObjCObjectPointerType *T) {
360 Visit(T->getPointeeType());
362 void VisitAtomicType(const AtomicType *T) { Visit(T->getValueType()); }
363 void VisitPipeType(const PipeType *T) { Visit(T->getElementType()); }
364 void VisitAdjustedType(const AdjustedType *T) { Visit(T->getOriginalType()); }
365 void VisitPackExpansionType(const PackExpansionType *T) {
367 Visit(T->getPattern());
369 // FIXME: ElaboratedType, DependentNameType,
370 // DependentTemplateSpecializationType, ObjCObjectType
372 void VisitTypedefDecl(const TypedefDecl *D) { Visit(D->getUnderlyingType()); }
374 void VisitEnumConstantDecl(const EnumConstantDecl *D) {
375 if (const Expr *Init = D->getInitExpr())
379 void VisitFunctionDecl(const FunctionDecl *D) {
380 if (const auto *FTSI = D->getTemplateSpecializationInfo())
381 dumpTemplateArgumentList(*FTSI->TemplateArguments);
383 if (D->param_begin())
384 for (const auto *Parameter : D->parameters())
387 if (const Expr *TRC = D->getTrailingRequiresClause())
390 if (const auto *C = dyn_cast<CXXConstructorDecl>(D))
391 for (const auto *I : C->inits())
394 if (D->doesThisDeclarationHaveABody())
398 void VisitFieldDecl(const FieldDecl *D) {
400 Visit(D->getBitWidth());
401 if (Expr *Init = D->getInClassInitializer())
405 void VisitVarDecl(const VarDecl *D) {
410 void VisitDecompositionDecl(const DecompositionDecl *D) {
412 for (const auto *B : D->bindings())
416 void VisitBindingDecl(const BindingDecl *D) {
417 if (const auto *E = D->getBinding())
421 void VisitFileScopeAsmDecl(const FileScopeAsmDecl *D) {
422 Visit(D->getAsmString());
425 void VisitCapturedDecl(const CapturedDecl *D) { Visit(D->getBody()); }
427 void VisitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D) {
428 for (const auto *E : D->varlists())
432 void VisitOMPDeclareReductionDecl(const OMPDeclareReductionDecl *D) {
433 Visit(D->getCombiner());
434 if (const auto *Initializer = D->getInitializer())
438 void VisitOMPDeclareMapperDecl(const OMPDeclareMapperDecl *D) {
439 for (const auto *C : D->clauselists())
443 void VisitOMPCapturedExprDecl(const OMPCapturedExprDecl *D) {
447 void VisitOMPAllocateDecl(const OMPAllocateDecl *D) {
448 for (const auto *E : D->varlists())
450 for (const auto *C : D->clauselists())
454 template <typename SpecializationDecl>
455 void dumpTemplateDeclSpecialization(const SpecializationDecl *D) {
456 for (const auto *RedeclWithBadType : D->redecls()) {
457 // FIXME: The redecls() range sometimes has elements of a less-specific
458 // type. (In particular, ClassTemplateSpecializationDecl::redecls() gives
459 // us TagDecls, and should give CXXRecordDecls).
460 auto *Redecl = dyn_cast<SpecializationDecl>(RedeclWithBadType);
462 // Found the injected-class-name for a class template. This will be
463 // dumped as part of its surrounding class so we don't need to dump it
465 assert(isa<CXXRecordDecl>(RedeclWithBadType) &&
466 "expected an injected-class-name");
473 template <typename TemplateDecl>
474 void dumpTemplateDecl(const TemplateDecl *D) {
475 dumpTemplateParameters(D->getTemplateParameters());
477 Visit(D->getTemplatedDecl());
479 for (const auto *Child : D->specializations())
480 dumpTemplateDeclSpecialization(Child);
483 void VisitTypeAliasDecl(const TypeAliasDecl *D) {
484 Visit(D->getUnderlyingType());
487 void VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D) {
488 dumpTemplateParameters(D->getTemplateParameters());
489 Visit(D->getTemplatedDecl());
492 void VisitStaticAssertDecl(const StaticAssertDecl *D) {
493 Visit(D->getAssertExpr());
494 Visit(D->getMessage());
497 void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {
501 void VisitClassTemplateDecl(const ClassTemplateDecl *D) {
505 void VisitClassTemplateSpecializationDecl(
506 const ClassTemplateSpecializationDecl *D) {
507 dumpTemplateArgumentList(D->getTemplateArgs());
510 void VisitClassTemplatePartialSpecializationDecl(
511 const ClassTemplatePartialSpecializationDecl *D) {
512 VisitClassTemplateSpecializationDecl(D);
513 dumpTemplateParameters(D->getTemplateParameters());
516 void VisitClassScopeFunctionSpecializationDecl(
517 const ClassScopeFunctionSpecializationDecl *D) {
518 Visit(D->getSpecialization());
519 dumpASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten());
521 void VisitVarTemplateDecl(const VarTemplateDecl *D) { dumpTemplateDecl(D); }
523 void VisitBuiltinTemplateDecl(const BuiltinTemplateDecl *D) {
524 dumpTemplateParameters(D->getTemplateParameters());
528 VisitVarTemplateSpecializationDecl(const VarTemplateSpecializationDecl *D) {
529 dumpTemplateArgumentList(D->getTemplateArgs());
533 void VisitVarTemplatePartialSpecializationDecl(
534 const VarTemplatePartialSpecializationDecl *D) {
535 dumpTemplateParameters(D->getTemplateParameters());
536 VisitVarTemplateSpecializationDecl(D);
539 void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
540 if (const auto *TC = D->getTypeConstraint())
541 if (TC->hasExplicitTemplateArgs())
542 for (const auto &ArgLoc : TC->getTemplateArgsAsWritten()->arguments())
543 dumpTemplateArgumentLoc(ArgLoc);
544 if (D->hasDefaultArgument())
545 Visit(D->getDefaultArgument(), SourceRange(),
546 D->getDefaultArgStorage().getInheritedFrom(),
547 D->defaultArgumentWasInherited() ? "inherited from" : "previous");
550 void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) {
551 if (const auto *E = D->getPlaceholderTypeConstraint())
553 if (D->hasDefaultArgument())
554 Visit(D->getDefaultArgument(), SourceRange(),
555 D->getDefaultArgStorage().getInheritedFrom(),
556 D->defaultArgumentWasInherited() ? "inherited from" : "previous");
559 void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D) {
560 dumpTemplateParameters(D->getTemplateParameters());
561 if (D->hasDefaultArgument())
562 dumpTemplateArgumentLoc(
563 D->getDefaultArgument(), D->getDefaultArgStorage().getInheritedFrom(),
564 D->defaultArgumentWasInherited() ? "inherited from" : "previous");
567 void VisitConceptDecl(const ConceptDecl *D) {
568 dumpTemplateParameters(D->getTemplateParameters());
569 Visit(D->getConstraintExpr());
572 void VisitUsingShadowDecl(const UsingShadowDecl *D) {
573 if (auto *TD = dyn_cast<TypeDecl>(D->getUnderlyingDecl()))
574 Visit(TD->getTypeForDecl());
577 void VisitFriendDecl(const FriendDecl *D) {
578 if (!D->getFriendType())
579 Visit(D->getFriendDecl());
582 void VisitObjCMethodDecl(const ObjCMethodDecl *D) {
583 if (D->isThisDeclarationADefinition())
586 for (const ParmVarDecl *Parameter : D->parameters())
593 void VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
594 dumpObjCTypeParamList(D->getTypeParamList());
597 void VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
598 dumpObjCTypeParamList(D->getTypeParamListAsWritten());
601 void VisitObjCImplementationDecl(const ObjCImplementationDecl *D) {
602 for (const auto &I : D->inits())
606 void VisitBlockDecl(const BlockDecl *D) {
607 for (const auto &I : D->parameters())
610 for (const auto &I : D->captures())
615 void VisitDeclStmt(const DeclStmt *Node) {
616 for (const auto &D : Node->decls())
620 void VisitAttributedStmt(const AttributedStmt *Node) {
621 for (const auto *A : Node->getAttrs())
625 void VisitCXXCatchStmt(const CXXCatchStmt *Node) {
626 Visit(Node->getExceptionDecl());
629 void VisitCapturedStmt(const CapturedStmt *Node) {
630 Visit(Node->getCapturedDecl());
633 void VisitOMPExecutableDirective(const OMPExecutableDirective *Node) {
634 for (const auto *C : Node->clauses())
638 void VisitInitListExpr(const InitListExpr *ILE) {
639 if (auto *Filler = ILE->getArrayFiller()) {
640 Visit(Filler, "array_filler");
644 void VisitBlockExpr(const BlockExpr *Node) { Visit(Node->getBlockDecl()); }
646 void VisitOpaqueValueExpr(const OpaqueValueExpr *Node) {
647 if (Expr *Source = Node->getSourceExpr())
651 void VisitGenericSelectionExpr(const GenericSelectionExpr *E) {
652 Visit(E->getControllingExpr());
653 Visit(E->getControllingExpr()->getType()); // FIXME: remove
655 for (const auto Assoc : E->associations()) {
660 void VisitLambdaExpr(const LambdaExpr *Node) {
661 if (Traversal == ast_type_traits::TK_IgnoreUnlessSpelledInSource) {
662 for (unsigned I = 0, N = Node->capture_size(); I != N; ++I) {
663 const auto *C = Node->capture_begin() + I;
664 if (!C->isExplicit())
666 if (Node->isInitCapture(C))
667 Visit(C->getCapturedVar());
669 Visit(Node->capture_init_begin()[I]);
671 dumpTemplateParameters(Node->getTemplateParameterList());
672 for (const auto *P : Node->getCallOperator()->parameters())
674 Visit(Node->getBody());
676 return Visit(Node->getLambdaClass());
680 void VisitSizeOfPackExpr(const SizeOfPackExpr *Node) {
681 if (Node->isPartiallySubstituted())
682 for (const auto &A : Node->getPartialArguments())
686 void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node) {
687 if (const VarDecl *CatchParam = Node->getCatchParamDecl())
691 void VisitExpressionTemplateArgument(const TemplateArgument &TA) {
692 Visit(TA.getAsExpr());
694 void VisitPackTemplateArgument(const TemplateArgument &TA) {
695 for (const auto &TArg : TA.pack_elements())
699 // Implements Visit methods for Attrs.
700 #include "clang/AST/AttrNodeTraverse.inc"
705 #endif // LLVM_CLANG_AST_ASTNODETRAVERSER_H