Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/AST/DynamicRecursiveASTVisitor.cpp
213766 views
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
375