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 NodeDelegateType &getNodeDelegate() {
69 return getDerived().doGetNodeDelegate();
71 Derived &getDerived() { return *static_cast<Derived *>(this); }
74 void setDeserialize(bool D) { Deserialize = D; }
75 bool getDeserialize() const { return Deserialize; }
77 void Visit(const Decl *D) {
78 getNodeDelegate().AddChild([=] {
79 getNodeDelegate().Visit(D);
83 ConstDeclVisitor<Derived>::Visit(D);
85 for (const auto &A : D->attrs())
88 if (const comments::FullComment *Comment =
89 D->getASTContext().getLocalCommentForDeclUncached(D))
90 Visit(Comment, Comment);
92 // Decls within functions are visited by the body.
93 if (!isa<FunctionDecl>(*D) && !isa<ObjCMethodDecl>(*D)) {
94 if (const auto *DC = dyn_cast<DeclContext>(D))
100 void Visit(const Stmt *S, StringRef Label = {}) {
101 getNodeDelegate().AddChild(Label, [=] {
102 getNodeDelegate().Visit(S);
108 ConstStmtVisitor<Derived>::Visit(S);
110 // Some statements have custom mechanisms for dumping their children.
111 if (isa<DeclStmt>(S) || isa<GenericSelectionExpr>(S)) {
115 for (const Stmt *SubStmt : S->children())
120 void Visit(QualType T) {
121 SplitQualType SQT = T.split();
122 if (!SQT.Quals.hasQualifiers())
123 return Visit(SQT.Ty);
125 getNodeDelegate().AddChild([=] {
126 getNodeDelegate().Visit(T);
131 void Visit(const Type *T) {
132 getNodeDelegate().AddChild([=] {
133 getNodeDelegate().Visit(T);
136 TypeVisitor<Derived>::Visit(T);
138 QualType SingleStepDesugar =
139 T->getLocallyUnqualifiedSingleStepDesugaredType();
140 if (SingleStepDesugar != QualType(T, 0))
141 Visit(SingleStepDesugar);
145 void Visit(const Attr *A) {
146 getNodeDelegate().AddChild([=] {
147 getNodeDelegate().Visit(A);
148 ConstAttrVisitor<Derived>::Visit(A);
152 void Visit(const CXXCtorInitializer *Init) {
153 getNodeDelegate().AddChild([=] {
154 getNodeDelegate().Visit(Init);
155 Visit(Init->getInit());
159 void Visit(const TemplateArgument &A, SourceRange R = {},
160 const Decl *From = nullptr, const char *Label = nullptr) {
161 getNodeDelegate().AddChild([=] {
162 getNodeDelegate().Visit(A, R, From, Label);
163 ConstTemplateArgumentVisitor<Derived>::Visit(A);
167 void Visit(const BlockDecl::Capture &C) {
168 getNodeDelegate().AddChild([=] {
169 getNodeDelegate().Visit(C);
171 Visit(C.getCopyExpr());
175 void Visit(const OMPClause *C) {
176 getNodeDelegate().AddChild([=] {
177 getNodeDelegate().Visit(C);
178 for (const auto *S : C->children())
183 void Visit(const GenericSelectionExpr::ConstAssociation &A) {
184 getNodeDelegate().AddChild([=] {
185 getNodeDelegate().Visit(A);
186 if (const TypeSourceInfo *TSI = A.getTypeSourceInfo())
187 Visit(TSI->getType());
188 Visit(A.getAssociationExpr());
192 void Visit(const comments::Comment *C, const comments::FullComment *FC) {
193 getNodeDelegate().AddChild([=] {
194 getNodeDelegate().Visit(C, FC);
198 comments::ConstCommentVisitor<Derived, void,
199 const comments::FullComment *>::visit(C,
201 for (comments::Comment::child_iterator I = C->child_begin(),
208 void Visit(const ast_type_traits::DynTypedNode &N) {
209 // FIXME: Improve this with a switch or a visitor pattern.
210 if (const auto *D = N.get<Decl>())
212 else if (const auto *S = N.get<Stmt>())
214 else if (const auto *QT = N.get<QualType>())
216 else if (const auto *T = N.get<Type>())
218 else if (const auto *C = N.get<CXXCtorInitializer>())
220 else if (const auto *C = N.get<OMPClause>())
222 else if (const auto *T = N.get<TemplateArgument>())
226 void dumpDeclContext(const DeclContext *DC) {
230 for (const auto *D : (Deserialize ? DC->decls() : DC->noload_decls()))
234 void dumpTemplateParameters(const TemplateParameterList *TPL) {
238 for (const auto &TP : *TPL)
243 dumpASTTemplateArgumentListInfo(const ASTTemplateArgumentListInfo *TALI) {
247 for (const auto &TA : TALI->arguments())
248 dumpTemplateArgumentLoc(TA);
251 void dumpTemplateArgumentLoc(const TemplateArgumentLoc &A,
252 const Decl *From = nullptr,
253 const char *Label = nullptr) {
254 Visit(A.getArgument(), A.getSourceRange(), From, Label);
257 void dumpTemplateArgumentList(const TemplateArgumentList &TAL) {
258 for (unsigned i = 0, e = TAL.size(); i < e; ++i)
262 void dumpObjCTypeParamList(const ObjCTypeParamList *typeParams) {
266 for (const auto &typeParam : *typeParams) {
271 void VisitComplexType(const ComplexType *T) { Visit(T->getElementType()); }
272 void VisitLocInfoType(const LocInfoType *T) {
273 Visit(T->getTypeSourceInfo()->getType());
275 void VisitPointerType(const PointerType *T) { Visit(T->getPointeeType()); }
276 void VisitBlockPointerType(const BlockPointerType *T) {
277 Visit(T->getPointeeType());
279 void VisitReferenceType(const ReferenceType *T) {
280 Visit(T->getPointeeType());
282 void VisitMemberPointerType(const MemberPointerType *T) {
283 Visit(T->getClass());
284 Visit(T->getPointeeType());
286 void VisitArrayType(const ArrayType *T) { Visit(T->getElementType()); }
287 void VisitVariableArrayType(const VariableArrayType *T) {
289 Visit(T->getSizeExpr());
291 void VisitDependentSizedArrayType(const DependentSizedArrayType *T) {
292 Visit(T->getElementType());
293 Visit(T->getSizeExpr());
295 void VisitDependentSizedExtVectorType(const DependentSizedExtVectorType *T) {
296 Visit(T->getElementType());
297 Visit(T->getSizeExpr());
299 void VisitVectorType(const VectorType *T) { Visit(T->getElementType()); }
300 void VisitFunctionType(const FunctionType *T) { Visit(T->getReturnType()); }
301 void VisitFunctionProtoType(const FunctionProtoType *T) {
302 VisitFunctionType(T);
303 for (const QualType &PT : T->getParamTypes())
306 void VisitTypeOfExprType(const TypeOfExprType *T) {
307 Visit(T->getUnderlyingExpr());
309 void VisitDecltypeType(const DecltypeType *T) {
310 Visit(T->getUnderlyingExpr());
312 void VisitUnaryTransformType(const UnaryTransformType *T) {
313 Visit(T->getBaseType());
315 void VisitAttributedType(const AttributedType *T) {
317 Visit(T->getModifiedType());
319 void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) {
320 Visit(T->getReplacedParameter());
323 VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T) {
324 Visit(T->getReplacedParameter());
325 Visit(T->getArgumentPack());
327 void VisitTemplateSpecializationType(const TemplateSpecializationType *T) {
328 for (const auto &Arg : *T)
330 if (T->isTypeAlias())
331 Visit(T->getAliasedType());
333 void VisitObjCObjectPointerType(const ObjCObjectPointerType *T) {
334 Visit(T->getPointeeType());
336 void VisitAtomicType(const AtomicType *T) { Visit(T->getValueType()); }
337 void VisitPipeType(const PipeType *T) { Visit(T->getElementType()); }
338 void VisitAdjustedType(const AdjustedType *T) { Visit(T->getOriginalType()); }
339 void VisitPackExpansionType(const PackExpansionType *T) {
341 Visit(T->getPattern());
343 // FIXME: ElaboratedType, DependentNameType,
344 // DependentTemplateSpecializationType, ObjCObjectType
346 void VisitTypedefDecl(const TypedefDecl *D) { Visit(D->getUnderlyingType()); }
348 void VisitEnumConstantDecl(const EnumConstantDecl *D) {
349 if (const Expr *Init = D->getInitExpr())
353 void VisitFunctionDecl(const FunctionDecl *D) {
354 if (const auto *FTSI = D->getTemplateSpecializationInfo())
355 dumpTemplateArgumentList(*FTSI->TemplateArguments);
357 if (D->param_begin())
358 for (const auto *Parameter : D->parameters())
361 if (const auto *C = dyn_cast<CXXConstructorDecl>(D))
362 for (const auto *I : C->inits())
365 if (D->doesThisDeclarationHaveABody())
369 void VisitFieldDecl(const FieldDecl *D) {
371 Visit(D->getBitWidth());
372 if (Expr *Init = D->getInClassInitializer())
376 void VisitVarDecl(const VarDecl *D) {
381 void VisitDecompositionDecl(const DecompositionDecl *D) {
383 for (const auto *B : D->bindings())
387 void VisitBindingDecl(const BindingDecl *D) {
388 if (const auto *E = D->getBinding())
392 void VisitFileScopeAsmDecl(const FileScopeAsmDecl *D) {
393 Visit(D->getAsmString());
396 void VisitCapturedDecl(const CapturedDecl *D) { Visit(D->getBody()); }
398 void VisitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D) {
399 for (const auto *E : D->varlists())
403 void VisitOMPDeclareReductionDecl(const OMPDeclareReductionDecl *D) {
404 Visit(D->getCombiner());
405 if (const auto *Initializer = D->getInitializer())
409 void VisitOMPDeclareMapperDecl(const OMPDeclareMapperDecl *D) {
410 for (const auto *C : D->clauselists())
414 void VisitOMPCapturedExprDecl(const OMPCapturedExprDecl *D) {
418 void VisitOMPAllocateDecl(const OMPAllocateDecl *D) {
419 for (const auto *E : D->varlists())
421 for (const auto *C : D->clauselists())
425 template <typename SpecializationDecl>
426 void dumpTemplateDeclSpecialization(const SpecializationDecl *D) {
427 for (const auto *RedeclWithBadType : D->redecls()) {
428 // FIXME: The redecls() range sometimes has elements of a less-specific
429 // type. (In particular, ClassTemplateSpecializationDecl::redecls() gives
430 // us TagDecls, and should give CXXRecordDecls).
431 auto *Redecl = dyn_cast<SpecializationDecl>(RedeclWithBadType);
433 // Found the injected-class-name for a class template. This will be
434 // dumped as part of its surrounding class so we don't need to dump it
436 assert(isa<CXXRecordDecl>(RedeclWithBadType) &&
437 "expected an injected-class-name");
444 template <typename TemplateDecl>
445 void dumpTemplateDecl(const TemplateDecl *D) {
446 dumpTemplateParameters(D->getTemplateParameters());
448 Visit(D->getTemplatedDecl());
450 for (const auto *Child : D->specializations())
451 dumpTemplateDeclSpecialization(Child);
454 void VisitTypeAliasDecl(const TypeAliasDecl *D) {
455 Visit(D->getUnderlyingType());
458 void VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D) {
459 dumpTemplateParameters(D->getTemplateParameters());
460 Visit(D->getTemplatedDecl());
463 void VisitStaticAssertDecl(const StaticAssertDecl *D) {
464 Visit(D->getAssertExpr());
465 Visit(D->getMessage());
468 void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {
472 void VisitClassTemplateDecl(const ClassTemplateDecl *D) {
476 void VisitClassTemplateSpecializationDecl(
477 const ClassTemplateSpecializationDecl *D) {
478 dumpTemplateArgumentList(D->getTemplateArgs());
481 void VisitClassTemplatePartialSpecializationDecl(
482 const ClassTemplatePartialSpecializationDecl *D) {
483 VisitClassTemplateSpecializationDecl(D);
484 dumpTemplateParameters(D->getTemplateParameters());
487 void VisitClassScopeFunctionSpecializationDecl(
488 const ClassScopeFunctionSpecializationDecl *D) {
489 Visit(D->getSpecialization());
490 dumpASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten());
492 void VisitVarTemplateDecl(const VarTemplateDecl *D) { dumpTemplateDecl(D); }
494 void VisitBuiltinTemplateDecl(const BuiltinTemplateDecl *D) {
495 dumpTemplateParameters(D->getTemplateParameters());
499 VisitVarTemplateSpecializationDecl(const VarTemplateSpecializationDecl *D) {
500 dumpTemplateArgumentList(D->getTemplateArgs());
504 void VisitVarTemplatePartialSpecializationDecl(
505 const VarTemplatePartialSpecializationDecl *D) {
506 dumpTemplateParameters(D->getTemplateParameters());
507 VisitVarTemplateSpecializationDecl(D);
510 void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
511 if (D->hasDefaultArgument())
512 Visit(D->getDefaultArgument(), SourceRange(),
513 D->getDefaultArgStorage().getInheritedFrom(),
514 D->defaultArgumentWasInherited() ? "inherited from" : "previous");
517 void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) {
518 if (D->hasDefaultArgument())
519 Visit(D->getDefaultArgument(), SourceRange(),
520 D->getDefaultArgStorage().getInheritedFrom(),
521 D->defaultArgumentWasInherited() ? "inherited from" : "previous");
524 void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D) {
525 dumpTemplateParameters(D->getTemplateParameters());
526 if (D->hasDefaultArgument())
527 dumpTemplateArgumentLoc(
528 D->getDefaultArgument(), D->getDefaultArgStorage().getInheritedFrom(),
529 D->defaultArgumentWasInherited() ? "inherited from" : "previous");
532 void VisitConceptDecl(const ConceptDecl *D) {
533 dumpTemplateParameters(D->getTemplateParameters());
534 Visit(D->getConstraintExpr());
537 void VisitUsingShadowDecl(const UsingShadowDecl *D) {
538 if (auto *TD = dyn_cast<TypeDecl>(D->getUnderlyingDecl()))
539 Visit(TD->getTypeForDecl());
542 void VisitFriendDecl(const FriendDecl *D) {
543 if (!D->getFriendType())
544 Visit(D->getFriendDecl());
547 void VisitObjCMethodDecl(const ObjCMethodDecl *D) {
548 if (D->isThisDeclarationADefinition())
551 for (const ParmVarDecl *Parameter : D->parameters())
558 void VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
559 dumpObjCTypeParamList(D->getTypeParamList());
562 void VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
563 dumpObjCTypeParamList(D->getTypeParamListAsWritten());
566 void VisitObjCImplementationDecl(const ObjCImplementationDecl *D) {
567 for (const auto &I : D->inits())
571 void VisitBlockDecl(const BlockDecl *D) {
572 for (const auto &I : D->parameters())
575 for (const auto &I : D->captures())
580 void VisitDeclStmt(const DeclStmt *Node) {
581 for (const auto &D : Node->decls())
585 void VisitAttributedStmt(const AttributedStmt *Node) {
586 for (const auto *A : Node->getAttrs())
590 void VisitCXXCatchStmt(const CXXCatchStmt *Node) {
591 Visit(Node->getExceptionDecl());
594 void VisitCapturedStmt(const CapturedStmt *Node) {
595 Visit(Node->getCapturedDecl());
598 void VisitOMPExecutableDirective(const OMPExecutableDirective *Node) {
599 for (const auto *C : Node->clauses())
603 void VisitInitListExpr(const InitListExpr *ILE) {
604 if (auto *Filler = ILE->getArrayFiller()) {
605 Visit(Filler, "array_filler");
609 void VisitBlockExpr(const BlockExpr *Node) { Visit(Node->getBlockDecl()); }
611 void VisitOpaqueValueExpr(const OpaqueValueExpr *Node) {
612 if (Expr *Source = Node->getSourceExpr())
616 void VisitGenericSelectionExpr(const GenericSelectionExpr *E) {
617 Visit(E->getControllingExpr());
618 Visit(E->getControllingExpr()->getType()); // FIXME: remove
620 for (const auto &Assoc : E->associations()) {
625 void VisitLambdaExpr(const LambdaExpr *Node) {
626 Visit(Node->getLambdaClass());
629 void VisitSizeOfPackExpr(const SizeOfPackExpr *Node) {
630 if (Node->isPartiallySubstituted())
631 for (const auto &A : Node->getPartialArguments())
635 void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node) {
636 if (const VarDecl *CatchParam = Node->getCatchParamDecl())
640 void VisitExpressionTemplateArgument(const TemplateArgument &TA) {
641 Visit(TA.getAsExpr());
643 void VisitPackTemplateArgument(const TemplateArgument &TA) {
644 for (const auto &TArg : TA.pack_elements())
648 // Implements Visit methods for Attrs.
649 #include "clang/AST/AttrNodeTraverse.inc"
654 #endif // LLVM_CLANG_AST_ASTNODETRAVERSER_H