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 | //===----------------------------------------------------------------------===// |
13 | #include "clang/AST/DynamicRecursiveASTVisitor.h" |
14 | #include "clang/AST/RecursiveASTVisitor.h" |
15 | |
16 | using 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, |
91 | namespace { |
92 | template <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) { return Visitor.TraverseType(T); } |
119 | bool TraverseTypeLoc(TypeLoc TL) { return Visitor.TraverseTypeLoc(TL); } |
120 | bool TraverseStmt(Stmt *S) { return Visitor.TraverseStmt(S); } |
121 | |
122 | bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { |
123 | return Visitor.TraverseConstructorInitializer(Init); |
124 | } |
125 | |
126 | bool TraverseTemplateArgument(const TemplateArgument &Arg) { |
127 | return Visitor.TraverseTemplateArgument(Arg); |
128 | } |
129 | |
130 | bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) { |
131 | return Visitor.TraverseTemplateArgumentLoc(ArgLoc); |
132 | } |
133 | |
134 | bool TraverseTemplateName(TemplateName Template) { |
135 | return Visitor.TraverseTemplateName(Template); |
136 | } |
137 | |
138 | bool TraverseObjCProtocolLoc(ObjCProtocolLoc ProtocolLoc) { |
139 | return Visitor.TraverseObjCProtocolLoc(ProtocolLoc); |
140 | } |
141 | |
142 | bool TraverseTypeConstraint(const TypeConstraint *C) { |
143 | return Visitor.TraverseTypeConstraint(C); |
144 | } |
145 | bool TraverseConceptRequirement(concepts::Requirement *R) { |
146 | return Visitor.TraverseConceptRequirement(R); |
147 | } |
148 | bool TraverseConceptTypeRequirement(concepts::TypeRequirement *R) { |
149 | return Visitor.TraverseConceptTypeRequirement(R); |
150 | } |
151 | bool TraverseConceptExprRequirement(concepts::ExprRequirement *R) { |
152 | return Visitor.TraverseConceptExprRequirement(R); |
153 | } |
154 | bool TraverseConceptNestedRequirement(concepts::NestedRequirement *R) { |
155 | return Visitor.TraverseConceptNestedRequirement(R); |
156 | } |
157 | |
158 | bool TraverseConceptReference(ConceptReference *CR) { |
159 | return Visitor.TraverseConceptReference(CR); |
160 | } |
161 | |
162 | bool TraverseCXXBaseSpecifier(const CXXBaseSpecifier &Base) { |
163 | return Visitor.TraverseCXXBaseSpecifier(Base); |
164 | } |
165 | |
166 | bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo) { |
167 | return Visitor.TraverseDeclarationNameInfo(NameInfo); |
168 | } |
169 | |
170 | bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C, |
171 | Expr *Init) { |
172 | return Visitor.TraverseLambdaCapture(LE, C, Init); |
173 | } |
174 | |
175 | bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) { |
176 | return Visitor.TraverseNestedNameSpecifier(NNS); |
177 | } |
178 | |
179 | bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) { |
180 | return Visitor.TraverseNestedNameSpecifierLoc(NNS); |
181 | } |
182 | |
183 | bool VisitConceptReference(ConceptReference *CR) { |
184 | return Visitor.VisitConceptReference(CR); |
185 | } |
186 | |
187 | bool dataTraverseStmtPre(Stmt *S) { return Visitor.dataTraverseStmtPre(S); } |
188 | bool dataTraverseStmtPost(Stmt *S) { return Visitor.dataTraverseStmtPost(S); } |
189 | |
190 | // TraverseStmt() always passes in a queue, so we have no choice but to |
191 | // accept it as a parameter here. |
192 | bool dataTraverseNode( |
193 | Stmt *S, |
194 | typename RecursiveASTVisitor<Impl>::DataRecursionQueue * = nullptr) { |
195 | // But since we don't support postorder traversal, we don't need it, so |
196 | // simply discard it here. This way, derived classes don't need to worry |
197 | // about including it as a parameter that they never use. |
198 | return Visitor.dataTraverseNode(S); |
199 | } |
200 | |
201 | /// Visit a node. |
202 | bool VisitAttr(Attr *A) { return Visitor.VisitAttr(A); } |
203 | bool VisitDecl(Decl *D) { return Visitor.VisitDecl(D); } |
204 | bool VisitStmt(Stmt *S) { return Visitor.VisitStmt(S); } |
205 | bool VisitType(Type *T) { return Visitor.VisitType(T); } |
206 | bool VisitTypeLoc(TypeLoc TL) { return Visitor.VisitTypeLoc(TL); } |
207 | |
208 | #define DEF_TRAVERSE_TMPL_INST(kind) \ |
209 | bool TraverseTemplateInstantiations(kind##TemplateDecl *D) { \ |
210 | return Visitor.TraverseTemplateInstantiations(D); \ |
211 | } |
212 | DEF_TRAVERSE_TMPL_INST(Class) |
213 | DEF_TRAVERSE_TMPL_INST(Var) |
214 | DEF_TRAVERSE_TMPL_INST(Function) |
215 | #undef DEF_TRAVERSE_TMPL_INST |
216 | |
217 | // Decls. |
218 | #define ABSTRACT_DECL(DECL) |
219 | #define DECL(CLASS, BASE) \ |
220 | bool Traverse##CLASS##Decl(CLASS##Decl *D) { \ |
221 | return Visitor.Traverse##CLASS##Decl(D); \ |
222 | } |
223 | #include "clang/AST/DeclNodes.inc" |
224 | |
225 | #define DECL(CLASS, BASE) \ |
226 | bool Visit##CLASS##Decl(CLASS##Decl *D) { \ |
227 | return Visitor.Visit##CLASS##Decl(D); \ |
228 | } |
229 | #include "clang/AST/DeclNodes.inc" |
230 | |
231 | // Stmts. |
232 | #define ABSTRACT_STMT(STMT) |
233 | #define STMT(CLASS, PARENT) \ |
234 | bool Traverse##CLASS(CLASS *S) { return Visitor.Traverse##CLASS(S); } |
235 | #include "clang/AST/StmtNodes.inc" |
236 | |
237 | #define STMT(CLASS, PARENT) \ |
238 | bool Visit##CLASS(CLASS *S) { return Visitor.Visit##CLASS(S); } |
239 | #include "clang/AST/StmtNodes.inc" |
240 | |
241 | // Types. |
242 | #define ABSTRACT_TYPE(CLASS, BASE) |
243 | #define TYPE(CLASS, BASE) \ |
244 | bool Traverse##CLASS##Type(CLASS##Type *T) { \ |
245 | return Visitor.Traverse##CLASS##Type(T); \ |
246 | } |
247 | #include "clang/AST/TypeNodes.inc" |
248 | |
249 | #define TYPE(CLASS, BASE) \ |
250 | bool Visit##CLASS##Type(CLASS##Type *T) { \ |
251 | return Visitor.Visit##CLASS##Type(T); \ |
252 | } |
253 | #include "clang/AST/TypeNodes.inc" |
254 | |
255 | // TypeLocs. |
256 | #define ABSTRACT_TYPELOC(CLASS, BASE) |
257 | #define TYPELOC(CLASS, BASE) \ |
258 | bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL) { \ |
259 | return Visitor.Traverse##CLASS##TypeLoc(TL); \ |
260 | } |
261 | #include "clang/AST/TypeLocNodes.def" |
262 | |
263 | #define TYPELOC(CLASS, BASE) \ |
264 | bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TL) { \ |
265 | return Visitor.Visit##CLASS##TypeLoc(TL); \ |
266 | } |
267 | #include "clang/AST/TypeLocNodes.def" |
268 | }; |
269 | } // namespace |
270 | |
271 | template <bool Const> void DynamicRecursiveASTVisitorBase<Const>::anchor() {} |
272 | |
273 | // Helper macros to forward a call to the base implementation since that |
274 | // ends up getting very verbose otherwise. |
275 | |
276 | // This calls the RecursiveASTVisitor implementation of the same function, |
277 | // stripping any 'const' that the DRAV implementation may have added since |
278 | // the RAV implementation largely doesn't use 'const'. |
279 | #define FORWARD_TO_BASE(Function, Type, RefOrPointer) \ |
280 | template <bool Const> \ |
281 | bool DynamicRecursiveASTVisitorBase<Const>::Function( \ |
282 | MaybeConst<Type> RefOrPointer Param) { \ |
283 | return Impl<Const>(*this).RecursiveASTVisitor<Impl<Const>>::Function( \ |
284 | const_cast<Type RefOrPointer>(Param)); \ |
285 | } |
286 | |
287 | // Same as 'FORWARD_TO_BASE', but doesn't change the parameter type in any way. |
288 | #define FORWARD_TO_BASE_EXACT(Function, Type) \ |
289 | template <bool Const> \ |
290 | bool DynamicRecursiveASTVisitorBase<Const>::Function(Type Param) { \ |
291 | return Impl<Const>(*this).RecursiveASTVisitor<Impl<Const>>::Function( \ |
292 | Param); \ |
293 | } |
294 | |
295 | FORWARD_TO_BASE(TraverseAST, ASTContext, &) |
296 | FORWARD_TO_BASE(TraverseAttr, Attr, *) |
297 | FORWARD_TO_BASE(TraverseConstructorInitializer, CXXCtorInitializer, *) |
298 | FORWARD_TO_BASE(TraverseDecl, Decl, *) |
299 | FORWARD_TO_BASE(TraverseStmt, Stmt, *) |
300 | FORWARD_TO_BASE(TraverseNestedNameSpecifier, NestedNameSpecifier, *) |
301 | FORWARD_TO_BASE(TraverseTemplateInstantiations, ClassTemplateDecl, *) |
302 | FORWARD_TO_BASE(TraverseTemplateInstantiations, VarTemplateDecl, *) |
303 | FORWARD_TO_BASE(TraverseTemplateInstantiations, FunctionTemplateDecl, *) |
304 | FORWARD_TO_BASE(TraverseConceptRequirement, concepts::Requirement, *) |
305 | FORWARD_TO_BASE(TraverseConceptTypeRequirement, concepts::TypeRequirement, *) |
306 | FORWARD_TO_BASE(TraverseConceptExprRequirement, concepts::ExprRequirement, *) |
307 | FORWARD_TO_BASE(TraverseConceptReference, ConceptReference, *) |
308 | FORWARD_TO_BASE(TraverseConceptNestedRequirement, |
309 | concepts::NestedRequirement, *) |
310 | |
311 | FORWARD_TO_BASE_EXACT(TraverseCXXBaseSpecifier, const CXXBaseSpecifier &) |
312 | FORWARD_TO_BASE_EXACT(TraverseDeclarationNameInfo, DeclarationNameInfo) |
313 | FORWARD_TO_BASE_EXACT(TraverseTemplateArgument, const TemplateArgument &) |
314 | FORWARD_TO_BASE_EXACT(TraverseTemplateArguments, ArrayRef<TemplateArgument>) |
315 | FORWARD_TO_BASE_EXACT(TraverseTemplateArgumentLoc, const TemplateArgumentLoc &) |
316 | FORWARD_TO_BASE_EXACT(TraverseTemplateName, TemplateName) |
317 | FORWARD_TO_BASE_EXACT(TraverseType, QualType) |
318 | FORWARD_TO_BASE_EXACT(TraverseTypeLoc, TypeLoc) |
319 | FORWARD_TO_BASE_EXACT(TraverseTypeConstraint, const TypeConstraint *) |
320 | FORWARD_TO_BASE_EXACT(TraverseObjCProtocolLoc, ObjCProtocolLoc) |
321 | FORWARD_TO_BASE_EXACT(TraverseNestedNameSpecifierLoc, NestedNameSpecifierLoc) |
322 | |
323 | template <bool Const> |
324 | bool DynamicRecursiveASTVisitorBase<Const>::TraverseLambdaCapture( |
325 | MaybeConst<LambdaExpr> *LE, const LambdaCapture *C, |
326 | MaybeConst<Expr> *Init) { |
327 | return Impl<Const>(*this) |
328 | .RecursiveASTVisitor<Impl<Const>>::TraverseLambdaCapture( |
329 | const_cast<LambdaExpr *>(LE), C, const_cast<Expr *>(Init)); |
330 | } |
331 | |
332 | template <bool Const> |
333 | bool DynamicRecursiveASTVisitorBase<Const>::dataTraverseNode( |
334 | MaybeConst<Stmt> *S) { |
335 | return Impl<Const>(*this).RecursiveASTVisitor<Impl<Const>>::dataTraverseNode( |
336 | const_cast<Stmt *>(S), nullptr); |
337 | } |
338 | |
339 | // Declare Traverse*() for and friends all concrete Decl classes. |
340 | #define ABSTRACT_DECL(DECL) |
341 | #define DECL(CLASS, BASE) \ |
342 | FORWARD_TO_BASE(Traverse##CLASS##Decl, CLASS##Decl, *) \ |
343 | FORWARD_TO_BASE(WalkUpFrom##CLASS##Decl, CLASS##Decl, *) |
344 | #include "clang/AST/DeclNodes.inc" |
345 | |
346 | // Declare Traverse*() and friends for all concrete Stmt classes. |
347 | #define ABSTRACT_STMT(STMT) |
348 | #define STMT(CLASS, PARENT) FORWARD_TO_BASE(Traverse##CLASS, CLASS, *) |
349 | #include "clang/AST/StmtNodes.inc" |
350 | |
351 | #define STMT(CLASS, PARENT) FORWARD_TO_BASE(WalkUpFrom##CLASS, CLASS, *) |
352 | #include "clang/AST/StmtNodes.inc" |
353 | |
354 | // Declare Traverse*() and friends for all concrete Type classes. |
355 | #define ABSTRACT_TYPE(CLASS, BASE) |
356 | #define TYPE(CLASS, BASE) \ |
357 | FORWARD_TO_BASE(Traverse##CLASS##Type, CLASS##Type, *) \ |
358 | FORWARD_TO_BASE(WalkUpFrom##CLASS##Type, CLASS##Type, *) |
359 | #include "clang/AST/TypeNodes.inc" |
360 | |
361 | #define ABSTRACT_TYPELOC(CLASS, BASE) |
362 | #define TYPELOC(CLASS, BASE) \ |
363 | FORWARD_TO_BASE_EXACT(Traverse##CLASS##TypeLoc, CLASS##TypeLoc) |
364 | #include "clang/AST/TypeLocNodes.def" |
365 | |
366 | #define TYPELOC(CLASS, BASE) \ |
367 | FORWARD_TO_BASE_EXACT(WalkUpFrom##CLASS##TypeLoc, CLASS##TypeLoc) |
368 | #include "clang/AST/TypeLocNodes.def" |
369 | |
370 | namespace clang { |
371 | template class DynamicRecursiveASTVisitorBase<false>; |
372 | template class DynamicRecursiveASTVisitorBase<true>; |
373 | } // namespace clang |
374 |
Definitions
- Impl
- Impl
- shouldVisitTemplateInstantiations
- shouldWalkTypesOfTypeLocs
- shouldVisitImplicitCode
- shouldVisitLambdaBody
- shouldTraversePostOrder
- TraverseAST
- TraverseAttr
- TraverseDecl
- TraverseType
- TraverseTypeLoc
- TraverseStmt
- TraverseConstructorInitializer
- TraverseTemplateArgument
- TraverseTemplateArgumentLoc
- TraverseTemplateName
- TraverseObjCProtocolLoc
- TraverseTypeConstraint
- TraverseConceptRequirement
- TraverseConceptTypeRequirement
- TraverseConceptExprRequirement
- TraverseConceptNestedRequirement
- TraverseConceptReference
- TraverseCXXBaseSpecifier
- TraverseDeclarationNameInfo
- TraverseLambdaCapture
- TraverseNestedNameSpecifier
- TraverseNestedNameSpecifierLoc
- VisitConceptReference
- dataTraverseStmtPre
- dataTraverseStmtPost
- dataTraverseNode
- VisitAttr
- VisitDecl
- VisitStmt
- VisitType
- VisitTypeLoc
- TraverseTemplateInstantiations
- TraverseTemplateInstantiations
- TraverseTemplateInstantiations
- anchor
- TraverseAST
- TraverseAttr
- TraverseConstructorInitializer
- TraverseDecl
- TraverseStmt
- TraverseNestedNameSpecifier
- TraverseTemplateInstantiations
- TraverseTemplateInstantiations
- TraverseTemplateInstantiations
- TraverseConceptRequirement
- TraverseConceptTypeRequirement
- TraverseConceptExprRequirement
- TraverseConceptReference
- TraverseConceptNestedRequirement
- TraverseCXXBaseSpecifier
- TraverseDeclarationNameInfo
- TraverseTemplateArgument
- TraverseTemplateArguments
- TraverseTemplateArgumentLoc
- TraverseTemplateName
- TraverseType
- TraverseTypeLoc
- TraverseTypeConstraint
- TraverseObjCProtocolLoc
- TraverseNestedNameSpecifierLoc
- TraverseLambdaCapture
Improve your Profiling and Debugging skills
Find out more