1 | //===--- ASTNodeTraverser.h - Traversal of AST nodes ----------------------===// |
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 the AST traversal facilities. Other users |
10 | // of this class may make use of the same traversal logic by inheriting it, |
11 | // similar to RecursiveASTVisitor. |
12 | // |
13 | //===----------------------------------------------------------------------===// |
14 | |
15 | #ifndef LLVM_CLANG_AST_ASTNODETRAVERSER_H |
16 | #define LLVM_CLANG_AST_ASTNODETRAVERSER_H |
17 | |
18 | #include "clang/AST/ASTTypeTraits.h" |
19 | #include "clang/AST/AttrVisitor.h" |
20 | #include "clang/AST/CommentVisitor.h" |
21 | #include "clang/AST/DeclVisitor.h" |
22 | #include "clang/AST/LocInfoType.h" |
23 | #include "clang/AST/StmtVisitor.h" |
24 | #include "clang/AST/TemplateArgumentVisitor.h" |
25 | #include "clang/AST/Type.h" |
26 | #include "clang/AST/TypeLocVisitor.h" |
27 | #include "clang/AST/TypeVisitor.h" |
28 | #include "llvm/Support/SaveAndRestore.h" |
29 | |
30 | namespace clang { |
31 | |
32 | class APValue; |
33 | |
34 | /** |
35 | |
36 | ASTNodeTraverser traverses the Clang AST for dumping purposes. |
37 | |
38 | The `Derived::doGetNodeDelegate()` method is required to be an accessible member |
39 | which returns a reference of type `NodeDelegateType &` which implements the |
40 | following interface: |
41 | |
42 | struct { |
43 | template <typename Fn> void AddChild(Fn DoAddChild); |
44 | template <typename Fn> void AddChild(StringRef Label, Fn DoAddChild); |
45 | |
46 | void Visit(const comments::Comment *C, const comments::FullComment *FC); |
47 | void Visit(const Attr *A); |
48 | void Visit(const TemplateArgument &TA, SourceRange R = {}, |
49 | const Decl *From = nullptr, StringRef Label = {}); |
50 | void Visit(const Stmt *Node); |
51 | void Visit(const Type *T); |
52 | void Visit(QualType T); |
53 | void Visit(TypeLoc); |
54 | void Visit(const Decl *D); |
55 | void Visit(const CXXCtorInitializer *Init); |
56 | void Visit(const OMPClause *C); |
57 | void Visit(const BlockDecl::Capture &C); |
58 | void Visit(const GenericSelectionExpr::ConstAssociation &A); |
59 | void Visit(const concepts::Requirement *R); |
60 | void Visit(const APValue &Value, QualType Ty); |
61 | }; |
62 | */ |
63 | template <typename Derived, typename NodeDelegateType> |
64 | class ASTNodeTraverser |
65 | : public ConstDeclVisitor<Derived>, |
66 | public ConstStmtVisitor<Derived>, |
67 | public comments::ConstCommentVisitor<Derived, void, |
68 | const comments::FullComment *>, |
69 | public TypeVisitor<Derived>, |
70 | public TypeLocVisitor<Derived>, |
71 | public ConstAttrVisitor<Derived>, |
72 | public ConstTemplateArgumentVisitor<Derived> { |
73 | |
74 | /// Indicates whether we should trigger deserialization of nodes that had |
75 | /// not already been loaded. |
76 | bool Deserialize = false; |
77 | |
78 | /// Tracks whether we should dump TypeLocs etc. |
79 | /// |
80 | /// Detailed location information such as TypeLoc nodes is not usually |
81 | /// included in the dump (too verbose). |
82 | /// But when explicitly asked to dump a Loc node, we do so recursively, |
83 | /// including e.g. FunctionTypeLoc => ParmVarDecl => TypeLoc. |
84 | bool VisitLocs = false; |
85 | |
86 | TraversalKind Traversal = TraversalKind::TK_AsIs; |
87 | |
88 | NodeDelegateType &getNodeDelegate() { |
89 | return getDerived().doGetNodeDelegate(); |
90 | } |
91 | Derived &getDerived() { return *static_cast<Derived *>(this); } |
92 | |
93 | public: |
94 | void setDeserialize(bool D) { Deserialize = D; } |
95 | bool getDeserialize() const { return Deserialize; } |
96 | |
97 | void SetTraversalKind(TraversalKind TK) { Traversal = TK; } |
98 | TraversalKind GetTraversalKind() const { return Traversal; } |
99 | |
100 | void Visit(const Decl *D, bool VisitLocs = false) { |
101 | if (Traversal == TK_IgnoreUnlessSpelledInSource && D->isImplicit()) |
102 | return; |
103 | |
104 | getNodeDelegate().AddChild([=] { |
105 | getNodeDelegate().Visit(D); |
106 | if (!D) |
107 | return; |
108 | |
109 | { |
110 | llvm::SaveAndRestore RestoreVisitLocs(this->VisitLocs, VisitLocs); |
111 | ConstDeclVisitor<Derived>::Visit(D); |
112 | } |
113 | |
114 | for (const auto &A : D->attrs()) |
115 | Visit(A); |
116 | |
117 | if (const comments::FullComment * = |
118 | D->getASTContext().getLocalCommentForDeclUncached(D)) |
119 | Visit(Comment, Comment); |
120 | |
121 | // Decls within functions are visited by the body. |
122 | if (!isa<FunctionDecl, ObjCMethodDecl, BlockDecl>(*D)) { |
123 | if (Traversal != TK_AsIs) { |
124 | if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) { |
125 | auto SK = CTSD->getSpecializationKind(); |
126 | if (SK == TSK_ExplicitInstantiationDeclaration || |
127 | SK == TSK_ExplicitInstantiationDefinition) |
128 | return; |
129 | } |
130 | } |
131 | if (const auto *DC = dyn_cast<DeclContext>(D)) |
132 | dumpDeclContext(DC: DC); |
133 | } |
134 | }); |
135 | } |
136 | |
137 | void Visit(const Stmt *Node, StringRef Label = {}) { |
138 | getNodeDelegate().AddChild(Label, [=] { |
139 | const Stmt *S = Node; |
140 | |
141 | if (auto *E = dyn_cast_or_null<Expr>(S)) { |
142 | switch (Traversal) { |
143 | case TK_AsIs: |
144 | break; |
145 | case TK_IgnoreUnlessSpelledInSource: |
146 | S = E->IgnoreUnlessSpelledInSource(); |
147 | break; |
148 | } |
149 | } |
150 | |
151 | getNodeDelegate().Visit(S); |
152 | |
153 | if (!S) { |
154 | return; |
155 | } |
156 | |
157 | ConstStmtVisitor<Derived>::Visit(S); |
158 | |
159 | // Some statements have custom mechanisms for dumping their children. |
160 | if (isa<DeclStmt>(S) || isa<GenericSelectionExpr>(S) || |
161 | isa<RequiresExpr>(S)) |
162 | return; |
163 | |
164 | if (Traversal == TK_IgnoreUnlessSpelledInSource && |
165 | isa<LambdaExpr, CXXForRangeStmt, CallExpr, |
166 | CXXRewrittenBinaryOperator>(S)) |
167 | return; |
168 | |
169 | for (const Stmt *SubStmt : S->children()) |
170 | Visit(SubStmt); |
171 | }); |
172 | } |
173 | |
174 | void Visit(QualType T) { |
175 | SplitQualType SQT = T.split(); |
176 | if (!SQT.Quals.hasQualifiers()) |
177 | return Visit(SQT.Ty); |
178 | |
179 | getNodeDelegate().AddChild([=] { |
180 | getNodeDelegate().Visit(T); |
181 | Visit(T.split().Ty); |
182 | }); |
183 | } |
184 | |
185 | void Visit(const Type *T) { |
186 | getNodeDelegate().AddChild([=] { |
187 | getNodeDelegate().Visit(T); |
188 | if (!T) |
189 | return; |
190 | TypeVisitor<Derived>::Visit(T); |
191 | |
192 | QualType SingleStepDesugar = |
193 | T->getLocallyUnqualifiedSingleStepDesugaredType(); |
194 | if (SingleStepDesugar != QualType(T, 0)) |
195 | Visit(SingleStepDesugar); |
196 | }); |
197 | } |
198 | |
199 | void Visit(TypeLoc T) { |
200 | getNodeDelegate().AddChild([=] { |
201 | getNodeDelegate().Visit(T); |
202 | if (T.isNull()) |
203 | return; |
204 | TypeLocVisitor<Derived>::Visit(T); |
205 | if (auto Inner = T.getNextTypeLoc()) |
206 | Visit(Inner); |
207 | }); |
208 | } |
209 | |
210 | void Visit(const Attr *A) { |
211 | getNodeDelegate().AddChild([=] { |
212 | getNodeDelegate().Visit(A); |
213 | ConstAttrVisitor<Derived>::Visit(A); |
214 | }); |
215 | } |
216 | |
217 | void Visit(const CXXCtorInitializer *Init) { |
218 | if (Traversal == TK_IgnoreUnlessSpelledInSource && !Init->isWritten()) |
219 | return; |
220 | getNodeDelegate().AddChild([=] { |
221 | getNodeDelegate().Visit(Init); |
222 | Visit(Init->getInit()); |
223 | }); |
224 | } |
225 | |
226 | void Visit(const TemplateArgument &A, SourceRange R = {}, |
227 | const Decl *From = nullptr, const char *Label = nullptr) { |
228 | getNodeDelegate().AddChild([=] { |
229 | getNodeDelegate().Visit(A, R, From, Label); |
230 | ConstTemplateArgumentVisitor<Derived>::Visit(A); |
231 | }); |
232 | } |
233 | |
234 | void Visit(const BlockDecl::Capture &C) { |
235 | getNodeDelegate().AddChild([=] { |
236 | getNodeDelegate().Visit(C); |
237 | if (C.hasCopyExpr()) |
238 | Visit(C.getCopyExpr()); |
239 | }); |
240 | } |
241 | |
242 | void Visit(const OMPClause *C) { |
243 | getNodeDelegate().AddChild([=] { |
244 | getNodeDelegate().Visit(C); |
245 | for (const auto *S : C->children()) |
246 | Visit(S); |
247 | }); |
248 | } |
249 | |
250 | void Visit(const GenericSelectionExpr::ConstAssociation &A) { |
251 | getNodeDelegate().AddChild([=] { |
252 | getNodeDelegate().Visit(A); |
253 | if (const TypeSourceInfo *TSI = A.getTypeSourceInfo()) |
254 | Visit(TSI->getType()); |
255 | Visit(A.getAssociationExpr()); |
256 | }); |
257 | } |
258 | |
259 | void Visit(const concepts::Requirement *R) { |
260 | getNodeDelegate().AddChild([=] { |
261 | getNodeDelegate().Visit(R); |
262 | if (!R) |
263 | return; |
264 | if (auto *TR = dyn_cast<concepts::TypeRequirement>(R)) { |
265 | if (!TR->isSubstitutionFailure()) |
266 | Visit(TR->getType()->getType().getTypePtr()); |
267 | } else if (auto *ER = dyn_cast<concepts::ExprRequirement>(R)) { |
268 | if (!ER->isExprSubstitutionFailure()) |
269 | Visit(ER->getExpr()); |
270 | if (!ER->getReturnTypeRequirement().isEmpty()) |
271 | Visit(ER->getReturnTypeRequirement() |
272 | .getTypeConstraint() |
273 | ->getImmediatelyDeclaredConstraint()); |
274 | } else if (auto *NR = dyn_cast<concepts::NestedRequirement>(R)) { |
275 | if (!NR->hasInvalidConstraint()) |
276 | Visit(NR->getConstraintExpr()); |
277 | } |
278 | }); |
279 | } |
280 | |
281 | void Visit(const ConceptReference *R) { |
282 | getNodeDelegate().AddChild([=] { getNodeDelegate().Visit(R); }); |
283 | } |
284 | |
285 | void Visit(const APValue &Value, QualType Ty) { |
286 | getNodeDelegate().AddChild([=] { getNodeDelegate().Visit(Value, Ty); }); |
287 | } |
288 | |
289 | void (const comments::Comment *C, const comments::FullComment *FC) { |
290 | getNodeDelegate().AddChild([=] { |
291 | getNodeDelegate().Visit(C, FC); |
292 | if (!C) { |
293 | return; |
294 | } |
295 | comments::ConstCommentVisitor<Derived, void, |
296 | const comments::FullComment *>::visit(C, |
297 | FC); |
298 | for (comments::Comment::child_iterator I = C->child_begin(), |
299 | E = C->child_end(); |
300 | I != E; ++I) |
301 | Visit(*I, FC); |
302 | }); |
303 | } |
304 | |
305 | void Visit(const DynTypedNode &N) { |
306 | // FIXME: Improve this with a switch or a visitor pattern. |
307 | if (const auto *D = N.get<Decl>()) |
308 | Visit(D); |
309 | else if (const auto *S = N.get<Stmt>()) |
310 | Visit(S); |
311 | else if (const auto *QT = N.get<QualType>()) |
312 | Visit(*QT); |
313 | else if (const auto *T = N.get<Type>()) |
314 | Visit(T); |
315 | else if (const auto *TL = N.get<TypeLoc>()) |
316 | Visit(*TL); |
317 | else if (const auto *C = N.get<CXXCtorInitializer>()) |
318 | Visit(C); |
319 | else if (const auto *C = N.get<OMPClause>()) |
320 | Visit(C); |
321 | else if (const auto *T = N.get<TemplateArgument>()) |
322 | Visit(*T); |
323 | else if (const auto *CR = N.get<ConceptReference>()) |
324 | Visit(CR); |
325 | } |
326 | |
327 | void dumpDeclContext(const DeclContext *DC) { |
328 | if (!DC) |
329 | return; |
330 | |
331 | for (const auto *D : (Deserialize ? DC->decls() : DC->noload_decls())) |
332 | Visit(D); |
333 | } |
334 | |
335 | void dumpTemplateParameters(const TemplateParameterList *TPL) { |
336 | if (!TPL) |
337 | return; |
338 | |
339 | for (const auto &TP : *TPL) |
340 | Visit(TP); |
341 | |
342 | if (const Expr *RC = TPL->getRequiresClause()) |
343 | Visit(RC); |
344 | } |
345 | |
346 | void |
347 | dumpASTTemplateArgumentListInfo(const ASTTemplateArgumentListInfo *TALI) { |
348 | if (!TALI) |
349 | return; |
350 | |
351 | for (const auto &TA : TALI->arguments()) |
352 | dumpTemplateArgumentLoc(TA); |
353 | } |
354 | |
355 | void dumpTemplateArgumentLoc(const TemplateArgumentLoc &A, |
356 | const Decl *From = nullptr, |
357 | const char *Label = nullptr) { |
358 | Visit(A.getArgument(), A.getSourceRange(), From, Label); |
359 | } |
360 | |
361 | void dumpTemplateArgumentList(const TemplateArgumentList &TAL) { |
362 | for (unsigned i = 0, e = TAL.size(); i < e; ++i) |
363 | Visit(TAL[i]); |
364 | } |
365 | |
366 | void dumpObjCTypeParamList(const ObjCTypeParamList *typeParams) { |
367 | if (!typeParams) |
368 | return; |
369 | |
370 | for (const auto &typeParam : *typeParams) { |
371 | Visit(typeParam); |
372 | } |
373 | } |
374 | |
375 | void VisitComplexType(const ComplexType *T) { Visit(T->getElementType()); } |
376 | void VisitLocInfoType(const LocInfoType *T) { |
377 | Visit(T->getTypeSourceInfo()->getTypeLoc()); |
378 | } |
379 | void VisitPointerType(const PointerType *T) { Visit(T->getPointeeType()); } |
380 | void VisitBlockPointerType(const BlockPointerType *T) { |
381 | Visit(T->getPointeeType()); |
382 | } |
383 | void VisitReferenceType(const ReferenceType *T) { |
384 | Visit(T->getPointeeType()); |
385 | } |
386 | void VisitMemberPointerType(const MemberPointerType *T) { |
387 | Visit(T->getClass()); |
388 | Visit(T->getPointeeType()); |
389 | } |
390 | void VisitArrayType(const ArrayType *T) { Visit(T->getElementType()); } |
391 | void VisitVariableArrayType(const VariableArrayType *T) { |
392 | VisitArrayType(T); |
393 | Visit(T->getSizeExpr()); |
394 | } |
395 | void VisitDependentSizedArrayType(const DependentSizedArrayType *T) { |
396 | Visit(T->getElementType()); |
397 | Visit(T->getSizeExpr()); |
398 | } |
399 | void VisitDependentSizedExtVectorType(const DependentSizedExtVectorType *T) { |
400 | Visit(T->getElementType()); |
401 | Visit(T->getSizeExpr()); |
402 | } |
403 | void VisitVectorType(const VectorType *T) { Visit(T->getElementType()); } |
404 | void VisitFunctionType(const FunctionType *T) { Visit(T->getReturnType()); } |
405 | void VisitFunctionProtoType(const FunctionProtoType *T) { |
406 | VisitFunctionType(T); |
407 | for (const QualType &PT : T->getParamTypes()) |
408 | Visit(PT); |
409 | } |
410 | void VisitTypeOfExprType(const TypeOfExprType *T) { |
411 | Visit(T->getUnderlyingExpr()); |
412 | } |
413 | void VisitDecltypeType(const DecltypeType *T) { |
414 | Visit(T->getUnderlyingExpr()); |
415 | } |
416 | |
417 | void VisitPackIndexingType(const PackIndexingType *T) { |
418 | Visit(T->getPattern()); |
419 | Visit(T->getIndexExpr()); |
420 | } |
421 | |
422 | void VisitUnaryTransformType(const UnaryTransformType *T) { |
423 | Visit(T->getBaseType()); |
424 | } |
425 | void VisitAttributedType(const AttributedType *T) { |
426 | // FIXME: AttrKind |
427 | if (T->getModifiedType() != T->getEquivalentType()) |
428 | Visit(T->getModifiedType()); |
429 | } |
430 | void VisitBTFTagAttributedType(const BTFTagAttributedType *T) { |
431 | Visit(T->getWrappedType()); |
432 | } |
433 | void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *) {} |
434 | void |
435 | VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T) { |
436 | Visit(T->getArgumentPack()); |
437 | } |
438 | void VisitTemplateSpecializationType(const TemplateSpecializationType *T) { |
439 | for (const auto &Arg : T->template_arguments()) |
440 | Visit(Arg); |
441 | } |
442 | void VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { |
443 | Visit(T->getPointeeType()); |
444 | } |
445 | void VisitAtomicType(const AtomicType *T) { Visit(T->getValueType()); } |
446 | void VisitPipeType(const PipeType *T) { Visit(T->getElementType()); } |
447 | void VisitAdjustedType(const AdjustedType *T) { Visit(T->getOriginalType()); } |
448 | void VisitPackExpansionType(const PackExpansionType *T) { |
449 | if (!T->isSugared()) |
450 | Visit(T->getPattern()); |
451 | } |
452 | void VisitAutoType(const AutoType *T) { |
453 | for (const auto &Arg : T->getTypeConstraintArguments()) |
454 | Visit(Arg); |
455 | } |
456 | // FIXME: ElaboratedType, DependentNameType, |
457 | // DependentTemplateSpecializationType, ObjCObjectType |
458 | |
459 | // For TypeLocs, we automatically visit the inner type loc (pointee type etc). |
460 | // We must explicitly visit other lexically-nested nodes. |
461 | void VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { |
462 | TypeLocVisitor<Derived>::VisitFunctionTypeLoc(TL); |
463 | for (const auto *Param : TL.getParams()) |
464 | Visit(Param, /*VisitTypeLocs=*/true); |
465 | } |
466 | void VisitAutoTypeLoc(AutoTypeLoc TL) { |
467 | if (const auto *CR = TL.getConceptReference()) { |
468 | if (auto *Args = CR->getTemplateArgsAsWritten()) |
469 | for (const auto &Arg : Args->arguments()) |
470 | dumpTemplateArgumentLoc(Arg); |
471 | } |
472 | } |
473 | void VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { |
474 | Visit(TL.getClassTInfo()->getTypeLoc()); |
475 | } |
476 | void VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) { |
477 | Visit(TL.getSizeExpr()); |
478 | } |
479 | void VisitDependentSizedArrayTypeLoc(DependentSizedArrayTypeLoc TL) { |
480 | Visit(TL.getSizeExpr()); |
481 | } |
482 | void VisitDependentSizedExtVectorTypeLoc(DependentSizedExtVectorTypeLoc TL) { |
483 | Visit(cast<DependentSizedExtVectorType>(TL.getType())->getSizeExpr()); |
484 | } |
485 | void VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { |
486 | Visit(TL.getUnderlyingExpr()); |
487 | } |
488 | void VisitDecltypeType(DecltypeType TL) { |
489 | Visit(TL.getUnderlyingExpr()); |
490 | } |
491 | void VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) { |
492 | for (unsigned I=0, N=TL.getNumArgs(); I < N; ++I) |
493 | dumpTemplateArgumentLoc(A: TL.getArgLoc(i: I)); |
494 | } |
495 | void VisitDependentTemplateSpecializationTypeLoc( |
496 | DependentTemplateSpecializationTypeLoc TL) { |
497 | for (unsigned I=0, N=TL.getNumArgs(); I < N; ++I) |
498 | dumpTemplateArgumentLoc(A: TL.getArgLoc(i: I)); |
499 | } |
500 | |
501 | void VisitTypedefDecl(const TypedefDecl *D) { Visit(D->getUnderlyingType()); } |
502 | |
503 | void VisitEnumConstantDecl(const EnumConstantDecl *D) { |
504 | if (const Expr *Init = D->getInitExpr()) |
505 | Visit(Init); |
506 | } |
507 | |
508 | void VisitFunctionDecl(const FunctionDecl *D) { |
509 | if (FunctionTemplateSpecializationInfo *FTSI = |
510 | D->getTemplateSpecializationInfo()) |
511 | dumpTemplateArgumentList(TAL: *FTSI->TemplateArguments); |
512 | else if (DependentFunctionTemplateSpecializationInfo *DFTSI = |
513 | D->getDependentSpecializationInfo()) |
514 | dumpASTTemplateArgumentListInfo(TALI: DFTSI->TemplateArgumentsAsWritten); |
515 | |
516 | if (D->param_begin()) |
517 | for (const auto *Parameter : D->parameters()) |
518 | Visit(Parameter); |
519 | |
520 | if (const Expr *TRC = D->getTrailingRequiresClause()) |
521 | Visit(TRC); |
522 | |
523 | if (Traversal == TK_IgnoreUnlessSpelledInSource && D->isDefaulted()) |
524 | return; |
525 | |
526 | if (const auto *C = dyn_cast<CXXConstructorDecl>(D)) |
527 | for (const auto *I : C->inits()) |
528 | Visit(I); |
529 | |
530 | if (D->doesThisDeclarationHaveABody()) |
531 | Visit(D->getBody()); |
532 | } |
533 | |
534 | void VisitFieldDecl(const FieldDecl *D) { |
535 | if (D->isBitField()) |
536 | Visit(D->getBitWidth()); |
537 | if (Expr *Init = D->getInClassInitializer()) |
538 | Visit(Init); |
539 | } |
540 | |
541 | void VisitVarDecl(const VarDecl *D) { |
542 | if (Traversal == TK_IgnoreUnlessSpelledInSource && D->isCXXForRangeDecl()) |
543 | return; |
544 | |
545 | if (const auto *TSI = D->getTypeSourceInfo(); VisitLocs && TSI) |
546 | Visit(TSI->getTypeLoc()); |
547 | if (D->hasInit()) |
548 | Visit(D->getInit()); |
549 | } |
550 | |
551 | void VisitDecompositionDecl(const DecompositionDecl *D) { |
552 | VisitVarDecl(D); |
553 | for (const auto *B : D->bindings()) |
554 | Visit(B); |
555 | } |
556 | |
557 | void VisitBindingDecl(const BindingDecl *D) { |
558 | if (Traversal == TK_IgnoreUnlessSpelledInSource) |
559 | return; |
560 | |
561 | if (const auto *V = D->getHoldingVar()) |
562 | Visit(V); |
563 | |
564 | if (const auto *E = D->getBinding()) |
565 | Visit(E); |
566 | } |
567 | |
568 | void VisitFileScopeAsmDecl(const FileScopeAsmDecl *D) { |
569 | Visit(D->getAsmString()); |
570 | } |
571 | |
572 | void VisitTopLevelStmtDecl(const TopLevelStmtDecl *D) { Visit(D->getStmt()); } |
573 | |
574 | void VisitCapturedDecl(const CapturedDecl *D) { Visit(D->getBody()); } |
575 | |
576 | void VisitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D) { |
577 | for (const auto *E : D->varlists()) |
578 | Visit(E); |
579 | } |
580 | |
581 | void VisitOMPDeclareReductionDecl(const OMPDeclareReductionDecl *D) { |
582 | Visit(D->getCombiner()); |
583 | if (const auto *Initializer = D->getInitializer()) |
584 | Visit(Initializer); |
585 | } |
586 | |
587 | void VisitOMPDeclareMapperDecl(const OMPDeclareMapperDecl *D) { |
588 | for (const auto *C : D->clauselists()) |
589 | Visit(C); |
590 | } |
591 | |
592 | void VisitOMPCapturedExprDecl(const OMPCapturedExprDecl *D) { |
593 | Visit(D->getInit()); |
594 | } |
595 | |
596 | void VisitOMPAllocateDecl(const OMPAllocateDecl *D) { |
597 | for (const auto *E : D->varlists()) |
598 | Visit(E); |
599 | for (const auto *C : D->clauselists()) |
600 | Visit(C); |
601 | } |
602 | |
603 | template <typename SpecializationDecl> |
604 | void dumpTemplateDeclSpecialization(const SpecializationDecl *D) { |
605 | for (const auto *RedeclWithBadType : D->redecls()) { |
606 | // FIXME: The redecls() range sometimes has elements of a less-specific |
607 | // type. (In particular, ClassTemplateSpecializationDecl::redecls() gives |
608 | // us TagDecls, and should give CXXRecordDecls). |
609 | auto *Redecl = dyn_cast<SpecializationDecl>(RedeclWithBadType); |
610 | if (!Redecl) { |
611 | // Found the injected-class-name for a class template. This will be |
612 | // dumped as part of its surrounding class so we don't need to dump it |
613 | // here. |
614 | assert(isa<CXXRecordDecl>(RedeclWithBadType) && |
615 | "expected an injected-class-name" ); |
616 | continue; |
617 | } |
618 | Visit(Redecl); |
619 | } |
620 | } |
621 | |
622 | template <typename TemplateDecl> |
623 | void dumpTemplateDecl(const TemplateDecl *D) { |
624 | dumpTemplateParameters(TPL: D->getTemplateParameters()); |
625 | |
626 | Visit(D->getTemplatedDecl()); |
627 | |
628 | if (Traversal == TK_AsIs) { |
629 | for (const auto *Child : D->specializations()) |
630 | dumpTemplateDeclSpecialization(Child); |
631 | } |
632 | } |
633 | |
634 | void VisitTypeAliasDecl(const TypeAliasDecl *D) { |
635 | Visit(D->getUnderlyingType()); |
636 | } |
637 | |
638 | void VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D) { |
639 | dumpTemplateParameters(TPL: D->getTemplateParameters()); |
640 | Visit(D->getTemplatedDecl()); |
641 | } |
642 | |
643 | void VisitStaticAssertDecl(const StaticAssertDecl *D) { |
644 | Visit(D->getAssertExpr()); |
645 | Visit(D->getMessage()); |
646 | } |
647 | |
648 | void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) { |
649 | dumpTemplateDecl(D); |
650 | } |
651 | |
652 | void VisitClassTemplateDecl(const ClassTemplateDecl *D) { |
653 | dumpTemplateDecl(D); |
654 | } |
655 | |
656 | void VisitClassTemplateSpecializationDecl( |
657 | const ClassTemplateSpecializationDecl *D) { |
658 | dumpTemplateArgumentList(TAL: D->getTemplateArgs()); |
659 | } |
660 | |
661 | void VisitClassTemplatePartialSpecializationDecl( |
662 | const ClassTemplatePartialSpecializationDecl *D) { |
663 | VisitClassTemplateSpecializationDecl(D); |
664 | dumpTemplateParameters(TPL: D->getTemplateParameters()); |
665 | } |
666 | |
667 | void VisitVarTemplateDecl(const VarTemplateDecl *D) { dumpTemplateDecl(D); } |
668 | |
669 | void VisitBuiltinTemplateDecl(const BuiltinTemplateDecl *D) { |
670 | dumpTemplateParameters(TPL: D->getTemplateParameters()); |
671 | } |
672 | |
673 | void |
674 | VisitVarTemplateSpecializationDecl(const VarTemplateSpecializationDecl *D) { |
675 | dumpTemplateArgumentList(TAL: D->getTemplateArgs()); |
676 | VisitVarDecl(D); |
677 | } |
678 | |
679 | void VisitVarTemplatePartialSpecializationDecl( |
680 | const VarTemplatePartialSpecializationDecl *D) { |
681 | dumpTemplateParameters(TPL: D->getTemplateParameters()); |
682 | VisitVarTemplateSpecializationDecl(D); |
683 | } |
684 | |
685 | void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) { |
686 | if (const auto *TC = D->getTypeConstraint()) |
687 | Visit(TC->getImmediatelyDeclaredConstraint()); |
688 | if (D->hasDefaultArgument()) |
689 | Visit(D->getDefaultArgument(), SourceRange(), |
690 | D->getDefaultArgStorage().getInheritedFrom(), |
691 | D->defaultArgumentWasInherited() ? "inherited from" : "previous" ); |
692 | } |
693 | |
694 | void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) { |
695 | if (const auto *E = D->getPlaceholderTypeConstraint()) |
696 | Visit(E); |
697 | if (D->hasDefaultArgument()) |
698 | Visit(D->getDefaultArgument(), SourceRange(), |
699 | D->getDefaultArgStorage().getInheritedFrom(), |
700 | D->defaultArgumentWasInherited() ? "inherited from" : "previous" ); |
701 | } |
702 | |
703 | void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D) { |
704 | dumpTemplateParameters(TPL: D->getTemplateParameters()); |
705 | if (D->hasDefaultArgument()) |
706 | dumpTemplateArgumentLoc( |
707 | A: D->getDefaultArgument(), From: D->getDefaultArgStorage().getInheritedFrom(), |
708 | Label: D->defaultArgumentWasInherited() ? "inherited from" : "previous" ); |
709 | } |
710 | |
711 | void VisitConceptDecl(const ConceptDecl *D) { |
712 | dumpTemplateParameters(TPL: D->getTemplateParameters()); |
713 | Visit(D->getConstraintExpr()); |
714 | } |
715 | |
716 | void VisitImplicitConceptSpecializationDecl( |
717 | const ImplicitConceptSpecializationDecl *CSD) { |
718 | for (const TemplateArgument &Arg : CSD->getTemplateArguments()) |
719 | Visit(Arg); |
720 | } |
721 | |
722 | void VisitConceptSpecializationExpr(const ConceptSpecializationExpr *CSE) { |
723 | Visit(CSE->getSpecializationDecl()); |
724 | if (CSE->hasExplicitTemplateArgs()) |
725 | for (const auto &ArgLoc : CSE->getTemplateArgsAsWritten()->arguments()) |
726 | dumpTemplateArgumentLoc(ArgLoc); |
727 | } |
728 | |
729 | void VisitUsingShadowDecl(const UsingShadowDecl *D) { |
730 | if (auto *TD = dyn_cast<TypeDecl>(D->getUnderlyingDecl())) |
731 | Visit(TD->getTypeForDecl()); |
732 | } |
733 | |
734 | void VisitFriendDecl(const FriendDecl *D) { |
735 | if (D->getFriendType()) { |
736 | // Traverse any CXXRecordDecl owned by this type, since |
737 | // it will not be in the parent context: |
738 | if (auto *ET = D->getFriendType()->getType()->getAs<ElaboratedType>()) |
739 | if (auto *TD = ET->getOwnedTagDecl()) |
740 | Visit(TD); |
741 | } else { |
742 | Visit(D->getFriendDecl()); |
743 | } |
744 | } |
745 | |
746 | void VisitObjCMethodDecl(const ObjCMethodDecl *D) { |
747 | if (D->isThisDeclarationADefinition()) |
748 | dumpDeclContext(DC: D); |
749 | else |
750 | for (const ParmVarDecl *Parameter : D->parameters()) |
751 | Visit(Parameter); |
752 | |
753 | if (D->hasBody()) |
754 | Visit(D->getBody()); |
755 | } |
756 | |
757 | void VisitObjCCategoryDecl(const ObjCCategoryDecl *D) { |
758 | dumpObjCTypeParamList(typeParams: D->getTypeParamList()); |
759 | } |
760 | |
761 | void VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) { |
762 | dumpObjCTypeParamList(typeParams: D->getTypeParamListAsWritten()); |
763 | } |
764 | |
765 | void VisitObjCImplementationDecl(const ObjCImplementationDecl *D) { |
766 | for (const auto &I : D->inits()) |
767 | Visit(I); |
768 | } |
769 | |
770 | void VisitBlockDecl(const BlockDecl *D) { |
771 | for (const auto &I : D->parameters()) |
772 | Visit(I); |
773 | |
774 | for (const auto &I : D->captures()) |
775 | Visit(I); |
776 | Visit(D->getBody()); |
777 | } |
778 | |
779 | void VisitDeclStmt(const DeclStmt *Node) { |
780 | for (const auto &D : Node->decls()) |
781 | Visit(D); |
782 | } |
783 | |
784 | void VisitAttributedStmt(const AttributedStmt *Node) { |
785 | for (const auto *A : Node->getAttrs()) |
786 | Visit(A); |
787 | } |
788 | |
789 | void VisitCXXCatchStmt(const CXXCatchStmt *Node) { |
790 | Visit(Node->getExceptionDecl()); |
791 | } |
792 | |
793 | void VisitCapturedStmt(const CapturedStmt *Node) { |
794 | Visit(Node->getCapturedDecl()); |
795 | } |
796 | |
797 | void VisitOMPExecutableDirective(const OMPExecutableDirective *Node) { |
798 | for (const auto *C : Node->clauses()) |
799 | Visit(C); |
800 | } |
801 | |
802 | void VisitInitListExpr(const InitListExpr *ILE) { |
803 | if (auto *Filler = ILE->getArrayFiller()) { |
804 | Visit(Filler, "array_filler" ); |
805 | } |
806 | } |
807 | |
808 | void VisitCXXParenListInitExpr(const CXXParenListInitExpr *PLIE) { |
809 | if (auto *Filler = PLIE->getArrayFiller()) { |
810 | Visit(Filler, "array_filler" ); |
811 | } |
812 | } |
813 | |
814 | void VisitBlockExpr(const BlockExpr *Node) { Visit(Node->getBlockDecl()); } |
815 | |
816 | void VisitOpaqueValueExpr(const OpaqueValueExpr *Node) { |
817 | if (Expr *Source = Node->getSourceExpr()) |
818 | Visit(Source); |
819 | } |
820 | |
821 | void VisitGenericSelectionExpr(const GenericSelectionExpr *E) { |
822 | if (E->isExprPredicate()) { |
823 | Visit(E->getControllingExpr()); |
824 | Visit(E->getControllingExpr()->getType()); // FIXME: remove |
825 | } else |
826 | Visit(E->getControllingType()->getType()); |
827 | |
828 | for (const auto Assoc : E->associations()) { |
829 | Visit(Assoc); |
830 | } |
831 | } |
832 | |
833 | void VisitRequiresExpr(const RequiresExpr *E) { |
834 | for (auto *D : E->getLocalParameters()) |
835 | Visit(D); |
836 | for (auto *R : E->getRequirements()) |
837 | Visit(R); |
838 | } |
839 | |
840 | void VisitLambdaExpr(const LambdaExpr *Node) { |
841 | if (Traversal == TK_IgnoreUnlessSpelledInSource) { |
842 | for (unsigned I = 0, N = Node->capture_size(); I != N; ++I) { |
843 | const auto *C = Node->capture_begin() + I; |
844 | if (!C->isExplicit()) |
845 | continue; |
846 | if (Node->isInitCapture(Capture: C)) |
847 | Visit(C->getCapturedVar()); |
848 | else |
849 | Visit(Node->capture_init_begin()[I]); |
850 | } |
851 | dumpTemplateParameters(TPL: Node->getTemplateParameterList()); |
852 | for (const auto *P : Node->getCallOperator()->parameters()) |
853 | Visit(P); |
854 | Visit(Node->getBody()); |
855 | } else { |
856 | return Visit(Node->getLambdaClass()); |
857 | } |
858 | } |
859 | |
860 | void VisitSizeOfPackExpr(const SizeOfPackExpr *Node) { |
861 | if (Node->isPartiallySubstituted()) |
862 | for (const auto &A : Node->getPartialArguments()) |
863 | Visit(A); |
864 | } |
865 | |
866 | void VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E) { |
867 | Visit(E->getParameter()); |
868 | } |
869 | void VisitSubstNonTypeTemplateParmPackExpr( |
870 | const SubstNonTypeTemplateParmPackExpr *E) { |
871 | Visit(E->getParameterPack()); |
872 | Visit(E->getArgumentPack()); |
873 | } |
874 | |
875 | void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node) { |
876 | if (const VarDecl *CatchParam = Node->getCatchParamDecl()) |
877 | Visit(CatchParam); |
878 | } |
879 | |
880 | void VisitCXXForRangeStmt(const CXXForRangeStmt *Node) { |
881 | if (Traversal == TK_IgnoreUnlessSpelledInSource) { |
882 | Visit(Node->getInit()); |
883 | Visit(Node->getLoopVariable()); |
884 | Visit(Node->getRangeInit()); |
885 | Visit(Node->getBody()); |
886 | } |
887 | } |
888 | |
889 | void VisitCallExpr(const CallExpr *Node) { |
890 | for (const auto *Child : |
891 | make_filter_range(Node->children(), [this](const Stmt *Child) { |
892 | if (Traversal != TK_IgnoreUnlessSpelledInSource) |
893 | return false; |
894 | return !isa<CXXDefaultArgExpr>(Child); |
895 | })) { |
896 | Visit(Child); |
897 | } |
898 | } |
899 | |
900 | void VisitCXXRewrittenBinaryOperator(const CXXRewrittenBinaryOperator *Node) { |
901 | if (Traversal == TK_IgnoreUnlessSpelledInSource) { |
902 | Visit(Node->getLHS()); |
903 | Visit(Node->getRHS()); |
904 | } else { |
905 | ConstStmtVisitor<Derived>::VisitCXXRewrittenBinaryOperator(Node); |
906 | } |
907 | } |
908 | |
909 | void VisitExpressionTemplateArgument(const TemplateArgument &TA) { |
910 | Visit(TA.getAsExpr()); |
911 | } |
912 | |
913 | void VisitTypeTemplateArgument(const TemplateArgument &TA) { |
914 | Visit(TA.getAsType()); |
915 | } |
916 | |
917 | void VisitPackTemplateArgument(const TemplateArgument &TA) { |
918 | for (const auto &TArg : TA.pack_elements()) |
919 | Visit(TArg); |
920 | } |
921 | |
922 | // Implements Visit methods for Attrs. |
923 | #include "clang/AST/AttrNodeTraverse.inc" |
924 | }; |
925 | |
926 | } // namespace clang |
927 | |
928 | #endif // LLVM_CLANG_AST_ASTNODETRAVERSER_H |
929 | |