clang: lib/ASTMatchers/ASTMatchFinder.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
23#include "llvm/ADT/DenseMap.h"
24#include "llvm/ADT/SmallPtrSet.h"
25#include "llvm/ADT/StringMap.h"
26#include "llvm/Support/PrettyStackTrace.h"
27#include "llvm/Support/Timer.h"
28#include
29#include
30#include
31
35namespace {
36
37typedef MatchFinder::MatchCallback MatchCallback;
38
39
40
41
42
43
44
45
46
47static const unsigned MaxMemoizationEntries = 10000;
48
49enum class MatchType {
50 Ancestors,
51
52 Descendants,
53 Child,
54};
55
56
57
58
59
60
61
62
63
64
65
66
67
68struct MatchKey {
69 DynTypedMatcher::MatcherIDType MatcherID;
71 BoundNodesTreeBuilder BoundNodes;
73 MatchType Type;
74
76 return std::tie(Traversal, Type, MatcherID, Node, BoundNodes) <
78 Other.BoundNodes);
79 }
80};
81
82
83struct MemoizedMatchResult {
84 bool ResultOfMatch;
85 BoundNodesTreeBuilder Nodes;
86};
87
88
89
90class MatchChildASTVisitor
91 : public RecursiveASTVisitor {
92public:
93 typedef RecursiveASTVisitor VisitorBase;
94
95
96
97
98
99 MatchChildASTVisitor(const DynTypedMatcher *Matcher, ASTMatchFinder *Finder,
100 BoundNodesTreeBuilder *Builder, int MaxDepth,
101 bool IgnoreImplicitChildren,
102 ASTMatchFinder::BindKind Bind)
103 : Matcher(Matcher), Finder(Finder), Builder(Builder), CurrentDepth(0),
104 MaxDepth(MaxDepth), IgnoreImplicitChildren(IgnoreImplicitChildren),
105 Bind(Bind), Matches(false) {}
106
107
108
109
110
111
112
113
114
115
116
117
118 bool findMatch(const DynTypedNode &DynNode) {
119 reset();
120 if (const Decl *D = DynNode.get())
122 else if (const Stmt *S = DynNode.get())
124 else if (const NestedNameSpecifier *NNS =
125 DynNode.get())
127 else if (const NestedNameSpecifierLoc *NNSLoc =
128 DynNode.get())
130 else if (const QualType *Q = DynNode.get())
131 traverse(*Q, true);
132 else if (const TypeLoc *T = DynNode.get())
134 else if (const auto *C = DynNode.get())
136 else if (const TemplateArgumentLoc *TALoc =
137 DynNode.get())
139 else if (const Attr *A = DynNode.get())
141
142
143
144
145
146 *Builder = ResultBindings;
147
148 return Matches;
149 }
150
151
152
153
154 bool TraverseDecl(Decl *DeclNode) {
155
156 if (DeclNode && DeclNode->isImplicit() &&
157 Finder->isTraversalIgnoringImplicitNodes())
158 return baseTraverse(*DeclNode);
159
160 ScopedIncrement ScopedDepth(&CurrentDepth);
161 return (DeclNode == nullptr) || traverse(*DeclNode);
162 }
163
164 Stmt *getStmtToTraverse(Stmt *StmtNode) {
165 Stmt *StmtToTraverse = StmtNode;
166 if (auto *ExprNode = dyn_cast_or_null(StmtNode)) {
167 auto *LambdaNode = dyn_cast_or_null(StmtNode);
168 if (LambdaNode && Finder->isTraversalIgnoringImplicitNodes())
169 StmtToTraverse = LambdaNode;
170 else
171 StmtToTraverse =
172 Finder->getASTContext().getParentMapContext().traverseIgnored(
173 ExprNode);
174 }
175 return StmtToTraverse;
176 }
177
178 bool TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue = nullptr) {
179
180 if (CurrentDepth == 0 || (CurrentDepth <= MaxDepth && MaxDepth < INT_MAX))
181 Queue = nullptr;
182
183 ScopedIncrement ScopedDepth(&CurrentDepth);
184 Stmt *StmtToTraverse = getStmtToTraverse(StmtNode);
185 if (!StmtToTraverse)
186 return true;
187
189 return true;
190
191 if ((*StmtToTraverse))
192 return false;
194 }
195
196
197 bool TraverseType(QualType TypeNode, bool TraverseQualifier = true) {
198 if (TypeNode.isNull())
199 return true;
200 ScopedIncrement ScopedDepth(&CurrentDepth);
201
202 if ((*TypeNode))
203 return false;
204
205 return traverse(TypeNode, TraverseQualifier);
206 }
207
208
209 bool TraverseTypeLoc(TypeLoc TypeLocNode, bool TraverseQualifier = true) {
210 if (TypeLocNode.isNull())
211 return true;
212 ScopedIncrement ScopedDepth(&CurrentDepth);
213
214 if ((*TypeLocNode.getType()))
215 return false;
216
217 if ((TypeLocNode.getType()))
218 return false;
219
220 return traverse(TypeLocNode, TraverseQualifier);
221 }
222 bool TraverseNestedNameSpecifier(NestedNameSpecifier NNS) {
223 ScopedIncrement ScopedDepth(&CurrentDepth);
224 return !NNS || traverse(NNS);
225 }
227 if (!NNS)
228 return true;
229 ScopedIncrement ScopedDepth(&CurrentDepth);
230 if ((NNS.getNestedNameSpecifier()))
231 return false;
233 }
234 bool TraverseConstructorInitializer(CXXCtorInitializer *CtorInit) {
235 if (!CtorInit)
236 return true;
237 ScopedIncrement ScopedDepth(&CurrentDepth);
239 }
240 bool TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL) {
241 ScopedIncrement ScopedDepth(&CurrentDepth);
243 }
244 bool TraverseCXXForRangeStmt(CXXForRangeStmt *Node) {
245 if (!Finder->isTraversalIgnoringImplicitNodes())
246 return VisitorBase::TraverseCXXForRangeStmt(Node);
247 if (!Node)
248 return true;
249 ScopedIncrement ScopedDepth(&CurrentDepth);
250 if (auto *Init = Node->getInit())
252 return false;
253 if ((*Node->getLoopVariable()))
254 return false;
255 if (match(*Node->getRangeInit()))
257 return false;
258 if ((*Node->getBody()))
259 return false;
261 }
262 bool TraverseCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *Node) {
263 if (!Finder->isTraversalIgnoringImplicitNodes())
264 return VisitorBase::TraverseCXXRewrittenBinaryOperator(Node);
265 if (!Node)
266 return true;
267 ScopedIncrement ScopedDepth(&CurrentDepth);
268
269 return match(*Node->getLHS()) && match(*Node->getRHS());
270 }
271 bool TraverseAttr(Attr *A) {
272 if (A == nullptr ||
273 (A->isImplicit() &&
274 Finder->getASTContext().getParentMapContext().getTraversalKind() ==
276 return true;
277 ScopedIncrement ScopedDepth(&CurrentDepth);
279 }
280 bool TraverseLambdaExpr(LambdaExpr *Node) {
281 if (!Finder->isTraversalIgnoringImplicitNodes())
282 return VisitorBase::TraverseLambdaExpr(Node);
283 if (!Node)
284 return true;
285 ScopedIncrement ScopedDepth(&CurrentDepth);
286
287 for (unsigned I = 0, N = Node->capture_size(); I != N; ++I) {
288 const LambdaCapture *C = Node->capture_begin() + I;
289 if (->isExplicit())
290 continue;
291 if (Node->isInitCapture(C) && (*C->getCapturedVar()))
292 return false;
293 const Expr *CIE = Node->capture_init_begin()[I];
294 if (CIE != nullptr && (*CIE))
295 return false;
296 }
297
298 if (const auto *TPL = Node->getTemplateParameterList()) {
299 for (const auto *TP : *TPL) {
301 return false;
302 }
303 }
304
305 for (const auto *P : Node->getCallOperator()->parameters()) {
307 return false;
308 }
309
310 if ((*Node->getBody()))
311 return false;
312
314 }
315
316 bool shouldVisitTemplateInstantiations() const { return true; }
317 bool shouldVisitImplicitCode() const { return !IgnoreImplicitChildren; }
318
319private:
320
321 struct ScopedIncrement {
322 explicit ScopedIncrement(int *Depth) : Depth(Depth) { ++(*Depth); }
323 ~ScopedIncrement() { --(*Depth); }
324
325 private:
326 int *Depth;
327 };
328
329
330 void reset() {
331 Matches = false;
332 CurrentDepth = 0;
333 }
334
335
336
337 bool baseTraverse(const Decl &DeclNode) {
339 }
340 bool baseTraverse(const Stmt &StmtNode) {
342 }
343 bool baseTraverse(QualType TypeNode, bool TraverseQualifier) {
345 }
346 bool baseTraverse(TypeLoc TypeLocNode, bool TraverseQualifier) {
348 }
349 bool baseTraverse(NestedNameSpecifier NNS) {
351 }
352 bool baseTraverse(NestedNameSpecifierLoc NNS) {
354 }
355 bool baseTraverse(const CXXCtorInitializer &CtorInit) {
357 const_cast<CXXCtorInitializer *>(&CtorInit));
358 }
359 bool baseTraverse(TemplateArgumentLoc TAL) {
361 }
362 bool baseTraverse(const Attr &AttrNode) {
364 }
365
366
367
368
369
370
371 template
372 bool match(const T &Node) {
373 if (CurrentDepth == 0 || CurrentDepth > MaxDepth) {
374 return true;
375 }
376 if (Bind != ASTMatchFinder::BK_All) {
377 BoundNodesTreeBuilder RecursiveBuilder(*Builder);
379 &RecursiveBuilder)) {
380 Matches = true;
381 ResultBindings.addMatch(RecursiveBuilder);
382 return false;
383 }
384 } else {
385 BoundNodesTreeBuilder RecursiveBuilder(*Builder);
387 &RecursiveBuilder)) {
388
389 Matches = true;
390 ResultBindings.addMatch(RecursiveBuilder);
391 }
392 }
393 return true;
394 }
395
396
397
398 template <typename T, class... Args>
399 bool traverse(const T &Node, Args &&...args) {
400 static_assert(IsBaseType::value,
401 "traverse can only be instantiated with base type");
402 if ((Node))
403 return false;
404 return baseTraverse(Node, std::forward(args)...);
405 }
406
407 const DynTypedMatcher *const Matcher;
408 ASTMatchFinder *const Finder;
409 BoundNodesTreeBuilder *const Builder;
410 BoundNodesTreeBuilder ResultBindings;
411 int CurrentDepth;
412 const int MaxDepth;
413 const bool IgnoreImplicitChildren;
414 const ASTMatchFinder::BindKind Bind;
415 bool Matches;
416};
417
418
419
420class MatchASTVisitor : public RecursiveASTVisitor,
421 public ASTMatchFinder {
422public:
423 MatchASTVisitor(const MatchFinder::MatchersByType *Matchers,
424 const MatchFinder::MatchFinderOptions &Options)
425 : Matchers(Matchers), Options(Options), ActiveASTContext(nullptr) {}
426
427 ~MatchASTVisitor() override {
428 if (Options.CheckProfiling) {
429 Options.CheckProfiling->Records = std::move(TimeByBucket);
430 }
431 }
432
433 void onStartOfTranslationUnit() {
434 const bool EnableCheckProfiling = Options.CheckProfiling.has_value();
435 TimeBucketRegion Timer;
436 for (MatchCallback *MC : Matchers->AllCallbacks) {
437 if (EnableCheckProfiling)
438 Timer.setBucket(&TimeByBucket[MC->getID()]);
439 MC->onStartOfTranslationUnit();
440 }
441 }
442
443 void onEndOfTranslationUnit() {
444 const bool EnableCheckProfiling = Options.CheckProfiling.has_value();
445 TimeBucketRegion Timer;
446 for (MatchCallback *MC : Matchers->AllCallbacks) {
447 if (EnableCheckProfiling)
448 Timer.setBucket(&TimeByBucket[MC->getID()]);
449 MC->onEndOfTranslationUnit();
450 }
451 }
452
453 void set_active_ast_context(ASTContext *NewActiveASTContext) {
454 ActiveASTContext = NewActiveASTContext;
455 }
456
457
458
459
460 bool VisitTypedefNameDecl(TypedefNameDecl *DeclNode) {
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488 const Type *TypeNode = DeclNode->getUnderlyingType().getTypePtr();
489 const Type *CanonicalType =
491 TypeAliases[CanonicalType].insert(DeclNode);
492 return true;
493 }
494
495 bool VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) {
496 const ObjCInterfaceDecl *InterfaceDecl = CAD->getClassInterface();
497 CompatibleAliases[InterfaceDecl].insert(CAD);
498 return true;
499 }
500
501 bool TraverseDecl(Decl *DeclNode);
502 bool TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue = nullptr);
503 bool TraverseType(QualType TypeNode, bool TraverseQualifier = true);
504 bool TraverseTypeLoc(TypeLoc TypeNode, bool TraverseQualifier = true);
505 bool TraverseNestedNameSpecifier(NestedNameSpecifier NNS);
507 bool TraverseConstructorInitializer(CXXCtorInitializer *CtorInit);
508 bool TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL);
509 bool TraverseAttr(Attr *AttrNode);
510
511 bool dataTraverseNode(Stmt *S, DataRecursionQueue *Queue) {
512 if (auto *RF = dyn_cast(S)) {
513 {
514 ASTNodeNotAsIsSourceScope RAII(this, true);
515 TraverseStmt(RF->getInit());
516
517 match(*RF->getLoopVariable());
518 TraverseStmt(RF->getRangeInit());
519 }
520 {
521 ASTNodeNotSpelledInSourceScope RAII(this, true);
522 for (auto *SubStmt : RF->children()) {
523 if (SubStmt != RF->getBody())
524 TraverseStmt(SubStmt);
525 }
526 }
527 TraverseStmt(RF->getBody());
528 return true;
529 } else if (auto *RBO = dyn_cast(S)) {
530 {
531 ASTNodeNotAsIsSourceScope RAII(this, true);
532 TraverseStmt(const_cast<Expr *>(RBO->getLHS()));
533 TraverseStmt(const_cast<Expr *>(RBO->getRHS()));
534 }
535 {
536 ASTNodeNotSpelledInSourceScope RAII(this, true);
537 for (auto *SubStmt : RBO->children()) {
538 TraverseStmt(SubStmt);
539 }
540 }
541 return true;
542 } else if (auto *LE = dyn_cast(S)) {
543 for (auto I : llvm::zip(LE->captures(), LE->capture_inits())) {
544 auto C = std::get<0>(I);
545 ASTNodeNotSpelledInSourceScope RAII(
546 this, TraversingASTNodeNotSpelledInSource || .isExplicit());
547 TraverseLambdaCapture(LE, &C, std::get<1>(I));
548 }
549
550 {
551 ASTNodeNotSpelledInSourceScope RAII(this, true);
552 TraverseDecl(LE->getLambdaClass());
553 }
554 {
555 ASTNodeNotAsIsSourceScope RAII(this, true);
556
557
558
559 TypeLoc TL = LE->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
560 FunctionProtoTypeLoc Proto = TL.getAsAdjusted();
561
562 if (auto *TPL = LE->getTemplateParameterList()) {
563 for (NamedDecl *D : *TPL) {
564 TraverseDecl(D);
565 }
566 if (Expr *RequiresClause = TPL->getRequiresClause()) {
567 TraverseStmt(RequiresClause);
568 }
569 }
570
571 if (LE->hasExplicitParameters()) {
572
573 for (ParmVarDecl *Param : Proto.getParams())
574 TraverseDecl(Param);
575 }
576
577 const auto *T = Proto.getTypePtr();
579 TraverseType(E, true);
580
582 TraverseStmt(NE, Queue);
583
584 if (LE->hasExplicitResultType())
585 TraverseTypeLoc(Proto.getReturnLoc(), true);
586 TraverseStmt(
587 const_cast<Expr *>(LE->getTrailingRequiresClause().ConstraintExpr));
588 }
589
590 TraverseStmt(LE->getBody());
591 return true;
592 }
594 }
595
596
597 bool memoizedMatchesRecursively(const DynTypedNode &Node, ASTContext &Ctx,
598 const DynTypedMatcher &Matcher,
599 BoundNodesTreeBuilder *Builder, int MaxDepth,
600 BindKind Bind) {
601
602 if (!Node.getMemoizationData() || !Builder->isComparable())
603 return matchesRecursively(Node, Matcher, Builder, MaxDepth, Bind);
604
605 MatchKey Key;
606 Key.MatcherID = Matcher.getID();
607 Key.Node = Node;
608
609 Key.BoundNodes = *Builder;
611
612 Key.Type = MaxDepth == 1 ? MatchType::Child : MatchType::Descendants;
613 MemoizationMap::iterator I = ResultCache.find(Key);
614 if (I != ResultCache.end()) {
615 *Builder = I->second.Nodes;
616 return I->second.ResultOfMatch;
617 }
618
619 MemoizedMatchResult Result;
620 Result.Nodes = *Builder;
621 Result.ResultOfMatch =
622 matchesRecursively(Node, Matcher, &Result.Nodes, MaxDepth, Bind);
623
624 MemoizedMatchResult &CachedResult = ResultCache[Key];
625 CachedResult = std::move(Result);
626
627 *Builder = CachedResult.Nodes;
628 return CachedResult.ResultOfMatch;
629 }
630
631
632 bool matchesRecursively(const DynTypedNode &Node,
633 const DynTypedMatcher &Matcher,
634 BoundNodesTreeBuilder *Builder, int MaxDepth,
635 BindKind Bind) {
636 bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
637 TraversingASTChildrenNotSpelledInSource;
638
639 bool IgnoreImplicitChildren = false;
640
641 if (isTraversalIgnoringImplicitNodes()) {
642 IgnoreImplicitChildren = true;
643 }
644
645 ASTNodeNotSpelledInSourceScope RAII(this, ScopedTraversal);
646
647 MatchChildASTVisitor Visitor(&Matcher, this, Builder, MaxDepth,
648 IgnoreImplicitChildren, Bind);
649 return Visitor.findMatch(Node);
650 }
651
652 bool classIsDerivedFrom(const CXXRecordDecl *Declaration,
653 const Matcher &Base,
654 BoundNodesTreeBuilder *Builder,
655 bool Directly) override;
656
657private:
658 bool
659 classIsDerivedFromImpl(const CXXRecordDecl *Declaration,
660 const Matcher &Base,
661 BoundNodesTreeBuilder *Builder, bool Directly,
662 llvm::SmallPtrSetImpl<const CXXRecordDecl *> &Visited);
663
664public:
665 bool objcClassIsDerivedFrom(const ObjCInterfaceDecl *Declaration,
666 const Matcher &Base,
667 BoundNodesTreeBuilder *Builder,
668 bool Directly) override;
669
670public:
671
672 bool matchesChildOf(const DynTypedNode &Node, ASTContext &Ctx,
673 const DynTypedMatcher &Matcher,
674 BoundNodesTreeBuilder *Builder, BindKind Bind) override {
675 if (ResultCache.size() > MaxMemoizationEntries)
676 ResultCache.clear();
677 return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder, 1, Bind);
678 }
679
680 bool matchesDescendantOf(const DynTypedNode &Node, ASTContext &Ctx,
681 const DynTypedMatcher &Matcher,
682 BoundNodesTreeBuilder *Builder,
683 BindKind Bind) override {
684 if (ResultCache.size() > MaxMemoizationEntries)
685 ResultCache.clear();
686 return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder, INT_MAX,
688 }
689
690 bool matchesAncestorOf(const DynTypedNode &Node, ASTContext &Ctx,
691 const DynTypedMatcher &Matcher,
692 BoundNodesTreeBuilder *Builder,
693 AncestorMatchMode MatchMode) override {
694
695
696 if (ResultCache.size() > MaxMemoizationEntries)
697 ResultCache.clear();
698 if (MatchMode == AncestorMatchMode::AMM_ParentOnly)
699 return matchesParentOf(Node, Matcher, Builder);
700 return matchesAnyAncestorOf(Node, Ctx, Matcher, Builder);
701 }
702
703
704
705 void match(const DynTypedNode &Node) {
706
707 if (auto *N = Node.get()) {
709 } else if (auto *N = Node.get()) {
711 } else if (auto *N = Node.get<Type>()) {
713 } else if (auto *N = Node.get()) {
715 } else if (auto *N = Node.get()) {
717 } else if (auto *N = Node.get()) {
719 } else if (auto *N = Node.get()) {
721 } else if (auto *N = Node.get()) {
723 } else if (auto *N = Node.get()) {
725 } else if (auto *N = Node.get()) {
727 }
728 }
729
730 template void match(const T &Node) {
731 matchDispatch(&Node);
732 }
733
734
735 ASTContext &getASTContext() const override { return *ActiveASTContext; }
736
737 bool shouldVisitTemplateInstantiations() const { return true; }
738 bool shouldVisitImplicitCode() const { return true; }
739
740
741
742 bool shouldVisitLambdaBody() const { return false; }
743
744 bool IsMatchingInASTNodeNotSpelledInSource() const override {
745 return TraversingASTNodeNotSpelledInSource;
746 }
747 bool isMatchingChildrenNotSpelledInSource() const override {
748 return TraversingASTChildrenNotSpelledInSource;
749 }
750 void setMatchingChildrenNotSpelledInSource(bool Set) override {
751 TraversingASTChildrenNotSpelledInSource = Set;
752 }
753
754 bool IsMatchingInASTNodeNotAsIs() const override {
755 return TraversingASTNodeNotAsIs;
756 }
757
758 bool TraverseTemplateInstantiations(ClassTemplateDecl *D) {
759 ASTNodeNotSpelledInSourceScope RAII(this, true);
760 return RecursiveASTVisitor::TraverseTemplateInstantiations(
761 D);
762 }
763
764 bool TraverseTemplateInstantiations(VarTemplateDecl *D) {
765 ASTNodeNotSpelledInSourceScope RAII(this, true);
766 return RecursiveASTVisitor::TraverseTemplateInstantiations(
767 D);
768 }
769
770 bool TraverseTemplateInstantiations(FunctionTemplateDecl *D) {
771 ASTNodeNotSpelledInSourceScope RAII(this, true);
772 return RecursiveASTVisitor::TraverseTemplateInstantiations(
773 D);
774 }
775
776private:
777 bool TraversingASTNodeNotSpelledInSource = false;
778 bool TraversingASTNodeNotAsIs = false;
779 bool TraversingASTChildrenNotSpelledInSource = false;
780
781 class CurMatchData {
782
783
784
785#define CMD_TYPES_0 \
786 const QualType *, const TypeLoc *, const NestedNameSpecifier *, \
787 const NestedNameSpecifierLoc *
788#define CMD_TYPES_1 \
789 const CXXCtorInitializer *, const TemplateArgumentLoc *, const Attr *, \
790 const DynTypedNode *
791
792#define IMPL(Index) \
793 template \
794 std::enable_if_t< \
795 llvm::is_one_of<const NodeType *, CMD_TYPES_##Index>::value> \
796 SetCallbackAndRawNode(const MatchCallback *CB, const NodeType &N) { \
797 assertEmpty(); \
798 Callback.setPointerAndInt(CB, Index); \
799 Node##Index = &N; \
800 } \
801 \
802 template \
803 std::enable_if_t<llvm::is_one_of<const T *, CMD_TYPES_##Index>::value, \
804 const T *> \
805 getNode() const { \
806 assertHoldsState(); \
807 return Callback.getInt() == (Index) ? Node##Index.dyn_cast<const T *>() \
808 : nullptr; \
809 }
810
811 public:
812 CurMatchData() : Node0(nullptr) {}
813
816
817 const MatchCallback *getCallback() const { return Callback.getPointer(); }
818
819 void SetBoundNodes(const BoundNodes &BN) {
820 assertHoldsState();
821 BNodes = &BN;
822 }
823
824 void clearBoundNodes() {
825 assertHoldsState();
826 BNodes = nullptr;
827 }
828
829 const BoundNodes *getBoundNodes() const {
830 assertHoldsState();
831 return BNodes;
832 }
833
834 void reset() {
835 assertHoldsState();
836 Callback.setPointerAndInt(nullptr, 0);
837 Node0 = nullptr;
838 }
839
840 private:
841 void assertHoldsState() const {
842 assert(Callback.getPointer() != nullptr && !Node0.isNull());
843 }
844
845 void assertEmpty() const {
846 assert(Callback.getPointer() == nullptr && Node0.isNull() &&
847 BNodes == nullptr);
848 }
849
850 llvm::PointerIntPair<const MatchCallback *, 1> Callback;
851 union {
852 llvm::PointerUnion<CMD_TYPES_0> Node0;
853 llvm::PointerUnion<CMD_TYPES_1> Node1;
854 };
855 const BoundNodes *BNodes = nullptr;
856
857#undef CMD_TYPES_0
858#undef CMD_TYPES_1
859#undef IMPL
860 } CurMatchState;
861
862 struct CurMatchRAII {
863 template
864 CurMatchRAII(MatchASTVisitor &MV, const MatchCallback *CB,
865 const NodeType &NT)
866 : MV(MV) {
867 MV.CurMatchState.SetCallbackAndRawNode(CB, NT);
868 }
869
870 ~CurMatchRAII() { MV.CurMatchState.reset(); }
871
872 private:
873 MatchASTVisitor &MV;
874 };
875
876public:
877 class TraceReporter : llvm::PrettyStackTraceEntry {
878 static void dumpNode(const ASTContext &Ctx, const DynTypedNode &Node,
879 raw_ostream &OS) {
880 if (const auto *D = Node.get()) {
881 OS << D->getDeclKindName() << "Decl ";
882 if (const auto *ND = dyn_cast(D)) {
883 ND->printQualifiedName(OS);
884 OS << " : ";
885 } else
886 OS << ": ";
888 } else if (const auto *S = Node.get()) {
889 OS << S->getStmtClassName() << " : ";
891 } else if (const auto *T = Node.get<Type>()) {
894 } else if (const auto *QT = Node.get()) {
895 OS << "QualType : ";
897 } else {
898 OS << Node.getNodeKind().asStringRef() << " : ";
900 }
901 }
902
903 static void dumpNodeFromState(const ASTContext &Ctx,
904 const CurMatchData &State, raw_ostream &OS) {
905 if (const DynTypedNode *MatchNode = State.getNode()) {
906 dumpNode(Ctx, *MatchNode, OS);
907 } else if (const auto *QT = State.getNode()) {
909 } else if (const auto *TL = State.getNode()) {
911 } else if (const auto *NNS = State.getNode()) {
913 } else if (const auto *NNSL = State.getNode()) {
915 } else if (const auto *CtorInit = State.getNode()) {
917 } else if (const auto *TAL = State.getNode()) {
919 } else if (const auto *At = State.getNode()) {
921 }
922 }
923
924 public:
925 TraceReporter(const MatchASTVisitor &MV) : MV(MV) {}
926 void print(raw_ostream &OS) const override {
927 const CurMatchData &State = MV.CurMatchState;
928 const MatchCallback *CB = State.getCallback();
929 if (!CB) {
930 OS << "ASTMatcher: Not currently matching\n";
931 return;
932 }
933
934 assert(MV.ActiveASTContext &&
935 "ActiveASTContext should be set if there is a matched callback");
936
937 ASTContext &Ctx = MV.getASTContext();
938
939 if (const BoundNodes *Nodes = State.getBoundNodes()) {
940 OS << "ASTMatcher: Processing '" << CB->getID() << "' against:\n\t";
941 dumpNodeFromState(Ctx, State, OS);
943 if (Map.empty()) {
944 OS << "\nNo bound nodes\n";
945 return;
946 }
947 OS << "\n--- Bound Nodes Begin ---\n";
948 for (const auto &Item : Map) {
949 OS << " " << Item.first << " - { ";
950 dumpNode(Ctx, Item.second, OS);
951 OS << " }\n";
952 }
953 OS << "--- Bound Nodes End ---\n";
954 } else {
955 OS << "ASTMatcher: Matching '" << CB->getID() << "' against:\n\t";
956 dumpNodeFromState(Ctx, State, OS);
957 OS << '\n';
958 }
959 }
960
961 private:
962 const MatchASTVisitor &MV;
963 };
964
965private:
966 struct ASTNodeNotSpelledInSourceScope {
967 ASTNodeNotSpelledInSourceScope(MatchASTVisitor *V, bool B)
968 : MV(V), MB(V->TraversingASTNodeNotSpelledInSource) {
969 V->TraversingASTNodeNotSpelledInSource = B;
970 }
971 ~ASTNodeNotSpelledInSourceScope() {
972 MV->TraversingASTNodeNotSpelledInSource = MB;
973 }
974
975 private:
976 MatchASTVisitor *MV;
977 bool MB;
978 };
979
980 struct ASTNodeNotAsIsSourceScope {
981 ASTNodeNotAsIsSourceScope(MatchASTVisitor *V, bool B)
982 : MV(V), MB(V->TraversingASTNodeNotAsIs) {
983 V->TraversingASTNodeNotAsIs = B;
984 }
985 ~ASTNodeNotAsIsSourceScope() { MV->TraversingASTNodeNotAsIs = MB; }
986
987 private:
988 MatchASTVisitor *MV;
989 bool MB;
990 };
991
992 class TimeBucketRegion {
993 public:
994 TimeBucketRegion() = default;
995 ~TimeBucketRegion() { setBucket(nullptr); }
996
997
998
999
1000
1001
1002
1003
1004
1005 void setBucket(llvm::TimeRecord *NewBucket) {
1006 if (Bucket != NewBucket) {
1007 auto Now = llvm::TimeRecord::getCurrentTime(true);
1008 if (Bucket)
1009 *Bucket += Now;
1010 if (NewBucket)
1011 *NewBucket -= Now;
1012 Bucket = NewBucket;
1013 }
1014 }
1015
1016 private:
1017 llvm::TimeRecord *Bucket = nullptr;
1018 };
1019
1020
1021
1022
1023 template <typename T, typename MC>
1024 void matchWithoutFilter(const T &Node, const MC &Matchers) {
1025 const bool EnableCheckProfiling = Options.CheckProfiling.has_value();
1026 TimeBucketRegion Timer;
1027 for (const auto &MP : Matchers) {
1028 if (EnableCheckProfiling)
1029 Timer.setBucket(&TimeByBucket[MP.second->getID()]);
1030 BoundNodesTreeBuilder Builder;
1031 CurMatchRAII RAII(*this, MP.second, Node);
1032 if (MP.first.matches(Node, this, &Builder)) {
1033 MatchVisitor Visitor(*this, ActiveASTContext, MP.second);
1034 Builder.visitMatches(&Visitor);
1035 }
1036 }
1037 }
1038
1039 void matchWithFilter(const DynTypedNode &DynNode) {
1040 auto Kind = DynNode.getNodeKind();
1041 auto it = MatcherFiltersMap.find(Kind);
1042 const auto &Filter =
1043 it != MatcherFiltersMap.end() ? it->second : getFilterForKind(Kind);
1044
1046 return;
1047
1048 const bool EnableCheckProfiling = Options.CheckProfiling.has_value();
1049 TimeBucketRegion Timer;
1050 auto &Matchers = this->Matchers->DeclOrStmt;
1051 for (unsigned short I : Filter) {
1052 auto &MP = Matchers[I];
1053 if (EnableCheckProfiling)
1054 Timer.setBucket(&TimeByBucket[MP.second->getID()]);
1055 BoundNodesTreeBuilder Builder;
1056
1057 {
1058 TraversalKindScope RAII(getASTContext(), MP.first.getTraversalKind());
1059 if (getASTContext().getParentMapContext().traverseIgnored(DynNode) !=
1060 DynNode)
1061 continue;
1062 }
1063
1064 CurMatchRAII RAII(*this, MP.second, DynNode);
1065 if (MP.first.matches(DynNode, this, &Builder)) {
1066 MatchVisitor Visitor(*this, ActiveASTContext, MP.second);
1067 Builder.visitMatches(&Visitor);
1068 }
1069 }
1070 }
1071
1072 const std::vector &getFilterForKind(ASTNodeKind Kind) {
1073 auto &Filter = MatcherFiltersMap[Kind];
1074 auto &Matchers = this->Matchers->DeclOrStmt;
1075 assert((Matchers.size() < USHRT_MAX) && "Too many matchers.");
1076 for (unsigned I = 0, E = Matchers.size(); I != E; ++I) {
1077 if (Matchers[I].first.canMatchNodesOfKind(Kind)) {
1078 Filter.push_back(I);
1079 }
1080 }
1082 }
1083
1084
1085
1086 void matchDispatch(const Decl *Node) {
1088 }
1089 void matchDispatch(const Stmt *Node) {
1091 }
1092
1093 void matchDispatch(const Type *Node) {
1094 matchWithoutFilter(QualType(Node, 0), Matchers->Type);
1095 }
1096 void matchDispatch(const TypeLoc *Node) {
1097 matchWithoutFilter(*Node, Matchers->TypeLoc);
1098 }
1099 void matchDispatch(const QualType *Node) {
1100 matchWithoutFilter(*Node, Matchers->Type);
1101 }
1102 void matchDispatch(const NestedNameSpecifier *Node) {
1103 matchWithoutFilter(*Node, Matchers->NestedNameSpecifier);
1104 }
1105 void matchDispatch(const NestedNameSpecifierLoc *Node) {
1106 matchWithoutFilter(*Node, Matchers->NestedNameSpecifierLoc);
1107 }
1108 void matchDispatch(const CXXCtorInitializer *Node) {
1109 matchWithoutFilter(*Node, Matchers->CtorInit);
1110 }
1111 void matchDispatch(const TemplateArgumentLoc *Node) {
1112 matchWithoutFilter(*Node, Matchers->TemplateArgumentLoc);
1113 }
1114 void matchDispatch(const Attr *Node) {
1115 matchWithoutFilter(*Node, Matchers->Attr);
1116 }
1117 void matchDispatch(const void *) { }
1118
1119
1120
1121
1122 bool matchesParentOf(const DynTypedNode &Node, const DynTypedMatcher &Matcher,
1123 BoundNodesTreeBuilder *Builder) {
1124 for (const auto &Parent : ActiveASTContext->getParents(Node)) {
1125 BoundNodesTreeBuilder BuilderCopy = *Builder;
1126 if (Matcher.matches(Parent, this, &BuilderCopy)) {
1127 *Builder = std::move(BuilderCopy);
1128 return true;
1129 }
1130 }
1131 return false;
1132 }
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150 bool matchesAnyAncestorOf(DynTypedNode Node, ASTContext &Ctx,
1151 const DynTypedMatcher &Matcher,
1152 BoundNodesTreeBuilder *Builder) {
1153
1154
1155
1156
1157 std::vector Keys;
1158
1159 auto Finish = [&](bool Matched) {
1160 for (const auto &Key : Keys) {
1161 MemoizedMatchResult &CachedResult = ResultCache[Key];
1162 CachedResult.ResultOfMatch = Matched;
1163 CachedResult.Nodes = *Builder;
1164 }
1165 return Matched;
1166 };
1167
1168
1169 DynTypedNodeList Parents{ArrayRef()};
1170 for (;;) {
1171
1172 if (Builder->isComparable()) {
1173 Keys.emplace_back();
1174 Keys.back().MatcherID = Matcher.getID();
1175 Keys.back().Node = Node;
1176 Keys.back().BoundNodes = *Builder;
1178 Keys.back().Type = MatchType::Ancestors;
1179
1180
1181 MemoizationMap::iterator I = ResultCache.find(Keys.back());
1182 if (I != ResultCache.end()) {
1183 Keys.pop_back();
1184 *Builder = I->second.Nodes;
1185 return Finish(I->second.ResultOfMatch);
1186 }
1187 }
1188
1189 Parents = ActiveASTContext->getParents(Node);
1190
1191
1192 if (Parents.size() != 1)
1193 break;
1194
1195
1196 Node = *Parents.begin();
1197 BoundNodesTreeBuilder BuilderCopy = *Builder;
1198 if (Matcher.matches(Node, this, &BuilderCopy)) {
1199 *Builder = std::move(BuilderCopy);
1200 return Finish(true);
1201 }
1202 }
1203
1204
1205 if (Parents.empty()) {
1206
1207
1208
1209
1210
1211
1212#ifndef NDEBUG
1213 if (!Node.get() &&
1214
1215 llvm::any_of(ActiveASTContext->getTraversalScope(), [](Decl *D) {
1216 return D->getKind() == Decl::TranslationUnit;
1217 })) {
1218 llvm::errs() << "Tried to match orphan node:\n";
1219 Node.dump(llvm::errs(), *ActiveASTContext);
1220 llvm_unreachable("Parent map should be complete!");
1221 }
1222#endif
1223 } else {
1224 assert(Parents.size() > 1);
1225
1226
1227
1228 std::deque Queue(Parents.begin(), Parents.end());
1229 llvm::DenseSet<const void *> Visited;
1230 while (!Queue.empty()) {
1231 BoundNodesTreeBuilder BuilderCopy = *Builder;
1232 if (Matcher.matches(Queue.front(), this, &BuilderCopy)) {
1233 *Builder = std::move(BuilderCopy);
1234 return Finish(true);
1235 }
1236 for (const auto &Parent : ActiveASTContext->getParents(Queue.front())) {
1237
1238
1239
1240 if (Visited.insert(Parent.getMemoizationData()).second)
1241 Queue.push_back(Parent);
1242 }
1243 Queue.pop_front();
1244 }
1245 }
1246 return Finish(false);
1247 }
1248
1249
1250
1251 class MatchVisitor : public BoundNodesTreeBuilder::Visitor {
1252 struct CurBoundScope {
1253 CurBoundScope(MatchASTVisitor::CurMatchData &State, const BoundNodes &BN)
1254 : State(State) {
1255 State.SetBoundNodes(BN);
1256 }
1257
1258 ~CurBoundScope() { State.clearBoundNodes(); }
1259
1260 private:
1261 MatchASTVisitor::CurMatchData &State;
1262 };
1263
1264 public:
1265 MatchVisitor(MatchASTVisitor &MV, ASTContext *Context,
1266 MatchFinder::MatchCallback *Callback)
1267 : State(MV.CurMatchState), Context(Context), Callback(Callback) {}
1268
1269 void visitMatch(const BoundNodes& BoundNodesView) override {
1270 TraversalKindScope RAII(*Context, Callback->getCheckTraversalKind());
1271 CurBoundScope RAII2(State, BoundNodesView);
1272 Callback->run(MatchFinder::MatchResult(BoundNodesView, Context));
1273 }
1274
1275 private:
1276 MatchASTVisitor::CurMatchData &State;
1277 ASTContext* Context;
1278 MatchFinder::MatchCallback* Callback;
1279 };
1280
1281
1282 bool typeHasMatchingAlias(const Type *TypeNode,
1283 const Matcher &Matcher,
1284 BoundNodesTreeBuilder *Builder) {
1285 const Type *const CanonicalType =
1286 ActiveASTContext->getCanonicalType(TypeNode);
1287 auto Aliases = TypeAliases.find(CanonicalType);
1288 if (Aliases == TypeAliases.end())
1289 return false;
1290
1291 auto matches = [&](const TypedefNameDecl *Alias) {
1292 BoundNodesTreeBuilder Result(*Builder);
1293 if (Matcher.matches(*Alias, this, &Result)) {
1294 *Builder = std::move(Result);
1295 return true;
1296 }
1297 return false;
1298 };
1299
1300 if (const auto *T = TypeNode->getAs()) {
1301 const auto *TD = T->getDecl()->getCanonicalDecl();
1302
1303
1304 SmallVector<const TypedefNameDecl *, 8> NonExactMatches;
1305 for (const TypedefNameDecl *Alias : Aliases->second) {
1307 NonExactMatches.push_back(Alias);
1308 continue;
1309 }
1311 return true;
1312 }
1313
1314 for (const TypedefNameDecl *Alias : NonExactMatches) {
1315 BoundNodesTreeBuilder Result(*Builder);
1316 if (Matcher.matches(*Alias, this, &Result)) {
1317 *Builder = std::move(Result);
1318 return true;
1319 }
1320 }
1321 return false;
1322 }
1323
1324 for (const TypedefNameDecl *Alias : Aliases->second)
1326 return true;
1327 return false;
1328 }
1329
1330 bool
1331 objcClassHasMatchingCompatibilityAlias(const ObjCInterfaceDecl *InterfaceDecl,
1332 const Matcher &Matcher,
1333 BoundNodesTreeBuilder *Builder) {
1334 auto Aliases = CompatibleAliases.find(InterfaceDecl);
1335 if (Aliases == CompatibleAliases.end())
1336 return false;
1337 for (const ObjCCompatibleAliasDecl *Alias : Aliases->second) {
1338 BoundNodesTreeBuilder Result(*Builder);
1339 if (Matcher.matches(*Alias, this, &Result)) {
1340 *Builder = std::move(Result);
1341 return true;
1342 }
1343 }
1344 return false;
1345 }
1346
1347 template static SourceLocation getNodeLocation(const T &Node) {
1348 return Node.getBeginLoc();
1349 }
1350
1351 static SourceLocation getNodeLocation(const CXXCtorInitializer &Node) {
1352 return Node.getSourceLocation();
1353 }
1354
1355 static SourceLocation getNodeLocation(const TemplateArgumentLoc &Node) {
1356 return Node.getLocation();
1357 }
1358
1359 static SourceLocation getNodeLocation(const Attr &Node) {
1360 return Node.getLocation();
1361 }
1362
1363 bool isInSystemHeader(SourceLocation Loc) {
1364 const SourceManager &SM = getASTContext().getSourceManager();
1365 return SM.isInSystemHeader(Loc);
1366 }
1367
1368 template bool shouldSkipNode(T &Node) {
1369 if (Options.IgnoreSystemHeaders && isInSystemHeader(getNodeLocation(Node)))
1370 return true;
1371 return false;
1372 }
1373
1374 template bool shouldSkipNode(T *Node) {
1375 return (Node == nullptr) || shouldSkipNode(*Node);
1376 }
1377
1378 bool shouldSkipNode(QualType &) { return false; }
1379
1380 bool shouldSkipNode(NestedNameSpecifier &) { return false; }
1381
1382
1383
1384
1385 llvm::StringMapllvm::TimeRecord TimeByBucket;
1386
1387 const MatchFinder::MatchersByType *Matchers;
1388
1389
1390
1391
1392
1393
1394
1395 llvm::DenseMap<ASTNodeKind, std::vector> MatcherFiltersMap;
1396
1397 const MatchFinder::MatchFinderOptions &Options;
1398 ASTContext *ActiveASTContext;
1399
1400
1401 llvm::DenseMap<const Type*, std::set<const TypedefNameDecl*> > TypeAliases;
1402
1403
1404 llvm::DenseMap<const ObjCInterfaceDecl *,
1405 llvm::SmallPtrSet<const ObjCCompatibleAliasDecl *, 2>>
1406 CompatibleAliases;
1407
1408
1409 typedef std::map<MatchKey, MemoizedMatchResult> MemoizationMap;
1410 MemoizationMap ResultCache;
1411};
1412
1413static CXXRecordDecl *
1414getAsCXXRecordDeclOrPrimaryTemplate(const Type *TypeNode) {
1415 if (auto *RD = TypeNode->getAsCXXRecordDecl())
1416 return RD;
1417
1418
1419 auto *TemplateType = TypeNode->getAs();
1420 while (TemplateType && TemplateType->isTypeAlias())
1421 TemplateType =
1422 TemplateType->getAliasedType()->getAs();
1423
1424
1425
1426 if (TemplateType)
1427 if (auto *ClassTemplate = dyn_cast_or_null(
1428 TemplateType->getTemplateName().getAsTemplateDecl()))
1429 return ClassTemplate->getTemplatedDecl();
1430
1431 return nullptr;
1432}
1433
1434
1435
1436
1437bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
1438 const Matcher &Base,
1439 BoundNodesTreeBuilder *Builder,
1440 bool Directly) {
1441 llvm::SmallPtrSet<const CXXRecordDecl *, 8> Visited;
1442 return classIsDerivedFromImpl(Declaration, Base, Builder, Directly, Visited);
1443}
1444
1445bool MatchASTVisitor::classIsDerivedFromImpl(
1446 const CXXRecordDecl *Declaration, const Matcher &Base,
1447 BoundNodesTreeBuilder *Builder, bool Directly,
1448 llvm::SmallPtrSetImpl<const CXXRecordDecl *> &Visited) {
1450 return false;
1451 if (!Visited.insert(Declaration).second)
1452 return false;
1453 for (const auto &It : Declaration->bases()) {
1454 const Type *TypeNode = It.getType().getTypePtr();
1455
1456 if (typeHasMatchingAlias(TypeNode, Base, Builder))
1457 return true;
1458
1459
1460
1461
1462 CXXRecordDecl *ClassDecl = getAsCXXRecordDeclOrPrimaryTemplate(TypeNode);
1463 if (!ClassDecl)
1464 continue;
1465 if (ClassDecl == Declaration) {
1466
1467 continue;
1468 }
1469 BoundNodesTreeBuilder Result(*Builder);
1470 if (Base.matches(*ClassDecl, this, &Result)) {
1471 *Builder = std::move(Result);
1472 return true;
1473 }
1474 if (!Directly &&
1475 classIsDerivedFromImpl(ClassDecl, Base, Builder, Directly, Visited))
1476 return true;
1477 }
1478 return false;
1479}
1480
1481
1482
1483
1484bool MatchASTVisitor::objcClassIsDerivedFrom(
1485 const ObjCInterfaceDecl *Declaration, const Matcher &Base,
1486 BoundNodesTreeBuilder *Builder, bool Directly) {
1487
1488 for (const ObjCInterfaceDecl *ClassDecl = Declaration->getSuperClass();
1489 ClassDecl != nullptr; ClassDecl = ClassDecl->getSuperClass()) {
1490
1491 if (objcClassHasMatchingCompatibilityAlias(ClassDecl, Base, Builder))
1492 return true;
1493
1494
1495 const Type *TypeNode = ClassDecl->getTypeForDecl();
1496 if (typeHasMatchingAlias(TypeNode, Base, Builder))
1497 return true;
1498
1499 if (Base.matches(*ClassDecl, this, Builder))
1500 return true;
1501
1502
1503 if (Directly)
1504 break;
1505 }
1506
1507 return false;
1508}
1509
1510bool MatchASTVisitor::TraverseDecl(Decl *DeclNode) {
1511 if (shouldSkipNode(DeclNode))
1512 return true;
1513
1514 bool ScopedTraversal =
1515 TraversingASTNodeNotSpelledInSource || DeclNode->isImplicit();
1516 bool ScopedChildren = TraversingASTChildrenNotSpelledInSource;
1517
1518 if (const auto *CTSD = dyn_cast(DeclNode)) {
1519 auto SK = CTSD->getSpecializationKind();
1520 if (SK == TSK_ExplicitInstantiationDeclaration ||
1521 SK == TSK_ExplicitInstantiationDefinition)
1522 ScopedChildren = true;
1523 } else if (const auto *FD = dyn_cast(DeclNode)) {
1524 if (FD->isDefaulted())
1525 ScopedChildren = true;
1526 if (FD->isTemplateInstantiation())
1527 ScopedTraversal = true;
1528 } else if (isa(DeclNode)) {
1529 ScopedChildren = true;
1530 }
1531
1532 ASTNodeNotSpelledInSourceScope RAII1(this, ScopedTraversal);
1533 ASTChildrenNotSpelledInSourceScope RAII2(this, ScopedChildren);
1534
1535 match(*DeclNode);
1536 return RecursiveASTVisitor::TraverseDecl(DeclNode);
1537}
1538
1539bool MatchASTVisitor::TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue) {
1540 if (shouldSkipNode(StmtNode))
1541 return true;
1542
1543 bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
1544 TraversingASTChildrenNotSpelledInSource;
1545
1546 ASTNodeNotSpelledInSourceScope RAII(this, ScopedTraversal);
1547 match(*StmtNode);
1548 return RecursiveASTVisitor::TraverseStmt(StmtNode, Queue);
1549}
1550
1551bool MatchASTVisitor::TraverseType(QualType TypeNode, bool TraverseQualifier) {
1552 if (shouldSkipNode(TypeNode))
1553 return true;
1554
1555 match(TypeNode);
1556 return RecursiveASTVisitor::TraverseType(TypeNode,
1557 TraverseQualifier);
1558}
1559
1560bool MatchASTVisitor::TraverseTypeLoc(TypeLoc TypeLocNode,
1561 bool TraverseQualifier) {
1562 if (shouldSkipNode(TypeLocNode))
1563 return true;
1564
1565
1566
1567
1568
1569 match(TypeLocNode);
1570 match(TypeLocNode.getType());
1571 return RecursiveASTVisitor::TraverseTypeLoc(
1572 TypeLocNode, TraverseQualifier);
1573}
1574
1575bool MatchASTVisitor::TraverseNestedNameSpecifier(NestedNameSpecifier NNS) {
1576 if (shouldSkipNode(NNS))
1577 return true;
1578
1580 return RecursiveASTVisitor::TraverseNestedNameSpecifier(NNS);
1581}
1582
1583bool MatchASTVisitor::TraverseNestedNameSpecifierLoc(
1584 NestedNameSpecifierLoc NNS) {
1585 if (!NNS)
1586 return true;
1587
1588 if (shouldSkipNode(NNS))
1589 return true;
1590
1592
1593
1594
1595 if (NNS.hasQualifier())
1596 match(NNS.getNestedNameSpecifier());
1597 return
1598 RecursiveASTVisitor::TraverseNestedNameSpecifierLoc(NNS);
1599}
1600
1601bool MatchASTVisitor::TraverseConstructorInitializer(
1602 CXXCtorInitializer *CtorInit) {
1603 if (shouldSkipNode(CtorInit))
1604 return true;
1605
1606 bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
1607 TraversingASTChildrenNotSpelledInSource;
1608
1609 if (!CtorInit->isWritten())
1610 ScopedTraversal = true;
1611
1612 ASTNodeNotSpelledInSourceScope RAII1(this, ScopedTraversal);
1613
1614 match(*CtorInit);
1615
1616 return RecursiveASTVisitor::TraverseConstructorInitializer(
1617 CtorInit);
1618}
1619
1620bool MatchASTVisitor::TraverseTemplateArgumentLoc(TemplateArgumentLoc Loc) {
1621 if (shouldSkipNode(Loc))
1622 return true;
1623
1625 return RecursiveASTVisitor::TraverseTemplateArgumentLoc(Loc);
1626}
1627
1628bool MatchASTVisitor::TraverseAttr(Attr *AttrNode) {
1629 if (shouldSkipNode(AttrNode))
1630 return true;
1631
1632 match(*AttrNode);
1633 return RecursiveASTVisitor::TraverseAttr(AttrNode);
1634}
1635
1636class MatchASTConsumer : public ASTConsumer {
1637public:
1638 MatchASTConsumer(MatchFinder *Finder,
1639 MatchFinder::ParsingDoneTestCallback *ParsingDone)
1640 : Finder(Finder), ParsingDone(ParsingDone) {}
1641
1642private:
1643 void HandleTranslationUnit(ASTContext &Context) override {
1644 if (ParsingDone != nullptr) {
1645 ParsingDone->run();
1646 }
1648 }
1649
1650 MatchFinder *Finder;
1651 MatchFinder::ParsingDoneTestCallback *ParsingDone;
1652};
1653
1654}
1655}
1656
1661
1664
1666 : Options(std::move(Options)), ParsingDone(nullptr) {}
1667
1669
1672 std::optional TK;
1673 if (Action)
1675 if (TK)
1676 Matchers.DeclOrStmt.emplace_back(traverse(*TK, NodeMatch), Action);
1677 else
1678 Matchers.DeclOrStmt.emplace_back(NodeMatch, Action);
1679 Matchers.AllCallbacks.insert(Action);
1680}
1681
1684 Matchers.Type.emplace_back(NodeMatch, Action);
1685 Matchers.AllCallbacks.insert(Action);
1686}
1687
1690 std::optional TK;
1691 if (Action)
1693 if (TK)
1694 Matchers.DeclOrStmt.emplace_back(traverse(*TK, NodeMatch), Action);
1695 else
1696 Matchers.DeclOrStmt.emplace_back(NodeMatch, Action);
1697 Matchers.AllCallbacks.insert(Action);
1698}
1699
1702 Matchers.NestedNameSpecifier.emplace_back(NodeMatch, Action);
1703 Matchers.AllCallbacks.insert(Action);
1704}
1705
1708 Matchers.NestedNameSpecifierLoc.emplace_back(NodeMatch, Action);
1709 Matchers.AllCallbacks.insert(Action);
1710}
1711
1714 Matchers.TypeLoc.emplace_back(NodeMatch, Action);
1715 Matchers.AllCallbacks.insert(Action);
1716}
1717
1720 Matchers.CtorInit.emplace_back(NodeMatch, Action);
1721 Matchers.AllCallbacks.insert(Action);
1722}
1723
1726 Matchers.TemplateArgumentLoc.emplace_back(NodeMatch, Action);
1727 Matchers.AllCallbacks.insert(Action);
1728}
1729
1732 Matchers.Attr.emplace_back(AttrMatch, Action);
1733 Matchers.AllCallbacks.insert(Action);
1734}
1735
1738 if (NodeMatch.canConvertTo<Decl>()) {
1740 return true;
1741 } else if (NodeMatch.canConvertTo<QualType>()) {
1743 return true;
1744 } else if (NodeMatch.canConvertTo<Stmt>()) {
1746 return true;
1749 return true;
1752 return true;
1753 } else if (NodeMatch.canConvertTo<TypeLoc>()) {
1755 return true;
1758 return true;
1761 return true;
1762 } else if (NodeMatch.canConvertTo<Attr>()) {
1764 return true;
1765 }
1766 return false;
1767}
1768
1770 return std::make_uniqueinternal::MatchASTConsumer(this, ParsingDone);
1771}
1772
1774 internal::MatchASTVisitor Visitor(&Matchers, Options);
1775 Visitor.set_active_ast_context(&Context);
1776 Visitor.match(Node);
1777}
1778
1780 internal::MatchASTVisitor Visitor(&Matchers, Options);
1781 internal::MatchASTVisitor::TraceReporter StackTrace(Visitor);
1782 Visitor.set_active_ast_context(&Context);
1783 Visitor.onStartOfTranslationUnit();
1784 Visitor.TraverseAST(Context);
1785 Visitor.onEndOfTranslationUnit();
1786}
1787
1790 ParsingDone = NewParsingDone;
1791}
1792
1794
1795std::optional
1797 return std::nullopt;
1798}
1799
1800}
1801}
Defines the clang::ASTContext interface.
#define IMPL(Index)
Definition ASTMatchFinder.cpp:792
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc QualifierLoc)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
static void print(llvm::raw_ostream &OS, const T &V, ASTContext &ASTCtx, QualType Ty)
SourceManager & getSourceManager()
ParentMapContext & getParentMapContext()
Returns the dynamic AST node parent map context.
static CanQualType getCanonicalType(QualType T)
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
const clang::PrintingPolicy & getPrintingPolicy() const
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Attr - This represents one attribute.
Represents a C++ base or member initializer.
Decl - This represents one declaration (or definition), e.g.
A dynamically typed AST node container.
static DynTypedNode create(const T &Node)
Creates a DynTypedNode from Node.
Expr * getNoexceptExpr() const
Return the expression inside noexcept(expression), or a null pointer if there is none (because the ex...
ArrayRef< QualType > exceptions() const
A C++ nested-name-specifier augmented with source location information.
Represents a C++ nested name specifier, such as "\::std::vector::".
A (possibly-)qualified type.
bool TraverseStmt(Stmt *S, DataRecursionQueue *Queue=nullptr)
bool TraverseNestedNameSpecifier(NestedNameSpecifier NNS)
bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc)
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS)
bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier=true)
bool dataTraverseNode(Stmt *S, DataRecursionQueue *Queue)
bool TraverseDecl(Decl *D)
bool TraverseAttr(Attr *At)
bool TraverseType(QualType T, bool TraverseQualifier=true)
bool TraverseConstructorInitializer(CXXCtorInitializer *Init)
Stmt - This represents one statement.
Location wrapper for a TemplateArgument.
Base wrapper for a particular "section" of type source info.
const char * getTypeClassName() const
Maps string IDs to AST nodes matched by parts of a matcher.
internal::BoundNodesMap::IDToNodeMap IDToNodeMap
Type of mapping from binding identifiers to bound nodes.
Called when the Match registered for it was successfully found in the AST.
virtual std::optional< TraversalKind > getCheckTraversalKind() const
TraversalKind to use while matching and processing the result nodes.
Definition ASTMatchFinder.cpp:1796
virtual StringRef getID() const
An id used to group the matchers.
Definition ASTMatchFinder.cpp:1793
virtual ~MatchCallback()
Definition ASTMatchFinder.cpp:1662
Called when parsing is finished. Intended for testing only.
virtual ~ParsingDoneTestCallback()
Definition ASTMatchFinder.cpp:1663
MatchFinder(MatchFinderOptions Options=MatchFinderOptions())
Definition ASTMatchFinder.cpp:1665
~MatchFinder()
Definition ASTMatchFinder.cpp:1668
bool addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch, MatchCallback *Action)
Adds a matcher to execute when running over the AST.
Definition ASTMatchFinder.cpp:1736
void addMatcher(const DeclarationMatcher &NodeMatch, MatchCallback *Action)
Adds a matcher to execute when running over the AST.
Definition ASTMatchFinder.cpp:1670
void match(const T &Node, ASTContext &Context)
Calls the registered callbacks on all matches on the given Node.
void registerTestCallbackAfterParsing(ParsingDoneTestCallback *ParsingDone)
Registers a callback to notify the end of parsing.
Definition ASTMatchFinder.cpp:1788
std::unique_ptr< clang::ASTConsumer > newASTConsumer()
Creates a clang ASTConsumer that finds all matches.
Definition ASTMatchFinder.cpp:1769
void matchAST(ASTContext &Context)
Finds all matches in the given AST.
Definition ASTMatchFinder.cpp:1779
internal::Matcher< QualType > TypeMatcher
internal::Matcher< Decl > DeclarationMatcher
Types of matchers for the top-level classes in the AST class hierarchy.
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
internal::Matcher< Attr > AttrMatcher
internal::Matcher< CXXCtorInitializer > CXXCtorInitializerMatcher
internal::Matcher< Stmt > StatementMatcher
internal::Matcher< TemplateArgumentLoc > TemplateArgumentLocMatcher
internal::Matcher< NestedNameSpecifierLoc > NestedNameSpecifierLocMatcher
internal::Matcher< T > traverse(TraversalKind TK, const internal::Matcher< T > &InnerMatcher)
Causes all nested matchers to be matched with the specified traversal kind.
internal::Matcher< NestedNameSpecifier > NestedNameSpecifierMatcher
internal::Matcher< TypeLoc > TypeLocMatcher
DynTypedNode DynTypedNode
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
bool LE(InterpState &S, CodePtr OpPC)
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
bool matches(const til::SExpr *E1, const til::SExpr *E2)
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
@ Bind
'bind' clause, allowed on routine constructs.
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
bool operator<(DeclarationName LHS, DeclarationName RHS)
Ordering on two declaration names.
TraversalKind
Defines how we descend a level in the AST when we pass through expressions.
@ TK_AsIs
Will traverse all child nodes.
@ TK_IgnoreUnlessSpelledInSource
Ignore AST nodes not written in the source.
@ Result
The result type of a method or function.
const FunctionProtoType * T
@ Type
The name was classified as a type.
bool declaresSameEntity(const Decl *D1, const Decl *D2)
Determine whether two declarations declare the same entity.
@ Other
Other implicit parameter.
clang::SourceManager *const SourceManager
MatchResult(const BoundNodes &Nodes, clang::ASTContext *Context)
Definition ASTMatchFinder.cpp:1657
const BoundNodes Nodes
Contains the nodes bound on the current match.
clang::ASTContext *const Context
Utilities for interpreting the matched AST structures.