clang 23.0.0git
DynamicRecursiveASTVisitor.cpp
Go to the documentation of this file.
1//=== DynamicRecursiveASTVisitor.cpp - Dynamic AST Visitor Implementation -===//
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 implements DynamicRecursiveASTVisitor in terms of the CRTP-based
10// RecursiveASTVisitor.
11//
12//===----------------------------------------------------------------------===//
15
16using namespace clang;
17
18// The implementation of DRAV deserves some explanation:
19//
20// We want to implement DynamicRecursiveASTVisitor without having to inherit or
21// reference RecursiveASTVisitor in any way in the header: if we instantiate
22// RAV in the header, then every user of (or rather every file that uses) DRAV
23// still has to instantiate a RAV, which gets us nowhere. Moreover, even just
24// including RecursiveASTVisitor.h would probably cause some amount of slowdown
25// because we'd have to parse a huge template. For these reasons, the fact that
26// DRAV is implemented using a RAV is solely an implementation detail.
27//
28// As for the implementation itself, DRAV by default acts exactly like a RAV
29// that overrides none of RAV's functions. There are two parts to this:
30//
31// 1. Any function in DRAV has to act like the corresponding function in RAV,
32// unless overridden by a derived class, of course.
33//
34// 2. Any call to a function by the RAV implementation that DRAV allows to be
35// overridden must be transformed to a virtual call on the user-provided
36// DRAV object: if some function in RAV calls e.g. TraverseCallExpr()
37// during traversal, then the derived class's TraverseCallExpr() must be
38// called (provided it overrides TraverseCallExpr()).
39//
40// The 'Impl' class is a helper that connects the two implementations; it is
41// a wrapper around a reference to a DRAV that is itself a RecursiveASTVisitor.
42// It overrides every function in RAV *that is virtual in DRAV* to perform a
43// virtual call on its DRAV reference. This accomplishes point 2 above.
44//
45// Point 1 is accomplished by, first, having the base class implementation of
46// each of the virtual functions construct an Impl object (which is actually
47// just a no-op), passing in itself so that any virtual calls use the right
48// vtable. Secondly, it then calls RAV's implementation of that same function
49// *on Impl* (using a qualified call so that we actually call into the RAV
50// implementation instead of Impl's version of that same function); this way,
51// we both execute RAV's implementation for this function only and ensure that
52// calls to subsequent functions call into Impl via CRTP (and Impl then calls
53// back into DRAV and so on).
54//
55// While this ends up constructing a lot of Impl instances (almost one per
56// function call), this doesn't really matter since Impl just holds a single
57// pointer, and everything in this file should get inlined into all the DRAV
58// functions here anyway.
59//
60//===----------------------------------------------------------------------===//
61//
62// The following illustrates how a call to an (overridden) function is actually
63// resolved: given some class 'Derived' that derives from DRAV and overrides
64// TraverseStmt(), if we are traversing some AST, and TraverseStmt() is called
65// by the RAV implementation, the following happens:
66//
67// 1. Impl::TraverseStmt() overrides RAV::TraverseStmt() via CRTP, so the
68// former is called.
69//
70// 2. Impl::TraverseStmt() performs a virtual call to the visitor (which is
71// an instance to Derived), so Derived::TraverseStmt() is called.
72//
73// End result: Derived::TraverseStmt() is executed.
74//
75// Suppose some other function, e.g. TraverseCallExpr(), which is NOT overridden
76// by Derived is called, we get:
77//
78// 1. Impl::TraverseCallExpr() overrides RAV::TraverseCallExpr() via CRTP,
79// so the former is called.
80//
81// 2. Impl::TraverseCallExpr() performs a virtual call, but since Derived
82// does not override that function, DRAV::TraverseCallExpr() is called.
83//
84// 3. DRAV::TraverseCallExpr() creates a new instance of Impl, passing in
85// itself (this doesn't change that the pointer is an instance of Derived);
86// it then calls RAV::TraverseCallExpr() on the Impl object, which actually
87// ends up executing RAV's implementation because we used a qualified
88// function call.
89//
90// End result: RAV::TraverseCallExpr() is executed.
91namespace {
92template <bool Const> struct Impl : RecursiveASTVisitor<Impl<Const>> {
93 DynamicRecursiveASTVisitorBase<Const> &Visitor;
94 Impl(DynamicRecursiveASTVisitorBase<Const> &Visitor) : Visitor(Visitor) {}
95
96 bool shouldVisitTemplateInstantiations() const {
97 return Visitor.ShouldVisitTemplateInstantiations;
98 }
99
100 bool shouldWalkTypesOfTypeLocs() const {
101 return Visitor.ShouldWalkTypesOfTypeLocs;
102 }
103
104 bool shouldVisitImplicitCode() const {
105 return Visitor.ShouldVisitImplicitCode;
106 }
107
108 bool shouldVisitLambdaBody() const { return Visitor.ShouldVisitLambdaBody; }
109
110 // Supporting post-order would be very hard because of quirks of the
111 // RAV implementation that only work with CRTP. It also is only used
112 // by less than 5 visitors in the entire code base.
113 bool shouldTraversePostOrder() const { return false; }
114
115 bool TraverseAST(ASTContext &AST) { return Visitor.TraverseAST(AST); }
116 bool TraverseAttr(Attr *At) { return Visitor.TraverseAttr(At); }
117 bool TraverseDecl(Decl *D) { return Visitor.TraverseDecl(D); }
118 bool TraverseType(QualType T, bool TraverseQualifier = true) {
119 return Visitor.TraverseType(T, TraverseQualifier);
120 }
121 bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier = true) {
122 return Visitor.TraverseTypeLoc(TL, TraverseQualifier);
123 }
124 bool TraverseStmt(Stmt *S) { return Visitor.TraverseStmt(S); }
125
126 bool TraverseConstructorInitializer(CXXCtorInitializer *Init) {
127 return Visitor.TraverseConstructorInitializer(Init);
128 }
129
130 bool TraverseTemplateArgument(const TemplateArgument &Arg) {
131 return Visitor.TraverseTemplateArgument(Arg);
132 }
133
134 bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) {
135 return Visitor.TraverseTemplateArgumentLoc(ArgLoc);
136 }
137
138 bool TraverseTemplateName(TemplateName Template) {
139 return Visitor.TraverseTemplateName(Template);
140 }
141
142 bool TraverseObjCProtocolLoc(ObjCProtocolLoc ProtocolLoc) {
143 return Visitor.TraverseObjCProtocolLoc(ProtocolLoc);
144 }
145
146 bool TraverseTypeConstraint(const TypeConstraint *C) {
147 return Visitor.TraverseTypeConstraint(C);
148 }
149 bool TraverseConceptRequirement(concepts::Requirement *R) {
150 return Visitor.TraverseConceptRequirement(R);
151 }
152 bool TraverseConceptTypeRequirement(concepts::TypeRequirement *R) {
153 return Visitor.TraverseConceptTypeRequirement(R);
154 }
155 bool TraverseConceptExprRequirement(concepts::ExprRequirement *R) {
156 return Visitor.TraverseConceptExprRequirement(R);
157 }
158 bool TraverseConceptNestedRequirement(concepts::NestedRequirement *R) {
159 return Visitor.TraverseConceptNestedRequirement(R);
160 }
161
162 bool TraverseConceptReference(ConceptReference *CR) {
163 return Visitor.TraverseConceptReference(CR);
164 }
165
166 bool TraverseOffsetOfNode(const OffsetOfNode *Node) {
167 return Visitor.TraverseOffsetOfNode(Node);
168 }
169 bool VisitOffsetOfNode(const OffsetOfNode *Node) {
170 return Visitor.VisitOffsetOfNode(Node);
171 }
172
173 bool TraverseCXXBaseSpecifier(const CXXBaseSpecifier &Base) {
174 return Visitor.TraverseCXXBaseSpecifier(Base);
175 }
176
177 bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo) {
178 return Visitor.TraverseDeclarationNameInfo(NameInfo);
179 }
180
181 bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,
182 Expr *Init) {
183 return Visitor.TraverseLambdaCapture(LE, C, Init);
184 }
185
186 bool TraverseNestedNameSpecifier(NestedNameSpecifier NNS) {
187 return Visitor.TraverseNestedNameSpecifier(NNS);
188 }
189
190 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
191 return Visitor.TraverseNestedNameSpecifierLoc(NNS);
192 }
193
194 bool VisitConceptReference(ConceptReference *CR) {
195 return Visitor.VisitConceptReference(CR);
196 }
197
198 bool dataTraverseStmtPre(Stmt *S) { return Visitor.dataTraverseStmtPre(S); }
199 bool dataTraverseStmtPost(Stmt *S) { return Visitor.dataTraverseStmtPost(S); }
200
201 // TraverseStmt() always passes in a queue, so we have no choice but to
202 // accept it as a parameter here.
203 bool dataTraverseNode(
204 Stmt *S,
206 // But since we don't support postorder traversal, we don't need it, so
207 // simply discard it here. This way, derived classes don't need to worry
208 // about including it as a parameter that they never use.
209 return Visitor.dataTraverseNode(S);
210 }
211
212 /// Visit a node.
213 bool VisitAttr(Attr *A) { return Visitor.VisitAttr(A); }
214 bool VisitDecl(Decl *D) { return Visitor.VisitDecl(D); }
215 bool VisitStmt(Stmt *S) { return Visitor.VisitStmt(S); }
216 bool VisitType(Type *T) { return Visitor.VisitType(T); }
217 bool VisitTypeLoc(TypeLoc TL) { return Visitor.VisitTypeLoc(TL); }
218
219#define DEF_TRAVERSE_TMPL_INST(kind) \
220 bool TraverseTemplateInstantiations(kind##TemplateDecl *D) { \
221 return Visitor.TraverseTemplateInstantiations(D); \
222 }
225 DEF_TRAVERSE_TMPL_INST(Function)
226#undef DEF_TRAVERSE_TMPL_INST
227
228 // Decls.
229#define ABSTRACT_DECL(DECL)
230#define DECL(CLASS, BASE) \
231 bool Traverse##CLASS##Decl(CLASS##Decl *D) { \
232 return Visitor.Traverse##CLASS##Decl(D); \
233 }
234#include "clang/AST/DeclNodes.inc"
235
236#define DECL(CLASS, BASE) \
237 bool Visit##CLASS##Decl(CLASS##Decl *D) { \
238 return Visitor.Visit##CLASS##Decl(D); \
239 }
240#include "clang/AST/DeclNodes.inc"
241
242 // Stmts.
243#define ABSTRACT_STMT(STMT)
244#define STMT(CLASS, PARENT) \
245 bool Traverse##CLASS(CLASS *S) { return Visitor.Traverse##CLASS(S); }
246#include "clang/AST/StmtNodes.inc"
247
248#define STMT(CLASS, PARENT) \
249 bool Visit##CLASS(CLASS *S) { return Visitor.Visit##CLASS(S); }
250#include "clang/AST/StmtNodes.inc"
251
252 // Types.
253#define ABSTRACT_TYPE(CLASS, BASE)
254#define TYPE(CLASS, BASE) \
255 bool Traverse##CLASS##Type(CLASS##Type *T, bool TraverseQualifier) { \
256 return Visitor.Traverse##CLASS##Type(T, TraverseQualifier); \
257 }
258#include "clang/AST/TypeNodes.inc"
259
260#define TYPE(CLASS, BASE) \
261 bool Visit##CLASS##Type(CLASS##Type *T) { \
262 return Visitor.Visit##CLASS##Type(T); \
263 }
264#include "clang/AST/TypeNodes.inc"
265
266 // TypeLocs.
267#define ABSTRACT_TYPELOC(CLASS, BASE)
268#define TYPELOC(CLASS, BASE) \
269 bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL, bool TraverseQualifier) { \
270 return Visitor.Traverse##CLASS##TypeLoc(TL, TraverseQualifier); \
271 }
272#include "clang/AST/TypeLocNodes.def"
273
274#define TYPELOC(CLASS, BASE) \
275 bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TL) { \
276 return Visitor.Visit##CLASS##TypeLoc(TL); \
277 }
278#include "clang/AST/TypeLocNodes.def"
279};
280} // namespace
281
283
284// Helper macros to forward a call to the base implementation since that
285// ends up getting very verbose otherwise.
286
287// This calls the RecursiveASTVisitor implementation of the same function,
288// stripping any 'const' that the DRAV implementation may have added since
289// the RAV implementation largely doesn't use 'const'.
290#define FORWARD_TO_BASE(Function, Type, RefOrPointer) \
291 template <bool Const> \
292 bool DynamicRecursiveASTVisitorBase<Const>::Function( \
293 MaybeConst<Type> RefOrPointer Param) { \
294 return Impl<Const>(*this).RecursiveASTVisitor<Impl<Const>>::Function( \
295 const_cast<Type RefOrPointer>(Param)); \
296 }
297
298// Same as 'FORWARD_TO_BASE', but doesn't change the parameter type in any way.
299#define FORWARD_TO_BASE_EXACT(Function, Type) \
300 template <bool Const> \
301 bool DynamicRecursiveASTVisitorBase<Const>::Function(Type Param) { \
302 return Impl<Const>(*this).RecursiveASTVisitor<Impl<Const>>::Function( \
303 Param); \
304 }
305
306FORWARD_TO_BASE(TraverseAST, ASTContext, &)
307FORWARD_TO_BASE(TraverseAttr, Attr, *)
308FORWARD_TO_BASE(TraverseConstructorInitializer, CXXCtorInitializer, *)
309FORWARD_TO_BASE(TraverseDecl, Decl, *)
310FORWARD_TO_BASE(TraverseStmt, Stmt, *)
311FORWARD_TO_BASE(TraverseTemplateInstantiations, ClassTemplateDecl, *)
312FORWARD_TO_BASE(TraverseTemplateInstantiations, VarTemplateDecl, *)
313FORWARD_TO_BASE(TraverseTemplateInstantiations, FunctionTemplateDecl, *)
314FORWARD_TO_BASE(TraverseConceptRequirement, concepts::Requirement, *)
315FORWARD_TO_BASE(TraverseConceptTypeRequirement, concepts::TypeRequirement, *)
316FORWARD_TO_BASE(TraverseConceptExprRequirement, concepts::ExprRequirement, *)
317FORWARD_TO_BASE(TraverseConceptReference, ConceptReference, *)
318FORWARD_TO_BASE(TraverseConceptNestedRequirement,
319 concepts::NestedRequirement, *)
320
321FORWARD_TO_BASE_EXACT(TraverseOffsetOfNode, const OffsetOfNode *)
322
323FORWARD_TO_BASE_EXACT(TraverseCXXBaseSpecifier, const CXXBaseSpecifier &)
324FORWARD_TO_BASE_EXACT(TraverseDeclarationNameInfo, DeclarationNameInfo)
325FORWARD_TO_BASE_EXACT(TraverseTemplateArgument, const TemplateArgument &)
326FORWARD_TO_BASE_EXACT(TraverseTemplateArguments, ArrayRef<TemplateArgument>)
327FORWARD_TO_BASE_EXACT(TraverseTemplateArgumentLoc, const TemplateArgumentLoc &)
328FORWARD_TO_BASE_EXACT(TraverseTemplateName, TemplateName)
329FORWARD_TO_BASE_EXACT(TraverseNestedNameSpecifier, NestedNameSpecifier)
330
331template <bool Const>
332bool DynamicRecursiveASTVisitorBase<Const>::TraverseType(
333 QualType T, bool TraverseQualifier) {
334 return Impl<Const>(*this).RecursiveASTVisitor<Impl<Const>>::TraverseType(
335 T, TraverseQualifier);
336}
337
338template <bool Const>
340 TypeLoc TL, bool TraverseQualifier) {
341 return Impl<Const>(*this).RecursiveASTVisitor<Impl<Const>>::TraverseTypeLoc(
342 TL, TraverseQualifier);
343}
344
345FORWARD_TO_BASE_EXACT(TraverseTypeConstraint, const TypeConstraint *)
346FORWARD_TO_BASE_EXACT(TraverseObjCProtocolLoc, ObjCProtocolLoc)
348
349template <bool Const>
353 return Impl<Const>(*this)
354 .RecursiveASTVisitor<Impl<Const>>::TraverseLambdaCapture(
355 const_cast<LambdaExpr *>(LE), C, const_cast<Expr *>(Init));
356}
357
358template <bool Const>
360 MaybeConst<Stmt> *S) {
361 return Impl<Const>(*this).RecursiveASTVisitor<Impl<Const>>::dataTraverseNode(
362 const_cast<Stmt *>(S), nullptr);
363}
364
365// Declare Traverse*() for and friends all concrete Decl classes.
366#define ABSTRACT_DECL(DECL)
367#define DECL(CLASS, BASE) \
368 FORWARD_TO_BASE(Traverse##CLASS##Decl, CLASS##Decl, *) \
369 FORWARD_TO_BASE(WalkUpFrom##CLASS##Decl, CLASS##Decl, *)
370#include "clang/AST/DeclNodes.inc"
371
372// Declare Traverse*() and friends for all concrete Stmt classes.
373#define ABSTRACT_STMT(STMT)
374#define STMT(CLASS, PARENT) FORWARD_TO_BASE(Traverse##CLASS, CLASS, *)
375#include "clang/AST/StmtNodes.inc"
376
377#define STMT(CLASS, PARENT) FORWARD_TO_BASE(WalkUpFrom##CLASS, CLASS, *)
378#include "clang/AST/StmtNodes.inc"
379
380// Declare Traverse*() and friends for all concrete Type classes.
381#define ABSTRACT_TYPE(CLASS, BASE)
382#define TYPE(CLASS, BASE) \
383 template <bool Const> \
384 bool DynamicRecursiveASTVisitorBase<Const>::Traverse##CLASS##Type( \
385 MaybeConst<CLASS##Type> *T, bool TraverseQualifier) { \
386 return Impl<Const>(*this) \
387 .RecursiveASTVisitor<Impl<Const>>::Traverse##CLASS##Type( \
388 const_cast<CLASS##Type *>(T), TraverseQualifier); \
389 } \
390 FORWARD_TO_BASE(WalkUpFrom##CLASS##Type, CLASS##Type, *)
391#include "clang/AST/TypeNodes.inc"
392
393#define ABSTRACT_TYPELOC(CLASS, BASE)
394#define TYPELOC(CLASS, BASE) \
395 template <bool Const> \
396 bool DynamicRecursiveASTVisitorBase<Const>::Traverse##CLASS##TypeLoc( \
397 CLASS##TypeLoc TL, bool TraverseQualifier) { \
398 return Impl<Const>(*this) \
399 .RecursiveASTVisitor<Impl<Const>>::Traverse##CLASS##TypeLoc( \
400 TL, TraverseQualifier); \
401 }
402#include "clang/AST/TypeLocNodes.def"
403
404#define TYPELOC(CLASS, BASE) \
405 FORWARD_TO_BASE_EXACT(WalkUpFrom##CLASS##TypeLoc, CLASS##TypeLoc)
406#include "clang/AST/TypeLocNodes.def"
407
408namespace clang {
411} // namespace clang
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc QualifierLoc)
#define FORWARD_TO_BASE_EXACT(Function, Type)
#define FORWARD_TO_BASE(Function, Type, RefOrPointer)
#define DEF_TRAVERSE_TMPL_INST(kind)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:227
Attr - This represents one attribute.
Definition Attr.h:46
Represents a base class of a C++ class.
Definition DeclCXX.h:146
Represents a C++ base or member initializer.
Definition DeclCXX.h:2385
Declaration of a class template.
A reference to a concept and its template args, as it appears in the code.
Definition ASTConcept.h:130
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
Recursive AST visitor that supports extension via dynamic dispatch.
std::conditional_t< IsConst, const ASTNode, ASTNode > MaybeConst
virtual bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier=true)
Recursively visit a type with location, by dispatching to Traverse*TypeLoc() based on the argument ty...
virtual bool TraverseLambdaCapture(MaybeConst< LambdaExpr > *LE, const LambdaCapture *C, MaybeConst< Expr > *Init)
Recursively visit a lambda capture.
virtual bool dataTraverseNode(MaybeConst< Stmt > *S)
This represents one expression.
Definition Expr.h:112
Declaration of a template function.
Describes the capture of a variable or of this, or of a C++1y init-capture.
A C++ lambda expression, which produces a function object (of unspecified type) that can be invoked l...
Definition ExprCXX.h:1972
A C++ nested-name-specifier augmented with source location information.
Represents a C++ nested name specifier, such as "\::std::vector<int>::".
Helper class for OffsetOfExpr.
Definition Expr.h:2424
A (possibly-)qualified type.
Definition TypeBase.h:937
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
SmallVectorImpl< llvm::PointerIntPair< Stmt *, 1, bool > > DataRecursionQueue
A queue used for performing data recursion over statements.
Stmt - This represents one statement.
Definition Stmt.h:86
Location wrapper for a TemplateArgument.
Represents a template argument.
Represents a C++ template name within the type system.
Models the abbreviated syntax to constrain a template type parameter: template <convertible_to<string...
Definition ASTConcept.h:227
Base wrapper for a particular "section" of type source info.
Definition TypeLoc.h:59
Declaration of a variable template.
The JSON file list parser is used to communicate input to InstallAPI.
@ TemplateName
The identifier is a template name. FIXME: Add an annotation for that.
Definition Parser.h:61
@ Template
We are parsing a template declaration.
Definition Parser.h:81
@ Type
The name was classified as a type.
Definition Sema.h:564
DeclarationNameInfo - A collector data type for bundling together a DeclarationName and the correspon...