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