22 #include "llvm/ADT/DenseMap.h" 23 #include "llvm/ADT/StringMap.h" 24 #include "llvm/Support/Timer.h" 34 typedef MatchFinder::MatchCallback MatchCallback;
44 static const unsigned MaxMemoizationEntries = 10000;
64 bool operator<(
const MatchKey &Other)
const {
65 return std::tie(MatcherID, Node, BoundNodes, Traversal) <
66 std::tie(Other.MatcherID, Other.Node, Other.BoundNodes,
72 struct MemoizedMatchResult {
79 class MatchChildASTVisitor
80 :
public RecursiveASTVisitor<MatchChildASTVisitor> {
82 typedef RecursiveASTVisitor<MatchChildASTVisitor> VisitorBase;
88 MatchChildASTVisitor(
const DynTypedMatcher *Matcher, ASTMatchFinder *Finder,
89 BoundNodesTreeBuilder *Builder,
int MaxDepth,
91 ASTMatchFinder::BindKind Bind)
92 : Matcher(Matcher), Finder(Finder), Builder(Builder), CurrentDepth(0),
93 MaxDepth(MaxDepth),
Traversal(Traversal), Bind(Bind), Matches(
false) {}
108 if (
const Decl *D = DynNode.get<Decl>())
110 else if (
const Stmt *S = DynNode.get<Stmt>())
112 else if (
const NestedNameSpecifier *NNS =
113 DynNode.get<NestedNameSpecifier>())
115 else if (
const NestedNameSpecifierLoc *NNSLoc =
116 DynNode.get<NestedNameSpecifierLoc>())
118 else if (
const QualType *Q = DynNode.get<QualType>())
120 else if (
const TypeLoc *T = DynNode.get<TypeLoc>())
122 else if (
const auto *C = DynNode.get<CXXCtorInitializer>())
129 *Builder = ResultBindings;
137 bool TraverseDecl(Decl *DeclNode) {
138 ScopedIncrement ScopedDepth(&CurrentDepth);
139 return (DeclNode ==
nullptr) ||
traverse(*DeclNode);
142 Stmt *getStmtToTraverse(Stmt *StmtNode) {
143 Stmt *StmtToTraverse = StmtNode;
144 if (
auto *ExprNode = dyn_cast_or_null<Expr>(StmtNode)) {
145 auto *LambdaNode = dyn_cast_or_null<LambdaExpr>(StmtNode);
146 if (LambdaNode && Finder->getASTContext().getTraversalKind() ==
148 StmtToTraverse = LambdaNode;
150 StmtToTraverse = Finder->getASTContext().traverseIgnored(ExprNode);
154 if (Expr *ExprNode = dyn_cast_or_null<Expr>(StmtNode))
155 StmtToTraverse = ExprNode->IgnoreParenImpCasts();
157 return StmtToTraverse;
160 bool TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue =
nullptr) {
162 if (CurrentDepth == 0 || (CurrentDepth <= MaxDepth && MaxDepth <
INT_MAX))
165 ScopedIncrement ScopedDepth(&CurrentDepth);
166 Stmt *StmtToTraverse = getStmtToTraverse(StmtNode);
169 if (!
match(*StmtToTraverse))
171 return VisitorBase::TraverseStmt(StmtToTraverse, Queue);
175 bool TraverseType(QualType TypeNode) {
176 if (TypeNode.isNull())
178 ScopedIncrement ScopedDepth(&CurrentDepth);
180 if (!
match(*TypeNode))
187 bool TraverseTypeLoc(TypeLoc TypeLocNode) {
188 if (TypeLocNode.isNull())
190 ScopedIncrement ScopedDepth(&CurrentDepth);
192 if (!
match(*TypeLocNode.getType()))
195 if (!
match(TypeLocNode.getType()))
200 bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {
201 ScopedIncrement ScopedDepth(&CurrentDepth);
202 return (NNS ==
nullptr) ||
traverse(*NNS);
204 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
207 ScopedIncrement ScopedDepth(&CurrentDepth);
208 if (!
match(*NNS.getNestedNameSpecifier()))
212 bool TraverseConstructorInitializer(CXXCtorInitializer *CtorInit) {
215 ScopedIncrement ScopedDepth(&CurrentDepth);
218 bool TraverseLambdaExpr(LambdaExpr *
Node) {
219 if (Finder->getASTContext().getTraversalKind() !=
221 return VisitorBase::TraverseLambdaExpr(Node);
224 ScopedIncrement ScopedDepth(&CurrentDepth);
226 for (
unsigned I = 0, N = Node->capture_size(); I != N; ++I) {
227 const auto *C = Node->capture_begin() + I;
228 if (!C->isExplicit())
230 if (Node->isInitCapture(C) && !
match(*C->getCapturedVar()))
232 if (!
match(*Node->capture_init_begin()[I]))
236 if (
const auto *TPL = Node->getTemplateParameterList()) {
237 for (
const auto *TP : *TPL) {
243 for (
const auto *
P : Node->getCallOperator()->parameters()) {
248 if (!
match(*Node->getBody()))
254 bool shouldVisitTemplateInstantiations()
const {
return true; }
255 bool shouldVisitImplicitCode()
const {
return true; }
259 struct ScopedIncrement {
260 explicit ScopedIncrement(
int *
Depth) :
Depth(Depth) { ++(*Depth); }
261 ~ScopedIncrement() { --(*Depth); }
275 bool baseTraverse(
const Decl &DeclNode) {
276 return VisitorBase::TraverseDecl(const_cast<Decl*>(&DeclNode));
278 bool baseTraverse(
const Stmt &StmtNode) {
279 return VisitorBase::TraverseStmt(const_cast<Stmt*>(&StmtNode));
281 bool baseTraverse(QualType TypeNode) {
282 return VisitorBase::TraverseType(TypeNode);
284 bool baseTraverse(TypeLoc TypeLocNode) {
285 return VisitorBase::TraverseTypeLoc(TypeLocNode);
287 bool baseTraverse(
const NestedNameSpecifier &NNS) {
288 return VisitorBase::TraverseNestedNameSpecifier(
289 const_cast<NestedNameSpecifier*>(&NNS));
291 bool baseTraverse(NestedNameSpecifierLoc NNS) {
292 return VisitorBase::TraverseNestedNameSpecifierLoc(NNS);
294 bool baseTraverse(
const CXXCtorInitializer &CtorInit) {
295 return VisitorBase::TraverseConstructorInitializer(
296 const_cast<CXXCtorInitializer *>(&CtorInit));
304 template <
typename T>
305 bool match(
const T &Node) {
306 if (CurrentDepth == 0 || CurrentDepth > MaxDepth) {
309 if (Bind != ASTMatchFinder::BK_All) {
310 BoundNodesTreeBuilder RecursiveBuilder(*Builder);
312 &RecursiveBuilder)) {
314 ResultBindings.addMatch(RecursiveBuilder);
318 BoundNodesTreeBuilder RecursiveBuilder(*Builder);
320 &RecursiveBuilder)) {
323 ResultBindings.addMatch(RecursiveBuilder);
331 template <
typename T>
333 static_assert(IsBaseType<T>::value,
334 "traverse can only be instantiated with base type");
337 return baseTraverse(Node);
340 const DynTypedMatcher *
const Matcher;
341 ASTMatchFinder *
const Finder;
342 BoundNodesTreeBuilder *
const Builder;
343 BoundNodesTreeBuilder ResultBindings;
347 const ASTMatchFinder::BindKind Bind;
353 class MatchASTVisitor :
public RecursiveASTVisitor<MatchASTVisitor>,
354 public ASTMatchFinder {
356 MatchASTVisitor(
const MatchFinder::MatchersByType *Matchers,
357 const MatchFinder::MatchFinderOptions &Options)
358 : Matchers(Matchers), Options(Options), ActiveASTContext(
nullptr) {}
360 ~MatchASTVisitor()
override {
361 if (Options.CheckProfiling) {
362 Options.CheckProfiling->Records = std::move(TimeByBucket);
366 void onStartOfTranslationUnit() {
367 const bool EnableCheckProfiling = Options.CheckProfiling.hasValue();
368 TimeBucketRegion Timer;
369 for (MatchCallback *MC : Matchers->AllCallbacks) {
370 if (EnableCheckProfiling)
371 Timer.setBucket(&TimeByBucket[MC->getID()]);
372 MC->onStartOfTranslationUnit();
376 void onEndOfTranslationUnit() {
377 const bool EnableCheckProfiling = Options.CheckProfiling.hasValue();
378 TimeBucketRegion Timer;
379 for (MatchCallback *MC : Matchers->AllCallbacks) {
380 if (EnableCheckProfiling)
381 Timer.setBucket(&TimeByBucket[MC->getID()]);
382 MC->onEndOfTranslationUnit();
386 void set_active_ast_context(ASTContext *NewActiveASTContext) {
387 ActiveASTContext = NewActiveASTContext;
393 bool VisitTypedefNameDecl(TypedefNameDecl *DeclNode) {
421 const Type *TypeNode = DeclNode->getUnderlyingType().getTypePtr();
422 const Type *CanonicalType =
423 ActiveASTContext->getCanonicalType(TypeNode);
424 TypeAliases[CanonicalType].insert(DeclNode);
428 bool VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) {
429 const ObjCInterfaceDecl *InterfaceDecl = CAD->getClassInterface();
430 CompatibleAliases[InterfaceDecl].insert(CAD);
434 bool TraverseDecl(Decl *DeclNode);
435 bool TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue =
nullptr);
436 bool TraverseType(QualType TypeNode);
437 bool TraverseTypeLoc(TypeLoc TypeNode);
438 bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS);
439 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);
440 bool TraverseConstructorInitializer(CXXCtorInitializer *CtorInit);
445 const DynTypedMatcher &Matcher,
446 BoundNodesTreeBuilder *Builder,
int MaxDepth,
450 if (!Node.getMemoizationData() || !Builder->isComparable())
451 return matchesRecursively(Node, Matcher, Builder, MaxDepth, Traversal,
455 Key.MatcherID = Matcher.getID();
458 Key.BoundNodes = *Builder;
459 Key.Traversal = Ctx.getTraversalKind();
461 MemoizationMap::iterator I = ResultCache.find(Key);
462 if (I != ResultCache.end()) {
463 *Builder = I->second.Nodes;
464 return I->second.ResultOfMatch;
467 MemoizedMatchResult Result;
468 Result.Nodes = *Builder;
469 Result.ResultOfMatch = matchesRecursively(Node, Matcher, &Result.Nodes,
470 MaxDepth, Traversal, Bind);
472 MemoizedMatchResult &CachedResult = ResultCache[Key];
473 CachedResult = std::move(Result);
475 *Builder = CachedResult.Nodes;
476 return CachedResult.ResultOfMatch;
481 const DynTypedMatcher &Matcher,
482 BoundNodesTreeBuilder *Builder,
int MaxDepth,
485 MatchChildASTVisitor Visitor(
486 &Matcher,
this, Builder, MaxDepth, Traversal, Bind);
487 return Visitor.findMatch(Node);
490 bool classIsDerivedFrom(
const CXXRecordDecl *Declaration,
491 const Matcher<NamedDecl> &
Base,
492 BoundNodesTreeBuilder *Builder,
493 bool Directly)
override;
495 bool objcClassIsDerivedFrom(
const ObjCInterfaceDecl *Declaration,
496 const Matcher<NamedDecl> &Base,
497 BoundNodesTreeBuilder *Builder,
498 bool Directly)
override;
502 ASTContext &Ctx,
const DynTypedMatcher &Matcher,
503 BoundNodesTreeBuilder *Builder,
505 BindKind Bind)
override {
506 if (ResultCache.size() > MaxMemoizationEntries)
508 return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder, 1, Traversal,
513 ASTContext &Ctx,
const DynTypedMatcher &Matcher,
514 BoundNodesTreeBuilder *Builder,
515 BindKind Bind)
override {
516 if (ResultCache.size() > MaxMemoizationEntries)
518 return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder,
INT_MAX,
524 ASTContext &Ctx,
const DynTypedMatcher &Matcher,
525 BoundNodesTreeBuilder *Builder,
526 AncestorMatchMode MatchMode)
override {
529 if (ResultCache.size() > MaxMemoizationEntries)
531 return memoizedMatchesAncestorOfRecursively(Node, Ctx, Matcher, Builder,
539 if (
auto *N = Node.get<Decl>()) {
541 }
else if (
auto *N = Node.get<Stmt>()) {
543 }
else if (
auto *N = Node.get<
Type>()) {
545 }
else if (
auto *N = Node.get<QualType>()) {
547 }
else if (
auto *N = Node.get<NestedNameSpecifier>()) {
549 }
else if (
auto *N = Node.get<NestedNameSpecifierLoc>()) {
551 }
else if (
auto *N = Node.get<TypeLoc>()) {
553 }
else if (
auto *N = Node.get<CXXCtorInitializer>()) {
558 template <
typename T>
void match(
const T &Node) {
559 matchDispatch(&Node);
563 ASTContext &getASTContext()
const override {
return *ActiveASTContext; }
565 bool shouldVisitTemplateInstantiations()
const {
return true; }
566 bool shouldVisitImplicitCode()
const {
return true; }
569 class TimeBucketRegion {
571 TimeBucketRegion() : Bucket(
nullptr) {}
572 ~TimeBucketRegion() { setBucket(
nullptr); }
582 void setBucket(llvm::TimeRecord *NewBucket) {
583 if (Bucket != NewBucket) {
584 auto Now = llvm::TimeRecord::getCurrentTime(
true);
594 llvm::TimeRecord *Bucket;
600 template <
typename T,
typename MC>
601 void matchWithoutFilter(
const T &Node,
const MC &Matchers) {
602 const bool EnableCheckProfiling = Options.CheckProfiling.hasValue();
603 TimeBucketRegion Timer;
604 for (
const auto &MP : Matchers) {
605 if (EnableCheckProfiling)
606 Timer.setBucket(&TimeByBucket[MP.second->getID()]);
607 BoundNodesTreeBuilder Builder;
608 if (MP.first.matches(Node,
this, &Builder)) {
609 MatchVisitor Visitor(ActiveASTContext, MP.second);
610 Builder.visitMatches(&Visitor);
616 auto Kind = DynNode.getNodeKind();
617 auto it = MatcherFiltersMap.find(
Kind);
619 it != MatcherFiltersMap.end() ? it->second : getFilterForKind(
Kind);
624 const bool EnableCheckProfiling = Options.CheckProfiling.hasValue();
625 TimeBucketRegion Timer;
626 auto &Matchers = this->Matchers->DeclOrStmt;
627 for (
unsigned short I :
Filter) {
628 auto &MP = Matchers[I];
629 if (EnableCheckProfiling)
630 Timer.setBucket(&TimeByBucket[MP.second->getID()]);
631 BoundNodesTreeBuilder Builder;
632 if (MP.first.matches(DynNode,
this, &Builder)) {
633 MatchVisitor Visitor(ActiveASTContext, MP.second);
634 Builder.visitMatches(&Visitor);
639 const std::vector<unsigned short> &
640 getFilterForKind(ast_type_traits::ASTNodeKind
Kind) {
642 auto &Matchers = this->Matchers->DeclOrStmt;
643 assert((Matchers.size() <
USHRT_MAX) &&
"Too many matchers.");
644 for (
unsigned I = 0, E = Matchers.size(); I != E; ++I) {
645 if (Matchers[I].first.canMatchNodesOfKind(Kind)) {
654 void matchDispatch(
const Decl *Node) {
657 void matchDispatch(
const Stmt *Node) {
661 void matchDispatch(
const Type *Node) {
662 matchWithoutFilter(QualType(Node, 0), Matchers->Type);
664 void matchDispatch(
const TypeLoc *Node) {
665 matchWithoutFilter(*Node, Matchers->TypeLoc);
667 void matchDispatch(
const QualType *Node) {
668 matchWithoutFilter(*Node, Matchers->Type);
670 void matchDispatch(
const NestedNameSpecifier *Node) {
671 matchWithoutFilter(*Node, Matchers->NestedNameSpecifier);
673 void matchDispatch(
const NestedNameSpecifierLoc *Node) {
674 matchWithoutFilter(*Node, Matchers->NestedNameSpecifierLoc);
676 void matchDispatch(
const CXXCtorInitializer *Node) {
677 matchWithoutFilter(*Node, Matchers->CtorInit);
679 void matchDispatch(
const void *) { }
695 bool memoizedMatchesAncestorOfRecursively(
697 const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder,
698 AncestorMatchMode MatchMode) {
700 if (!Builder->isComparable())
701 return matchesAncestorOfRecursively(Node, Ctx, Matcher, Builder,
705 Key.MatcherID = Matcher.getID();
707 Key.BoundNodes = *Builder;
708 Key.Traversal = Ctx.getTraversalKind();
712 MemoizationMap::iterator I = ResultCache.find(Key);
713 if (I != ResultCache.end()) {
714 *Builder = I->second.Nodes;
715 return I->second.ResultOfMatch;
718 MemoizedMatchResult Result;
719 Result.Nodes = *Builder;
720 Result.ResultOfMatch = matchesAncestorOfRecursively(
721 Node, Ctx, Matcher, &Result.Nodes, MatchMode);
723 MemoizedMatchResult &CachedResult = ResultCache[Key];
724 CachedResult = std::move(Result);
726 *Builder = CachedResult.Nodes;
727 return CachedResult.ResultOfMatch;
732 const DynTypedMatcher &Matcher,
733 BoundNodesTreeBuilder *Builder,
734 AncestorMatchMode MatchMode) {
735 const auto &Parents = ActiveASTContext->getParents(Node);
736 if (Parents.empty()) {
744 if (!Node.get<TranslationUnitDecl>() &&
746 llvm::any_of(ActiveASTContext->getTraversalScope(), [](Decl *D) {
747 return D->getKind() == Decl::TranslationUnit;
749 llvm::errs() <<
"Tried to match orphan node:\n";
750 Node.dump(llvm::errs(), ActiveASTContext->getSourceManager());
751 llvm_unreachable(
"Parent map should be complete!");
756 if (Parents.size() == 1) {
759 BoundNodesTreeBuilder BuilderCopy = *Builder;
760 if (Matcher.matches(Parent,
this, &BuilderCopy)) {
761 *Builder = std::move(BuilderCopy);
764 if (MatchMode != ASTMatchFinder::AMM_ParentOnly) {
765 return memoizedMatchesAncestorOfRecursively(Parent, Ctx, Matcher,
773 std::deque<ast_type_traits::DynTypedNode> Queue(Parents.begin(),
775 while (!Queue.empty()) {
776 BoundNodesTreeBuilder BuilderCopy = *Builder;
777 if (Matcher.matches(Queue.front(),
this, &BuilderCopy)) {
778 *Builder = std::move(BuilderCopy);
781 if (MatchMode != ASTMatchFinder::AMM_ParentOnly) {
783 ActiveASTContext->getParents(Queue.front())) {
787 if (Visited.insert(
Parent.getMemoizationData()).second)
799 class MatchVisitor :
public BoundNodesTreeBuilder::Visitor {
801 MatchVisitor(ASTContext* Context,
802 MatchFinder::MatchCallback* Callback)
804 Callback(Callback) {}
806 void visitMatch(
const BoundNodes& BoundNodesView)
override {
812 MatchFinder::MatchCallback* Callback;
816 bool typeHasMatchingAlias(
const Type *TypeNode,
817 const Matcher<NamedDecl> &Matcher,
818 BoundNodesTreeBuilder *Builder) {
819 const Type *
const CanonicalType =
820 ActiveASTContext->getCanonicalType(TypeNode);
821 auto Aliases = TypeAliases.find(CanonicalType);
822 if (Aliases == TypeAliases.end())
824 for (
const TypedefNameDecl *Alias : Aliases->second) {
825 BoundNodesTreeBuilder Result(*Builder);
826 if (Matcher.matches(*Alias,
this, &Result)) {
827 *Builder = std::move(Result);
835 objcClassHasMatchingCompatibilityAlias(
const ObjCInterfaceDecl *InterfaceDecl,
836 const Matcher<NamedDecl> &Matcher,
837 BoundNodesTreeBuilder *Builder) {
838 auto Aliases = CompatibleAliases.find(InterfaceDecl);
839 if (Aliases == CompatibleAliases.end())
841 for (
const ObjCCompatibleAliasDecl *Alias : Aliases->second) {
842 BoundNodesTreeBuilder Result(*Builder);
843 if (Matcher.matches(*Alias,
this, &Result)) {
844 *Builder = std::move(Result);
854 llvm::StringMap<llvm::TimeRecord> TimeByBucket;
856 const MatchFinder::MatchersByType *Matchers;
864 llvm::DenseMap<ast_type_traits::ASTNodeKind, std::vector<unsigned short>>
867 const MatchFinder::MatchFinderOptions &Options;
868 ASTContext *ActiveASTContext;
871 llvm::DenseMap<const Type*, std::set<const TypedefNameDecl*> > TypeAliases;
874 llvm::DenseMap<
const ObjCInterfaceDecl *,
875 llvm::SmallPtrSet<const ObjCCompatibleAliasDecl *, 2>>
879 typedef std::map<MatchKey, MemoizedMatchResult> MemoizationMap;
880 MemoizationMap ResultCache;
883 static CXXRecordDecl *
884 getAsCXXRecordDeclOrPrimaryTemplate(
const Type *TypeNode) {
885 if (
auto *RD = TypeNode->getAsCXXRecordDecl())
889 auto *TemplateType = TypeNode->getAs<TemplateSpecializationType>();
890 while (TemplateType && TemplateType->isTypeAlias())
892 TemplateType->getAliasedType()->getAs<TemplateSpecializationType>();
897 if (
auto *ClassTemplate = dyn_cast_or_null<ClassTemplateDecl>(
898 TemplateType->getTemplateName().getAsTemplateDecl()))
899 return ClassTemplate->getTemplatedDecl();
907 bool MatchASTVisitor::classIsDerivedFrom(
const CXXRecordDecl *Declaration,
908 const Matcher<NamedDecl> &
Base,
909 BoundNodesTreeBuilder *Builder,
911 if (!Declaration->hasDefinition())
913 for (
const auto &It : Declaration->bases()) {
914 const Type *TypeNode = It.getType().getTypePtr();
916 if (typeHasMatchingAlias(TypeNode, Base, Builder))
922 CXXRecordDecl *ClassDecl = getAsCXXRecordDeclOrPrimaryTemplate(TypeNode);
925 if (ClassDecl == Declaration) {
930 BoundNodesTreeBuilder Result(*Builder);
931 if (Base.matches(*ClassDecl,
this, &Result)) {
932 *Builder = std::move(Result);
935 if (!Directly && classIsDerivedFrom(ClassDecl, Base, Builder, Directly))
944 bool MatchASTVisitor::objcClassIsDerivedFrom(
945 const ObjCInterfaceDecl *Declaration,
const Matcher<NamedDecl> &Base,
946 BoundNodesTreeBuilder *Builder,
bool Directly) {
948 for (
const ObjCInterfaceDecl *ClassDecl = Declaration->getSuperClass();
949 ClassDecl !=
nullptr; ClassDecl = ClassDecl->getSuperClass()) {
951 if (objcClassHasMatchingCompatibilityAlias(ClassDecl, Base, Builder))
955 const Type *TypeNode = ClassDecl->getTypeForDecl();
956 if (typeHasMatchingAlias(TypeNode, Base, Builder))
959 if (Base.matches(*ClassDecl,
this, Builder))
970 bool MatchASTVisitor::TraverseDecl(Decl *DeclNode) {
978 bool MatchASTVisitor::TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue) {
986 bool MatchASTVisitor::TraverseType(QualType TypeNode) {
991 bool MatchASTVisitor::TraverseTypeLoc(TypeLoc TypeLocNode) {
998 match(TypeLocNode.getType());
1002 bool MatchASTVisitor::TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {
1007 bool MatchASTVisitor::TraverseNestedNameSpecifierLoc(
1008 NestedNameSpecifierLoc NNS) {
1016 if (NNS.hasQualifier())
1017 match(*NNS.getNestedNameSpecifier());
1022 bool MatchASTVisitor::TraverseConstructorInitializer(
1023 CXXCtorInitializer *CtorInit) {
1033 class MatchASTConsumer :
public ASTConsumer {
1035 MatchASTConsumer(MatchFinder *Finder,
1036 MatchFinder::ParsingDoneTestCallback *ParsingDone)
1037 : Finder(Finder), ParsingDone(ParsingDone) {}
1040 void HandleTranslationUnit(ASTContext &Context)
override {
1041 if (ParsingDone !=
nullptr) {
1044 Finder->matchAST(Context);
1047 MatchFinder *Finder;
1048 MatchFinder::ParsingDoneTestCallback *ParsingDone;
1056 : Nodes(Nodes), Context(Context),
1063 : Options(
std::move(Options)), ParsingDone(nullptr) {}
1069 Matchers.
DeclOrStmt.emplace_back(NodeMatch, Action);
1075 Matchers.
Type.emplace_back(NodeMatch, Action);
1081 Matchers.
DeclOrStmt.emplace_back(NodeMatch, Action);
1099 Matchers.
TypeLoc.emplace_back(NodeMatch, Action);
1105 Matchers.
CtorInit.emplace_back(NodeMatch, Action);
1111 if (NodeMatch.canConvertTo<
Decl>()) {
1114 }
else if (NodeMatch.canConvertTo<
QualType>()) {
1117 }
else if (NodeMatch.canConvertTo<
Stmt>()) {
1126 }
else if (NodeMatch.canConvertTo<
TypeLoc>()) {
1137 return std::make_unique<internal::MatchASTConsumer>(
this, ParsingDone);
1142 internal::MatchASTVisitor Visitor(&Matchers, Options);
1143 Visitor.set_active_ast_context(&Context);
1144 Visitor.match(Node);
1148 internal::MatchASTVisitor Visitor(&Matchers, Options);
1149 Visitor.set_active_ast_context(&Context);
1150 Visitor.onStartOfTranslationUnit();
1151 Visitor.TraverseAST(Context);
1152 Visitor.onEndOfTranslationUnit();
1157 ParsingDone = NewParsingDone;
Defines the clang::ASTContext interface.
A (possibly-)qualified type.
internal::Matcher< NestedNameSpecifier > NestedNameSpecifierMatcher
Stmt - This represents one statement.
internal::Matcher< Stmt > StatementMatcher
Decl - This represents one declaration (or definition), e.g.
MatchFinder::MatchResult MatchResult
llvm::SmallPtrSet< MatchCallback *, 16 > AllCallbacks
All the callbacks in one container to simplify iteration.
Called when parsing is finished. Intended for testing only.
MatchFinder(MatchFinderOptions Options=MatchFinderOptions())
internal::Matcher< QualType > TypeMatcher
BoundNodesTreeBuilder Nodes
bool TraverseDecl(Decl *D)
Recursively visit a declaration, by dispatching to Traverse*Decl() based on the argument's dynamic ty...
Base wrapper for a particular "section" of type source info.
virtual ~ParsingDoneTestCallback()
void match(const T &Node, ASTContext &Context)
Calls the registered callbacks on all matches on the given Node.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
A C++ nested-name-specifier augmented with source location information.
Will traverse all child nodes.
void addMatcher(const DeclarationMatcher &NodeMatch, MatchCallback *Action)
Adds a matcher to execute when running over the AST.
std::vector< std::pair< CXXCtorInitializerMatcher, MatchCallback * > > CtorInit
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
DynTypedMatcher::MatcherIDType MatcherID
ast_type_traits::TraversalKind Traversal
bool TraverseConstructorInitializer(CXXCtorInitializer *Init)
Recursively visit a constructor initializer.
Will not traverse implicit casts and parentheses.
Ignore AST nodes not written in the source.
void registerTestCallbackAfterParsing(ParsingDoneTestCallback *ParsingDone)
Registers a callback to notify the end of parsing.
MatchResult(const BoundNodes &Nodes, clang::ASTContext *Context)
std::unique_ptr< clang::ASTConsumer > newASTConsumer()
Creates a clang ASTConsumer that finds all matches.
Maps string IDs to AST nodes matched by parts of a matcher.
virtual StringRef getID() const
An id used to group the matchers.
bool TraverseTypeLoc(TypeLoc TL)
Recursively visit a type with location, by dispatching to Traverse*TypeLoc() based on the argument ty...
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS)
Recursively visit a C++ nested-name-specifier with location information.
Represents a C++ nested name specifier, such as "\::std::vector<int>::".
void matchAST(ASTContext &Context)
Finds all matches in the given AST.
std::vector< std::pair< NestedNameSpecifierLocMatcher, MatchCallback * > > NestedNameSpecifierLoc
bool TraverseStmt(Stmt *S, DataRecursionQueue *Queue=nullptr)
Recursively visit a statement or expression, by dispatching to Traverse*() based on the argument's dy...
std::vector< std::pair< internal::DynTypedMatcher, MatchCallback * > > DeclOrStmt
bool operator<(DeclarationName LHS, DeclarationName RHS)
Ordering on two declaration names.
bool TraverseType(QualType T)
Recursively visit a type, by dispatching to Traverse*Type() based on the argument's getTypeClass() pr...
static DynTypedNode create(const T &Node)
Creates a DynTypedNode from Node.
std::vector< std::pair< NestedNameSpecifierMatcher, MatchCallback * > > NestedNameSpecifier
std::vector< std::pair< TypeMatcher, MatchCallback * > > Type
BoundNodesTreeBuilder BoundNodes
ast_type_traits::DynTypedNode DynTypedNode
ast_type_traits::DynTypedNode Node
Optional< types::ID > Type
Dataflow Directional Tag Classes.
internal::Matcher< CXXCtorInitializer > CXXCtorInitializerMatcher
A dynamically typed AST node container.
std::vector< std::pair< TypeLocMatcher, MatchCallback * > > TypeLoc
Represents a C++ base or member initializer.
TraversalKind
Defines how we descend a level in the AST when we pass through expressions.
bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS)
Recursively visit a C++ nested-name-specifier.
internal::Matcher< T > traverse(ast_type_traits::TraversalKind TK, const internal::Matcher< T > &InnerMatcher)
Causes all nested matchers to be matched with the specified traversal kind.
internal::Matcher< NestedNameSpecifierLoc > NestedNameSpecifierLocMatcher
internal::Matcher< TypeLoc > TypeLocMatcher
Called when the Match registered for it was successfully found in the AST.
This class handles loading and caching of source files into memory.
internal::Matcher< Decl > DeclarationMatcher
Types of matchers for the top-level classes in the AST class hierarchy.
bool addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch, MatchCallback *Action)
Adds a matcher to execute when running over the AST.