1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | #ifndef LLVM_CLANG_AST_ASTNODETRAVERSER_H |
16 | #define LLVM_CLANG_AST_ASTNODETRAVERSER_H |
17 | |
18 | #include "clang/AST/AttrVisitor.h" |
19 | #include "clang/AST/CommentVisitor.h" |
20 | #include "clang/AST/DeclVisitor.h" |
21 | #include "clang/AST/LocInfoType.h" |
22 | #include "clang/AST/StmtVisitor.h" |
23 | #include "clang/AST/TemplateArgumentVisitor.h" |
24 | #include "clang/AST/TypeVisitor.h" |
25 | |
26 | namespace clang { |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | |
34 | |
35 | |
36 | |
37 | |
38 | |
39 | |
40 | |
41 | |
42 | |
43 | |
44 | |
45 | |
46 | |
47 | |
48 | |
49 | |
50 | |
51 | |
52 | |
53 | |
54 | template <typename Derived, typename NodeDelegateType> |
55 | class ASTNodeTraverser |
56 | : public ConstDeclVisitor<Derived>, |
57 | public ConstStmtVisitor<Derived>, |
58 | public comments::ConstCommentVisitor<Derived, void, |
59 | const comments::FullComment *>, |
60 | public TypeVisitor<Derived>, |
61 | public ConstAttrVisitor<Derived>, |
62 | public ConstTemplateArgumentVisitor<Derived> { |
63 | |
64 | |
65 | |
66 | bool Deserialize = false; |
67 | |
68 | NodeDelegateType &getNodeDelegate() { |
69 | return getDerived().doGetNodeDelegate(); |
70 | } |
71 | Derived &getDerived() { return *static_cast<Derived *>(this); } |
72 | |
73 | public: |
74 | void setDeserialize(bool D) { Deserialize = D; } |
75 | bool getDeserialize() const { return Deserialize; } |
76 | |
77 | void Visit(const Decl *D) { |
78 | getNodeDelegate().AddChild([=] { |
79 | getNodeDelegate().Visit(D); |
80 | if (!D) |
81 | return; |
82 | |
83 | ConstDeclVisitor<Derived>::Visit(D); |
84 | |
85 | for (const auto &A : D->attrs()) |
86 | Visit(A); |
87 | |
88 | if (const comments::FullComment * = |
89 | D->getASTContext().getLocalCommentForDeclUncached(D)) |
90 | Visit(Comment, Comment); |
91 | |
92 | |
93 | if (!isa<FunctionDecl>(*D) && !isa<ObjCMethodDecl>(*D)) { |
94 | if (const auto *DC = dyn_cast<DeclContext>(D)) |
95 | dumpDeclContext(DC); |
96 | } |
97 | }); |
98 | } |
99 | |
100 | void Visit(const Stmt *S, StringRef Label = {}) { |
101 | getNodeDelegate().AddChild(Label, [=] { |
102 | getNodeDelegate().Visit(S); |
103 | |
104 | if (!S) { |
105 | return; |
106 | } |
107 | |
108 | ConstStmtVisitor<Derived>::Visit(S); |
109 | |
110 | |
111 | if (isa<DeclStmt>(S) || isa<GenericSelectionExpr>(S)) { |
112 | return; |
113 | } |
114 | |
115 | for (const Stmt *SubStmt : S->children()) |
116 | Visit(SubStmt); |
117 | }); |
118 | } |
119 | |
120 | void Visit(QualType T) { |
121 | SplitQualType SQT = T.split(); |
122 | if (!SQT.Quals.hasQualifiers()) |
123 | return Visit(SQT.Ty); |
124 | |
125 | getNodeDelegate().AddChild([=] { |
126 | getNodeDelegate().Visit(T); |
127 | Visit(T.split().Ty); |
128 | }); |
129 | } |
130 | |
131 | void Visit(const Type *T) { |
132 | getNodeDelegate().AddChild([=] { |
133 | getNodeDelegate().Visit(T); |
134 | if (!T) |
135 | return; |
136 | TypeVisitor<Derived>::Visit(T); |
137 | |
138 | QualType SingleStepDesugar = |
139 | T->getLocallyUnqualifiedSingleStepDesugaredType(); |
140 | if (SingleStepDesugar != QualType(T, 0)) |
141 | Visit(SingleStepDesugar); |
142 | }); |
143 | } |
144 | |
145 | void Visit(const Attr *A) { |
146 | getNodeDelegate().AddChild([=] { |
147 | getNodeDelegate().Visit(A); |
148 | ConstAttrVisitor<Derived>::Visit(A); |
149 | }); |
150 | } |
151 | |
152 | void Visit(const CXXCtorInitializer *Init) { |
153 | getNodeDelegate().AddChild([=] { |
154 | getNodeDelegate().Visit(Init); |
155 | Visit(Init->getInit()); |
156 | }); |
157 | } |
158 | |
159 | void Visit(const TemplateArgument &A, SourceRange R = {}, |
160 | const Decl *From = nullptr, const char *Label = nullptr) { |
161 | getNodeDelegate().AddChild([=] { |
162 | getNodeDelegate().Visit(A, R, From, Label); |
163 | ConstTemplateArgumentVisitor<Derived>::Visit(A); |
164 | }); |
165 | } |
166 | |
167 | void Visit(const BlockDecl::Capture &C) { |
168 | getNodeDelegate().AddChild([=] { |
169 | getNodeDelegate().Visit(C); |
170 | if (C.hasCopyExpr()) |
171 | Visit(C.getCopyExpr()); |
172 | }); |
173 | } |
174 | |
175 | void Visit(const OMPClause *C) { |
176 | getNodeDelegate().AddChild([=] { |
177 | getNodeDelegate().Visit(C); |
178 | for (const auto *S : C->children()) |
179 | Visit(S); |
180 | }); |
181 | } |
182 | |
183 | void Visit(const GenericSelectionExpr::ConstAssociation &A) { |
184 | getNodeDelegate().AddChild([=] { |
185 | getNodeDelegate().Visit(A); |
186 | if (const TypeSourceInfo *TSI = A.getTypeSourceInfo()) |
187 | Visit(TSI->getType()); |
188 | Visit(A.getAssociationExpr()); |
189 | }); |
190 | } |
191 | |
192 | void (const comments::Comment *C, const comments::FullComment *FC) { |
193 | getNodeDelegate().AddChild([=] { |
194 | getNodeDelegate().Visit(C, FC); |
195 | if (!C) { |
196 | return; |
197 | } |
198 | comments::ConstCommentVisitor<Derived, void, |
199 | const comments::FullComment *>::visit(C, |
200 | FC); |
201 | for (comments::Comment::child_iterator I = C->child_begin(), |
202 | E = C->child_end(); |
203 | I != E; ++I) |
204 | Visit(*I, FC); |
205 | }); |
206 | } |
207 | |
208 | void dumpDeclContext(const DeclContext *DC) { |
209 | if (!DC) |
210 | return; |
211 | |
212 | for (const auto *D : (Deserialize ? DC->decls() : DC->noload_decls())) |
213 | Visit(D); |
214 | } |
215 | |
216 | void dumpTemplateParameters(const TemplateParameterList *TPL) { |
217 | if (!TPL) |
218 | return; |
219 | |
220 | for (const auto &TP : *TPL) |
221 | Visit(TP); |
222 | } |
223 | |
224 | void dumpTemplateArgumentListInfo(const TemplateArgumentListInfo &TALI) { |
225 | for (const auto &TA : TALI.arguments()) |
226 | dumpTemplateArgumentLoc(TA); |
227 | } |
228 | |
229 | void dumpTemplateArgumentLoc(const TemplateArgumentLoc &A, |
230 | const Decl *From = nullptr, |
231 | const char *Label = nullptr) { |
232 | Visit(A.getArgument(), A.getSourceRange(), From, Label); |
233 | } |
234 | |
235 | void dumpTemplateArgumentList(const TemplateArgumentList &TAL) { |
236 | for (unsigned i = 0, e = TAL.size(); i < e; ++i) |
237 | Visit(TAL[i]); |
238 | } |
239 | |
240 | void dumpObjCTypeParamList(const ObjCTypeParamList *typeParams) { |
241 | if (!typeParams) |
242 | return; |
243 | |
244 | for (const auto &typeParam : *typeParams) { |
245 | Visit(typeParam); |
246 | } |
247 | } |
248 | |
249 | void VisitComplexType(const ComplexType *T) { Visit(T->getElementType()); } |
250 | void VisitLocInfoType(const LocInfoType *T) { |
251 | Visit(T->getTypeSourceInfo()->getType()); |
252 | } |
253 | void VisitPointerType(const PointerType *T) { Visit(T->getPointeeType()); } |
254 | void VisitBlockPointerType(const BlockPointerType *T) { |
255 | Visit(T->getPointeeType()); |
256 | } |
257 | void VisitReferenceType(const ReferenceType *T) { |
258 | Visit(T->getPointeeType()); |
259 | } |
260 | void VisitMemberPointerType(const MemberPointerType *T) { |
261 | Visit(T->getClass()); |
262 | Visit(T->getPointeeType()); |
263 | } |
264 | void VisitArrayType(const ArrayType *T) { Visit(T->getElementType()); } |
265 | void VisitVariableArrayType(const VariableArrayType *T) { |
266 | VisitArrayType(T); |
267 | Visit(T->getSizeExpr()); |
268 | } |
269 | void VisitDependentSizedArrayType(const DependentSizedArrayType *T) { |
270 | Visit(T->getElementType()); |
271 | Visit(T->getSizeExpr()); |
272 | } |
273 | void VisitDependentSizedExtVectorType(const DependentSizedExtVectorType *T) { |
274 | Visit(T->getElementType()); |
275 | Visit(T->getSizeExpr()); |
276 | } |
277 | void VisitVectorType(const VectorType *T) { Visit(T->getElementType()); } |
278 | void VisitFunctionType(const FunctionType *T) { Visit(T->getReturnType()); } |
279 | void VisitFunctionProtoType(const FunctionProtoType *T) { |
280 | VisitFunctionType(T); |
281 | for (const QualType &PT : T->getParamTypes()) |
282 | Visit(PT); |
283 | } |
284 | void VisitTypeOfExprType(const TypeOfExprType *T) { |
285 | Visit(T->getUnderlyingExpr()); |
286 | } |
287 | void VisitDecltypeType(const DecltypeType *T) { |
288 | Visit(T->getUnderlyingExpr()); |
289 | } |
290 | void VisitUnaryTransformType(const UnaryTransformType *T) { |
291 | Visit(T->getBaseType()); |
292 | } |
293 | void VisitAttributedType(const AttributedType *T) { |
294 | |
295 | Visit(T->getModifiedType()); |
296 | } |
297 | void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) { |
298 | Visit(T->getReplacedParameter()); |
299 | } |
300 | void |
301 | VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T) { |
302 | Visit(T->getReplacedParameter()); |
303 | Visit(T->getArgumentPack()); |
304 | } |
305 | void VisitTemplateSpecializationType(const TemplateSpecializationType *T) { |
306 | for (const auto &Arg : *T) |
307 | Visit(Arg); |
308 | if (T->isTypeAlias()) |
309 | Visit(T->getAliasedType()); |
310 | } |
311 | void VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { |
312 | Visit(T->getPointeeType()); |
313 | } |
314 | void VisitAtomicType(const AtomicType *T) { Visit(T->getValueType()); } |
315 | void VisitPipeType(const PipeType *T) { Visit(T->getElementType()); } |
316 | void VisitAdjustedType(const AdjustedType *T) { Visit(T->getOriginalType()); } |
317 | void VisitPackExpansionType(const PackExpansionType *T) { |
318 | if (!T->isSugared()) |
319 | Visit(T->getPattern()); |
320 | } |
321 | |
322 | |
323 | |
324 | void VisitTypedefDecl(const TypedefDecl *D) { Visit(D->getUnderlyingType()); } |
325 | |
326 | void VisitEnumConstantDecl(const EnumConstantDecl *D) { |
327 | if (const Expr *Init = D->getInitExpr()) |
328 | Visit(Init); |
329 | } |
330 | |
331 | void VisitFunctionDecl(const FunctionDecl *D) { |
332 | if (const auto *FTSI = D->getTemplateSpecializationInfo()) |
333 | dumpTemplateArgumentList(*FTSI->TemplateArguments); |
334 | |
335 | if (D->param_begin()) |
336 | for (const auto *Parameter : D->parameters()) |
337 | Visit(Parameter); |
338 | |
339 | if (const auto *C = dyn_cast<CXXConstructorDecl>(D)) |
340 | for (const auto *I : C->inits()) |
341 | Visit(I); |
342 | |
343 | if (D->doesThisDeclarationHaveABody()) |
344 | Visit(D->getBody()); |
345 | } |
346 | |
347 | void VisitFieldDecl(const FieldDecl *D) { |
348 | if (D->isBitField()) |
349 | Visit(D->getBitWidth()); |
350 | if (Expr *Init = D->getInClassInitializer()) |
351 | Visit(Init); |
352 | } |
353 | |
354 | void VisitVarDecl(const VarDecl *D) { |
355 | if (D->hasInit()) |
356 | Visit(D->getInit()); |
357 | } |
358 | |
359 | void VisitDecompositionDecl(const DecompositionDecl *D) { |
360 | VisitVarDecl(D); |
361 | for (const auto *B : D->bindings()) |
362 | Visit(B); |
363 | } |
364 | |
365 | void VisitBindingDecl(const BindingDecl *D) { |
366 | if (const auto *E = D->getBinding()) |
367 | Visit(E); |
368 | } |
369 | |
370 | void VisitFileScopeAsmDecl(const FileScopeAsmDecl *D) { |
371 | Visit(D->getAsmString()); |
372 | } |
373 | |
374 | void VisitCapturedDecl(const CapturedDecl *D) { Visit(D->getBody()); } |
375 | |
376 | void VisitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D) { |
377 | for (const auto *E : D->varlists()) |
378 | Visit(E); |
379 | } |
380 | |
381 | void VisitOMPDeclareReductionDecl(const OMPDeclareReductionDecl *D) { |
382 | Visit(D->getCombiner()); |
383 | if (const auto *Initializer = D->getInitializer()) |
384 | Visit(Initializer); |
385 | } |
386 | |
387 | void VisitOMPDeclareMapperDecl(const OMPDeclareMapperDecl *D) { |
388 | for (const auto *C : D->clauselists()) |
389 | Visit(C); |
390 | } |
391 | |
392 | void VisitOMPCapturedExprDecl(const OMPCapturedExprDecl *D) { |
393 | Visit(D->getInit()); |
394 | } |
395 | |
396 | void VisitOMPAllocateDecl(const OMPAllocateDecl *D) { |
397 | for (const auto *E : D->varlists()) |
398 | Visit(E); |
399 | for (const auto *C : D->clauselists()) |
400 | Visit(C); |
401 | } |
402 | |
403 | template <typename SpecializationDecl> |
404 | void dumpTemplateDeclSpecialization(const SpecializationDecl *D) { |
405 | for (const auto *RedeclWithBadType : D->redecls()) { |
406 | |
407 | |
408 | |
409 | auto *Redecl = dyn_cast<SpecializationDecl>(RedeclWithBadType); |
410 | if (!Redecl) { |
411 | |
412 | |
413 | |
414 | (0) . __assert_fail ("isa(RedeclWithBadType) && \"expected an injected-class-name\"", "/home/seafit/code_projects/clang_source/clang/include/clang/AST/ASTNodeTraverser.h", 415, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(isa<CXXRecordDecl>(RedeclWithBadType) && |
415 | (0) . __assert_fail ("isa(RedeclWithBadType) && \"expected an injected-class-name\"", "/home/seafit/code_projects/clang_source/clang/include/clang/AST/ASTNodeTraverser.h", 415, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> "expected an injected-class-name"); |
416 | continue; |
417 | } |
418 | Visit(Redecl); |
419 | } |
420 | } |
421 | |
422 | template <typename TemplateDecl> |
423 | void dumpTemplateDecl(const TemplateDecl *D) { |
424 | dumpTemplateParameters(D->getTemplateParameters()); |
425 | |
426 | Visit(D->getTemplatedDecl()); |
427 | |
428 | for (const auto *Child : D->specializations()) |
429 | dumpTemplateDeclSpecialization(Child); |
430 | } |
431 | |
432 | void VisitTypeAliasDecl(const TypeAliasDecl *D) { |
433 | Visit(D->getUnderlyingType()); |
434 | } |
435 | |
436 | void VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D) { |
437 | dumpTemplateParameters(D->getTemplateParameters()); |
438 | Visit(D->getTemplatedDecl()); |
439 | } |
440 | |
441 | void VisitStaticAssertDecl(const StaticAssertDecl *D) { |
442 | Visit(D->getAssertExpr()); |
443 | Visit(D->getMessage()); |
444 | } |
445 | |
446 | void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) { |
447 | dumpTemplateDecl(D); |
448 | } |
449 | |
450 | void VisitClassTemplateDecl(const ClassTemplateDecl *D) { |
451 | dumpTemplateDecl(D); |
452 | } |
453 | |
454 | void VisitClassTemplateSpecializationDecl( |
455 | const ClassTemplateSpecializationDecl *D) { |
456 | dumpTemplateArgumentList(D->getTemplateArgs()); |
457 | } |
458 | |
459 | void VisitClassTemplatePartialSpecializationDecl( |
460 | const ClassTemplatePartialSpecializationDecl *D) { |
461 | VisitClassTemplateSpecializationDecl(D); |
462 | dumpTemplateParameters(D->getTemplateParameters()); |
463 | } |
464 | |
465 | void VisitClassScopeFunctionSpecializationDecl( |
466 | const ClassScopeFunctionSpecializationDecl *D) { |
467 | Visit(D->getSpecialization()); |
468 | if (D->hasExplicitTemplateArgs()) |
469 | dumpTemplateArgumentListInfo(D->templateArgs()); |
470 | } |
471 | void VisitVarTemplateDecl(const VarTemplateDecl *D) { dumpTemplateDecl(D); } |
472 | |
473 | void VisitBuiltinTemplateDecl(const BuiltinTemplateDecl *D) { |
474 | dumpTemplateParameters(D->getTemplateParameters()); |
475 | } |
476 | |
477 | void |
478 | VisitVarTemplateSpecializationDecl(const VarTemplateSpecializationDecl *D) { |
479 | dumpTemplateArgumentList(D->getTemplateArgs()); |
480 | VisitVarDecl(D); |
481 | } |
482 | |
483 | void VisitVarTemplatePartialSpecializationDecl( |
484 | const VarTemplatePartialSpecializationDecl *D) { |
485 | dumpTemplateParameters(D->getTemplateParameters()); |
486 | VisitVarTemplateSpecializationDecl(D); |
487 | } |
488 | |
489 | void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) { |
490 | if (D->hasDefaultArgument()) |
491 | Visit(D->getDefaultArgument(), SourceRange(), |
492 | D->getDefaultArgStorage().getInheritedFrom(), |
493 | D->defaultArgumentWasInherited() ? "inherited from" : "previous"); |
494 | } |
495 | |
496 | void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) { |
497 | if (D->hasDefaultArgument()) |
498 | Visit(D->getDefaultArgument(), SourceRange(), |
499 | D->getDefaultArgStorage().getInheritedFrom(), |
500 | D->defaultArgumentWasInherited() ? "inherited from" : "previous"); |
501 | } |
502 | |
503 | void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D) { |
504 | dumpTemplateParameters(D->getTemplateParameters()); |
505 | if (D->hasDefaultArgument()) |
506 | dumpTemplateArgumentLoc( |
507 | D->getDefaultArgument(), D->getDefaultArgStorage().getInheritedFrom(), |
508 | D->defaultArgumentWasInherited() ? "inherited from" : "previous"); |
509 | } |
510 | |
511 | void VisitUsingShadowDecl(const UsingShadowDecl *D) { |
512 | if (auto *TD = dyn_cast<TypeDecl>(D->getUnderlyingDecl())) |
513 | Visit(TD->getTypeForDecl()); |
514 | } |
515 | |
516 | void VisitFriendDecl(const FriendDecl *D) { |
517 | if (!D->getFriendType()) |
518 | Visit(D->getFriendDecl()); |
519 | } |
520 | |
521 | void VisitObjCMethodDecl(const ObjCMethodDecl *D) { |
522 | if (D->isThisDeclarationADefinition()) |
523 | dumpDeclContext(D); |
524 | else |
525 | for (const ParmVarDecl *Parameter : D->parameters()) |
526 | Visit(Parameter); |
527 | |
528 | if (D->hasBody()) |
529 | Visit(D->getBody()); |
530 | } |
531 | |
532 | void VisitObjCCategoryDecl(const ObjCCategoryDecl *D) { |
533 | dumpObjCTypeParamList(D->getTypeParamList()); |
534 | } |
535 | |
536 | void VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) { |
537 | dumpObjCTypeParamList(D->getTypeParamListAsWritten()); |
538 | } |
539 | |
540 | void VisitObjCImplementationDecl(const ObjCImplementationDecl *D) { |
541 | for (const auto &I : D->inits()) |
542 | Visit(I); |
543 | } |
544 | |
545 | void VisitBlockDecl(const BlockDecl *D) { |
546 | for (const auto &I : D->parameters()) |
547 | Visit(I); |
548 | |
549 | for (const auto &I : D->captures()) |
550 | Visit(I); |
551 | Visit(D->getBody()); |
552 | } |
553 | |
554 | void VisitDeclStmt(const DeclStmt *Node) { |
555 | for (const auto &D : Node->decls()) |
556 | Visit(D); |
557 | } |
558 | |
559 | void VisitAttributedStmt(const AttributedStmt *Node) { |
560 | for (const auto *A : Node->getAttrs()) |
561 | Visit(A); |
562 | } |
563 | |
564 | void VisitCXXCatchStmt(const CXXCatchStmt *Node) { |
565 | Visit(Node->getExceptionDecl()); |
566 | } |
567 | |
568 | void VisitCapturedStmt(const CapturedStmt *Node) { |
569 | Visit(Node->getCapturedDecl()); |
570 | } |
571 | |
572 | void VisitOMPExecutableDirective(const OMPExecutableDirective *Node) { |
573 | for (const auto *C : Node->clauses()) |
574 | Visit(C); |
575 | } |
576 | |
577 | void VisitInitListExpr(const InitListExpr *ILE) { |
578 | if (auto *Filler = ILE->getArrayFiller()) { |
579 | Visit(Filler, "array_filler"); |
580 | } |
581 | } |
582 | |
583 | void VisitBlockExpr(const BlockExpr *Node) { Visit(Node->getBlockDecl()); } |
584 | |
585 | void VisitOpaqueValueExpr(const OpaqueValueExpr *Node) { |
586 | if (Expr *Source = Node->getSourceExpr()) |
587 | Visit(Source); |
588 | } |
589 | |
590 | void VisitGenericSelectionExpr(const GenericSelectionExpr *E) { |
591 | Visit(E->getControllingExpr()); |
592 | Visit(E->getControllingExpr()->getType()); |
593 | |
594 | for (const auto &Assoc : E->associations()) { |
595 | Visit(Assoc); |
596 | } |
597 | } |
598 | |
599 | void VisitLambdaExpr(const LambdaExpr *Node) { |
600 | Visit(Node->getLambdaClass()); |
601 | } |
602 | |
603 | void VisitSizeOfPackExpr(const SizeOfPackExpr *Node) { |
604 | if (Node->isPartiallySubstituted()) |
605 | for (const auto &A : Node->getPartialArguments()) |
606 | Visit(A); |
607 | } |
608 | |
609 | void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node) { |
610 | if (const VarDecl *CatchParam = Node->getCatchParamDecl()) |
611 | Visit(CatchParam); |
612 | } |
613 | |
614 | void VisitExpressionTemplateArgument(const TemplateArgument &TA) { |
615 | Visit(TA.getAsExpr()); |
616 | } |
617 | void VisitPackTemplateArgument(const TemplateArgument &TA) { |
618 | for (const auto &TArg : TA.pack_elements()) |
619 | Visit(TArg); |
620 | } |
621 | |
622 | |
623 | #include "clang/AST/AttrNodeTraverse.inc" |
624 | }; |
625 | |
626 | } |
627 | |
628 | #endif |
629 | |