1 //===--- DynamicRecursiveASTVisitor.h - Virtual AST Visitor -----*- C++ -*-===// 2 // 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 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines the DynamicRecursiveASTVisitor interface, which acts 10 // identically to RecursiveASTVisitor, except that it uses virtual dispatch 11 // instead of CRTP, which greatly improves compile times and binary size. 12 // 13 // Prefer to use this over RecursiveASTVisitor whenever possible. 14 // 15 //===----------------------------------------------------------------------===// 16 #ifndef LLVM_CLANG_AST_DYNAMIC_RECURSIVE_AST_VISITOR_H 17 #define LLVM_CLANG_AST_DYNAMIC_RECURSIVE_AST_VISITOR_H 18 19 #include "clang/AST/Attr.h" 20 #include "clang/AST/ExprConcepts.h" 21 #include "clang/AST/TypeLoc.h" 22 23 namespace clang { 24 class ASTContext; 25 26 /// Recursive AST visitor that supports extension via dynamic dispatch. 27 /// 28 /// Like RecursiveASTVisitor, this class allows for traversal of arbitrarily 29 /// complex ASTs. The main difference is that this uses virtual functions 30 /// instead of CRTP, which greatly improves compile times of Clang itself, 31 /// as well as binary size. 32 /// 33 /// Instead of functions (e.g. shouldVisitImplicitCode()), this class 34 /// uses member variables (e.g. ShouldVisitImplicitCode) to control 35 /// visitation behaviour. 36 /// 37 /// However, there is no support for overriding some of the less commonly 38 /// used features of the RAV, such as WalkUpFromX or attribute traversal 39 /// (attributes can still be traversed, but you can't change what happens 40 /// when we traverse one). 41 /// 42 /// The following is a list of RAV features that are NOT customisable: 43 /// 44 /// - Visiting attributes, 45 /// - Overriding WalkUpFromX, 46 /// - Overriding getStmtChildren(). 47 /// 48 /// Furthermore, post-order traversal is not supported at all. 49 /// 50 /// Prefer to use this over RecursiveASTVisitor unless you absolutely 51 /// need to use one of the features listed above (e.g. overriding 52 /// WalkUpFromX or post-order traversal). 53 /// 54 /// \see RecursiveASTVisitor. 55 template <bool IsConst> class DynamicRecursiveASTVisitorBase { 56 protected: 57 template <typename ASTNode> 58 using MaybeConst = std::conditional_t<IsConst, const ASTNode, ASTNode>; 59 60 public: 61 /// Whether this visitor should recurse into template instantiations. 62 bool ShouldVisitTemplateInstantiations = false; 63 64 /// Whether this visitor should recurse into the types of TypeLocs. 65 bool ShouldWalkTypesOfTypeLocs = true; 66 67 /// Whether this visitor should recurse into implicit code, e.g. 68 /// implicit constructors and destructors. 69 bool ShouldVisitImplicitCode = false; 70 71 /// Whether this visitor should recurse into lambda body. 72 bool ShouldVisitLambdaBody = true; 73 74 protected: 75 DynamicRecursiveASTVisitorBase() = default; 76 DynamicRecursiveASTVisitorBase(DynamicRecursiveASTVisitorBase &&) = default; 77 DynamicRecursiveASTVisitorBase(const DynamicRecursiveASTVisitorBase &) = 78 default; 79 DynamicRecursiveASTVisitorBase & 80 operator=(DynamicRecursiveASTVisitorBase &&) = default; 81 DynamicRecursiveASTVisitorBase & 82 operator=(const DynamicRecursiveASTVisitorBase &) = default; 83 84 public: 85 virtual void anchor(); 86 virtual ~DynamicRecursiveASTVisitorBase() = default; 87 88 /// Recursively visits an entire AST, starting from the TranslationUnitDecl. 89 /// \returns false if visitation was terminated early. 90 virtual bool TraverseAST(MaybeConst<ASTContext> &AST); 91 92 /// Recursively visit an attribute, by dispatching to 93 /// Traverse*Attr() based on the argument's dynamic type. 94 /// 95 /// \returns false if the visitation was terminated early, true 96 /// otherwise (including when the argument is a Null type location). 97 virtual bool TraverseAttr(MaybeConst<Attr> *At); 98 99 /// Recursively visit a constructor initializer. This 100 /// automatically dispatches to another visitor for the initializer 101 /// expression, but not for the name of the initializer, so may 102 /// be overridden for clients that need access to the name. 103 /// 104 /// \returns false if the visitation was terminated early, true otherwise. 105 virtual bool 106 TraverseConstructorInitializer(MaybeConst<CXXCtorInitializer> *Init); 107 108 /// Recursively visit a base specifier. This can be overridden by a 109 /// subclass. 110 /// 111 /// \returns false if the visitation was terminated early, true otherwise. 112 virtual bool TraverseCXXBaseSpecifier(const CXXBaseSpecifier &Base); 113 114 /// Recursively visit a declaration, by dispatching to 115 /// Traverse*Decl() based on the argument's dynamic type. 116 /// 117 /// \returns false if the visitation was terminated early, true 118 /// otherwise (including when the argument is NULL). 119 virtual bool TraverseDecl(MaybeConst<Decl> *D); 120 121 /// Recursively visit a name with its location information. 122 /// 123 /// \returns false if the visitation was terminated early, true otherwise. 124 virtual bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo); 125 126 /// Recursively visit a lambda capture. \c Init is the expression that 127 /// will be used to initialize the capture. 128 /// 129 /// \returns false if the visitation was terminated early, true otherwise. 130 virtual bool TraverseLambdaCapture(MaybeConst<LambdaExpr> *LE, 131 const LambdaCapture *C, 132 MaybeConst<Expr> *Init); 133 134 /// Recursively visit a C++ nested-name-specifier. 135 /// 136 /// \returns false if the visitation was terminated early, true otherwise. 137 virtual bool 138 TraverseNestedNameSpecifier(MaybeConst<NestedNameSpecifier> *NNS); 139 140 /// Recursively visit a C++ nested-name-specifier with location 141 /// information. 142 /// 143 /// \returns false if the visitation was terminated early, true otherwise. 144 virtual bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS); 145 146 /// Recursively visit a statement or expression, by 147 /// dispatching to Traverse*() based on the argument's dynamic type. 148 /// 149 /// \returns false if the visitation was terminated early, true 150 /// otherwise (including when the argument is nullptr). 151 virtual bool TraverseStmt(MaybeConst<Stmt> *S); 152 153 /// Recursively visit a template argument and dispatch to the 154 /// appropriate method for the argument type. 155 /// 156 /// \returns false if the visitation was terminated early, true otherwise. 157 // FIXME: migrate callers to TemplateArgumentLoc instead. 158 virtual bool TraverseTemplateArgument(const TemplateArgument &Arg); 159 160 /// Recursively visit a template argument location and dispatch to the 161 /// appropriate method for the argument type. 162 /// 163 /// \returns false if the visitation was terminated early, true otherwise. 164 virtual bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc); 165 166 /// Recursively visit a set of template arguments. 167 /// 168 /// \returns false if the visitation was terminated early, true otherwise. 169 // FIXME: take a TemplateArgumentLoc* (or TemplateArgumentListInfo) instead. 170 // Not virtual for now because no-one overrides it. 171 bool TraverseTemplateArguments(ArrayRef<TemplateArgument> Args); 172 173 /// Recursively visit a template name and dispatch to the 174 /// appropriate method. 175 /// 176 /// \returns false if the visitation was terminated early, true otherwise. 177 virtual bool TraverseTemplateName(TemplateName Template); 178 179 /// Recursively visit a type, by dispatching to 180 /// Traverse*Type() based on the argument's getTypeClass() property. 181 /// 182 /// \returns false if the visitation was terminated early, true 183 /// otherwise (including when the argument is a Null type). 184 virtual bool TraverseType(QualType T); 185 186 /// Recursively visit a type with location, by dispatching to 187 /// Traverse*TypeLoc() based on the argument type's getTypeClass() property. 188 /// 189 /// \returns false if the visitation was terminated early, true 190 /// otherwise (including when the argument is a Null type location). 191 virtual bool TraverseTypeLoc(TypeLoc TL); 192 193 /// Recursively visit an Objective-C protocol reference with location 194 /// information. 195 /// 196 /// \returns false if the visitation was terminated early, true otherwise. 197 virtual bool TraverseObjCProtocolLoc(ObjCProtocolLoc ProtocolLoc); 198 199 /// Traverse a concept (requirement). 200 virtual bool TraverseTypeConstraint(const TypeConstraint *C); 201 virtual bool TraverseConceptRequirement(MaybeConst<concepts::Requirement> *R); 202 203 virtual bool 204 TraverseConceptTypeRequirement(MaybeConst<concepts::TypeRequirement> *R); 205 206 virtual bool 207 TraverseConceptExprRequirement(MaybeConst<concepts::ExprRequirement> *R); 208 209 virtual bool 210 TraverseConceptNestedRequirement(MaybeConst<concepts::NestedRequirement> *R); 211 212 virtual bool TraverseConceptReference(MaybeConst<ConceptReference> *CR); VisitConceptReference(MaybeConst<ConceptReference> * CR)213 virtual bool VisitConceptReference(MaybeConst<ConceptReference> *CR) { 214 return true; 215 } 216 217 /// Visit a node. VisitAttr(MaybeConst<Attr> * A)218 virtual bool VisitAttr(MaybeConst<Attr> *A) { return true; } VisitDecl(MaybeConst<Decl> * D)219 virtual bool VisitDecl(MaybeConst<Decl> *D) { return true; } VisitStmt(MaybeConst<Stmt> * S)220 virtual bool VisitStmt(MaybeConst<Stmt> *S) { return true; } VisitType(MaybeConst<Type> * T)221 virtual bool VisitType(MaybeConst<Type> *T) { return true; } VisitTypeLoc(TypeLoc TL)222 virtual bool VisitTypeLoc(TypeLoc TL) { return true; } 223 224 /// Walk up from a node. WalkUpFromDecl(MaybeConst<Decl> * D)225 bool WalkUpFromDecl(MaybeConst<Decl> *D) { return VisitDecl(D); } WalkUpFromStmt(MaybeConst<Stmt> * S)226 bool WalkUpFromStmt(MaybeConst<Stmt> *S) { return VisitStmt(S); } WalkUpFromType(MaybeConst<Type> * T)227 bool WalkUpFromType(MaybeConst<Type> *T) { return VisitType(T); } WalkUpFromTypeLoc(TypeLoc TL)228 bool WalkUpFromTypeLoc(TypeLoc TL) { return VisitTypeLoc(TL); } 229 230 /// Invoked before visiting a statement or expression via data recursion. 231 /// 232 /// \returns false to skip visiting the node, true otherwise. dataTraverseStmtPre(MaybeConst<Stmt> * S)233 virtual bool dataTraverseStmtPre(MaybeConst<Stmt> *S) { return true; } 234 235 /// Invoked after visiting a statement or expression via data recursion. 236 /// This is not invoked if the previously invoked \c dataTraverseStmtPre 237 /// returned false. 238 /// 239 /// \returns false if the visitation was terminated early, true otherwise. dataTraverseStmtPost(MaybeConst<Stmt> * S)240 virtual bool dataTraverseStmtPost(MaybeConst<Stmt> *S) { return true; } 241 virtual bool dataTraverseNode(MaybeConst<Stmt> *S); 242 243 #define DEF_TRAVERSE_TMPL_INST(kind) \ 244 virtual bool TraverseTemplateInstantiations( \ 245 MaybeConst<kind##TemplateDecl> *D); 246 DEF_TRAVERSE_TMPL_INST(Class) 247 DEF_TRAVERSE_TMPL_INST(Var) 248 DEF_TRAVERSE_TMPL_INST(Function) 249 #undef DEF_TRAVERSE_TMPL_INST 250 251 // Decls. 252 #define ABSTRACT_DECL(DECL) 253 #define DECL(CLASS, BASE) \ 254 bool WalkUpFrom##CLASS##Decl(MaybeConst<CLASS##Decl> *D); \ 255 virtual bool Traverse##CLASS##Decl(MaybeConst<CLASS##Decl> *D); 256 #include "clang/AST/DeclNodes.inc" 257 258 #define DECL(CLASS, BASE) \ 259 virtual bool Visit##CLASS##Decl(MaybeConst<CLASS##Decl> *D) { return true; } 260 #include "clang/AST/DeclNodes.inc" 261 262 // Stmts. 263 #define ABSTRACT_STMT(STMT) 264 #define STMT(CLASS, PARENT) virtual bool Traverse##CLASS(MaybeConst<CLASS> *S); 265 #include "clang/AST/StmtNodes.inc" 266 267 #define STMT(CLASS, PARENT) \ 268 bool WalkUpFrom##CLASS(MaybeConst<CLASS> *S); \ 269 virtual bool Visit##CLASS(MaybeConst<CLASS> *S) { return true; } 270 #include "clang/AST/StmtNodes.inc" 271 272 // Types. 273 #define ABSTRACT_TYPE(CLASS, BASE) 274 #define TYPE(CLASS, BASE) \ 275 bool WalkUpFrom##CLASS##Type(MaybeConst<CLASS##Type> *T); \ 276 virtual bool Traverse##CLASS##Type(MaybeConst<CLASS##Type> *T); 277 #include "clang/AST/TypeNodes.inc" 278 279 #define TYPE(CLASS, BASE) \ 280 virtual bool Visit##CLASS##Type(MaybeConst<CLASS##Type> *T) { return true; } 281 #include "clang/AST/TypeNodes.inc" 282 283 // TypeLocs. 284 #define ABSTRACT_TYPELOC(CLASS, BASE) 285 #define TYPELOC(CLASS, BASE) \ 286 virtual bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL); 287 #include "clang/AST/TypeLocNodes.def" 288 289 #define TYPELOC(CLASS, BASE) \ 290 bool WalkUpFrom##CLASS##TypeLoc(CLASS##TypeLoc TL); \ 291 virtual bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TL) { return true; } 292 #include "clang/AST/TypeLocNodes.def" 293 }; 294 295 extern template class DynamicRecursiveASTVisitorBase<false>; 296 extern template class DynamicRecursiveASTVisitorBase<true>; 297 298 using DynamicRecursiveASTVisitor = 299 DynamicRecursiveASTVisitorBase</*Const=*/false>; 300 using ConstDynamicRecursiveASTVisitor = 301 DynamicRecursiveASTVisitorBase</*Const=*/true>; 302 } // namespace clang 303 304 #endif // LLVM_CLANG_AST_DYNAMIC_RECURSIVE_AST_VISITOR_H 305