Skip to content

Commit ff5551c

Browse files
authored
[Clang] [NFC] Introduce DynamicRecursiveASTVisitor (#110040)
See #105195 as well as the big comment in DynamicRecursiveASTVisitor.cpp for more context.
1 parent 5f8b83e commit ff5551c

File tree

3 files changed

+729
-0
lines changed

3 files changed

+729
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
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+
class DynamicRecursiveASTVisitor {
56+
public:
57+
/// Whether this visitor should recurse into template instantiations.
58+
bool ShouldVisitTemplateInstantiations = false;
59+
60+
/// Whether this visitor should recurse into the types of TypeLocs.
61+
bool ShouldWalkTypesOfTypeLocs = true;
62+
63+
/// Whether this visitor should recurse into implicit code, e.g.
64+
/// implicit constructors and destructors.
65+
bool ShouldVisitImplicitCode = false;
66+
67+
/// Whether this visitor should recurse into lambda body.
68+
bool ShouldVisitLambdaBody = true;
69+
70+
protected:
71+
DynamicRecursiveASTVisitor() = default;
72+
DynamicRecursiveASTVisitor(DynamicRecursiveASTVisitor &&) = default;
73+
DynamicRecursiveASTVisitor(const DynamicRecursiveASTVisitor &) = default;
74+
DynamicRecursiveASTVisitor &
75+
operator=(DynamicRecursiveASTVisitor &&) = default;
76+
DynamicRecursiveASTVisitor &
77+
operator=(const DynamicRecursiveASTVisitor &) = default;
78+
79+
public:
80+
virtual void anchor();
81+
virtual ~DynamicRecursiveASTVisitor() = default;
82+
83+
/// Recursively visits an entire AST, starting from the TranslationUnitDecl.
84+
/// \returns false if visitation was terminated early.
85+
virtual bool TraverseAST(ASTContext &AST);
86+
87+
/// Recursively visit an attribute, by dispatching to
88+
/// Traverse*Attr() based on the argument's dynamic type.
89+
///
90+
/// \returns false if the visitation was terminated early, true
91+
/// otherwise (including when the argument is a Null type location).
92+
virtual bool TraverseAttr(Attr *At);
93+
94+
/// Recursively visit a constructor initializer. This
95+
/// automatically dispatches to another visitor for the initializer
96+
/// expression, but not for the name of the initializer, so may
97+
/// be overridden for clients that need access to the name.
98+
///
99+
/// \returns false if the visitation was terminated early, true otherwise.
100+
virtual bool TraverseConstructorInitializer(CXXCtorInitializer *Init);
101+
102+
/// Recursively visit a base specifier. This can be overridden by a
103+
/// subclass.
104+
///
105+
/// \returns false if the visitation was terminated early, true otherwise.
106+
virtual bool TraverseCXXBaseSpecifier(const CXXBaseSpecifier &Base);
107+
108+
/// Recursively visit a declaration, by dispatching to
109+
/// Traverse*Decl() based on the argument's dynamic type.
110+
///
111+
/// \returns false if the visitation was terminated early, true
112+
/// otherwise (including when the argument is NULL).
113+
virtual bool TraverseDecl(Decl *D);
114+
115+
/// Recursively visit a name with its location information.
116+
///
117+
/// \returns false if the visitation was terminated early, true otherwise.
118+
virtual bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo);
119+
120+
/// Recursively visit a lambda capture. \c Init is the expression that
121+
/// will be used to initialize the capture.
122+
///
123+
/// \returns false if the visitation was terminated early, true otherwise.
124+
virtual bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,
125+
Expr *Init);
126+
127+
/// Recursively visit a C++ nested-name-specifier.
128+
///
129+
/// \returns false if the visitation was terminated early, true otherwise.
130+
virtual bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS);
131+
132+
/// Recursively visit a C++ nested-name-specifier with location
133+
/// information.
134+
///
135+
/// \returns false if the visitation was terminated early, true otherwise.
136+
virtual bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);
137+
138+
/// Recursively visit a statement or expression, by
139+
/// dispatching to Traverse*() based on the argument's dynamic type.
140+
///
141+
/// \returns false if the visitation was terminated early, true
142+
/// otherwise (including when the argument is nullptr).
143+
virtual bool TraverseStmt(Stmt *S);
144+
145+
/// Recursively visit a template argument and dispatch to the
146+
/// appropriate method for the argument type.
147+
///
148+
/// \returns false if the visitation was terminated early, true otherwise.
149+
// FIXME: migrate callers to TemplateArgumentLoc instead.
150+
virtual bool TraverseTemplateArgument(const TemplateArgument &Arg);
151+
152+
/// Recursively visit a template argument location and dispatch to the
153+
/// appropriate method for the argument type.
154+
///
155+
/// \returns false if the visitation was terminated early, true otherwise.
156+
virtual bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc);
157+
158+
/// Recursively visit a set of template arguments.
159+
///
160+
/// \returns false if the visitation was terminated early, true otherwise.
161+
// FIXME: take a TemplateArgumentLoc* (or TemplateArgumentListInfo) instead.
162+
// Not virtual for now because no-one overrides it.
163+
bool TraverseTemplateArguments(ArrayRef<TemplateArgument> Args);
164+
165+
/// Recursively visit a template name and dispatch to the
166+
/// appropriate method.
167+
///
168+
/// \returns false if the visitation was terminated early, true otherwise.
169+
virtual bool TraverseTemplateName(TemplateName Template);
170+
171+
/// Recursively visit a type, by dispatching to
172+
/// Traverse*Type() based on the argument's getTypeClass() property.
173+
///
174+
/// \returns false if the visitation was terminated early, true
175+
/// otherwise (including when the argument is a Null type).
176+
virtual bool TraverseType(QualType T);
177+
178+
/// Recursively visit a type with location, by dispatching to
179+
/// Traverse*TypeLoc() based on the argument type's getTypeClass() property.
180+
///
181+
/// \returns false if the visitation was terminated early, true
182+
/// otherwise (including when the argument is a Null type location).
183+
virtual bool TraverseTypeLoc(TypeLoc TL);
184+
185+
/// Recursively visit an Objective-C protocol reference with location
186+
/// information.
187+
///
188+
/// \returns false if the visitation was terminated early, true otherwise.
189+
virtual bool TraverseObjCProtocolLoc(ObjCProtocolLoc ProtocolLoc);
190+
191+
/// Traverse a concept (requirement).
192+
virtual bool TraverseTypeConstraint(const TypeConstraint *C);
193+
virtual bool TraverseConceptRequirement(concepts::Requirement *R);
194+
virtual bool TraverseConceptTypeRequirement(concepts::TypeRequirement *R);
195+
virtual bool TraverseConceptExprRequirement(concepts::ExprRequirement *R);
196+
virtual bool TraverseConceptNestedRequirement(concepts::NestedRequirement *R);
197+
virtual bool TraverseConceptReference(ConceptReference *CR);
198+
virtual bool VisitConceptReference(ConceptReference *CR) { return true; }
199+
200+
/// Visit a node.
201+
virtual bool VisitAttr(Attr *A) { return true; }
202+
virtual bool VisitDecl(Decl *D) { return true; }
203+
virtual bool VisitStmt(Stmt *S) { return true; }
204+
virtual bool VisitType(Type *T) { return true; }
205+
virtual bool VisitTypeLoc(TypeLoc TL) { return true; }
206+
207+
/// Walk up from a node.
208+
bool WalkUpFromDecl(Decl *D) { return VisitDecl(D); }
209+
bool WalkUpFromStmt(Stmt *S) { return VisitStmt(S); }
210+
bool WalkUpFromType(Type *T) { return VisitType(T); }
211+
bool WalkUpFromTypeLoc(TypeLoc TL) { return VisitTypeLoc(TL); }
212+
213+
/// Invoked before visiting a statement or expression via data recursion.
214+
///
215+
/// \returns false to skip visiting the node, true otherwise.
216+
virtual bool dataTraverseStmtPre(Stmt *S) { return true; }
217+
218+
/// Invoked after visiting a statement or expression via data recursion.
219+
/// This is not invoked if the previously invoked \c dataTraverseStmtPre
220+
/// returned false.
221+
///
222+
/// \returns false if the visitation was terminated early, true otherwise.
223+
virtual bool dataTraverseStmtPost(Stmt *S) { return true; }
224+
virtual bool dataTraverseNode(Stmt *S);
225+
226+
#define DEF_TRAVERSE_TMPL_INST(kind) \
227+
virtual bool TraverseTemplateInstantiations(kind##TemplateDecl *D);
228+
DEF_TRAVERSE_TMPL_INST(Class)
229+
DEF_TRAVERSE_TMPL_INST(Var)
230+
DEF_TRAVERSE_TMPL_INST(Function)
231+
#undef DEF_TRAVERSE_TMPL_INST
232+
233+
// Decls.
234+
#define ABSTRACT_DECL(DECL)
235+
#define DECL(CLASS, BASE) virtual bool Traverse##CLASS##Decl(CLASS##Decl *D);
236+
#include "clang/AST/DeclNodes.inc"
237+
238+
#define DECL(CLASS, BASE) \
239+
bool WalkUpFrom##CLASS##Decl(CLASS##Decl *D); \
240+
virtual bool Visit##CLASS##Decl(CLASS##Decl *D) { return true; }
241+
#include "clang/AST/DeclNodes.inc"
242+
243+
// Stmts.
244+
#define ABSTRACT_STMT(STMT)
245+
#define STMT(CLASS, PARENT) virtual bool Traverse##CLASS(CLASS *S);
246+
#include "clang/AST/StmtNodes.inc"
247+
248+
#define STMT(CLASS, PARENT) \
249+
bool WalkUpFrom##CLASS(CLASS *S); \
250+
virtual bool Visit##CLASS(CLASS *S) { return true; }
251+
#include "clang/AST/StmtNodes.inc"
252+
253+
// Types.
254+
#define ABSTRACT_TYPE(CLASS, BASE)
255+
#define TYPE(CLASS, BASE) virtual bool Traverse##CLASS##Type(CLASS##Type *T);
256+
#include "clang/AST/TypeNodes.inc"
257+
258+
#define TYPE(CLASS, BASE) \
259+
bool WalkUpFrom##CLASS##Type(CLASS##Type *T); \
260+
virtual bool Visit##CLASS##Type(CLASS##Type *T) { return true; }
261+
#include "clang/AST/TypeNodes.inc"
262+
263+
// TypeLocs.
264+
#define ABSTRACT_TYPELOC(CLASS, BASE)
265+
#define TYPELOC(CLASS, BASE) \
266+
virtual bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL);
267+
#include "clang/AST/TypeLocNodes.def"
268+
269+
#define TYPELOC(CLASS, BASE) \
270+
bool WalkUpFrom##CLASS##TypeLoc(CLASS##TypeLoc TL); \
271+
virtual bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TL) { return true; }
272+
#include "clang/AST/TypeLocNodes.def"
273+
};
274+
} // namespace clang
275+
276+
#endif // LLVM_CLANG_AST_DYNAMIC_RECURSIVE_AST_VISITOR_H

clang/lib/AST/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ add_clang_library(clangAST
5353
DeclOpenMP.cpp
5454
DeclPrinter.cpp
5555
DeclTemplate.cpp
56+
DynamicRecursiveASTVisitor.cpp
5657
ParentMapContext.cpp
5758
Expr.cpp
5859
ExprClassification.cpp

0 commit comments

Comments
 (0)