24#include "llvm/ADT/DenseMap.h"
25#include "llvm/ADT/SmallPtrSet.h"
26#include "llvm/ADT/StringMap.h"
27#include "llvm/Support/PrettyStackTrace.h"
28#include "llvm/Support/Timer.h"
38typedef MatchFinder::MatchCallback MatchCallback;
48static const unsigned MaxMemoizationEntries = 10000;
70 DynTypedMatcher::MatcherIDType MatcherID;
72 BoundNodesTreeBuilder BoundNodes;
77 return std::tie(Traversal, Type, MatcherID, Node, BoundNodes) <
84struct MemoizedMatchResult {
86 BoundNodesTreeBuilder Nodes;
91class MatchChildASTVisitor
92 :
public RecursiveASTVisitor<MatchChildASTVisitor> {
94 typedef RecursiveASTVisitor<MatchChildASTVisitor> VisitorBase;
100 MatchChildASTVisitor(
const DynTypedMatcher *Matcher, ASTMatchFinder *Finder,
101 BoundNodesTreeBuilder *Builder,
int MaxDepth,
102 bool IgnoreImplicitChildren,
103 ASTMatchFinder::BindKind Bind)
104 : Matcher(Matcher), Finder(Finder), Builder(Builder), CurrentDepth(0),
105 MaxDepth(MaxDepth), IgnoreImplicitChildren(IgnoreImplicitChildren),
106 Bind(Bind), Matches(
false) {}
119 bool findMatch(
const DynTypedNode &DynNode) {
121 if (
const Decl *D = DynNode.get<Decl>())
123 else if (
const Stmt *S = DynNode.get<Stmt>())
125 else if (
const NestedNameSpecifier *NNS =
126 DynNode.get<NestedNameSpecifier>())
128 else if (
const NestedNameSpecifierLoc *NNSLoc =
129 DynNode.get<NestedNameSpecifierLoc>())
131 else if (
const QualType *Q = DynNode.get<QualType>())
133 else if (
const TypeLoc *T = DynNode.get<TypeLoc>())
135 else if (
const auto *
C = DynNode.get<CXXCtorInitializer>())
137 else if (
const TemplateArgumentLoc *TALoc =
138 DynNode.get<TemplateArgumentLoc>())
140 else if (
const Attr *A = DynNode.get<Attr>())
147 *Builder = ResultBindings;
155 bool TraverseDecl(Decl *DeclNode) {
157 if (DeclNode && DeclNode->isImplicit() &&
158 Finder->isTraversalIgnoringImplicitNodes())
159 return baseTraverse(*DeclNode);
161 ScopedIncrement ScopedDepth(&CurrentDepth);
162 return (DeclNode ==
nullptr) ||
traverse(*DeclNode);
165 Stmt *getStmtToTraverse(Stmt *StmtNode) {
166 Stmt *StmtToTraverse = StmtNode;
167 if (
auto *ExprNode = dyn_cast_or_null<Expr>(StmtNode)) {
168 auto *LambdaNode = dyn_cast_or_null<LambdaExpr>(StmtNode);
169 if (LambdaNode && Finder->isTraversalIgnoringImplicitNodes())
170 StmtToTraverse = LambdaNode;
173 Finder->getASTContext().getParentMapContext().traverseIgnored(
176 return StmtToTraverse;
179 bool TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue =
nullptr) {
181 if (CurrentDepth == 0 || (CurrentDepth <= MaxDepth && MaxDepth <
INT_MAX))
184 ScopedIncrement ScopedDepth(&CurrentDepth);
185 Stmt *StmtToTraverse = getStmtToTraverse(StmtNode);
192 if (!
match(*StmtToTraverse))
198 bool TraverseType(QualType TypeNode,
bool TraverseQualifier =
true) {
199 if (TypeNode.isNull())
201 ScopedIncrement ScopedDepth(&CurrentDepth);
203 if (!
match(*TypeNode))
206 return traverse(TypeNode, TraverseQualifier);
210 bool TraverseTypeLoc(TypeLoc TypeLocNode,
bool TraverseQualifier =
true) {
211 if (TypeLocNode.isNull())
213 ScopedIncrement ScopedDepth(&CurrentDepth);
215 if (!
match(*TypeLocNode.getType()))
218 if (!
match(TypeLocNode.getType()))
221 return traverse(TypeLocNode, TraverseQualifier);
223 bool TraverseNestedNameSpecifier(NestedNameSpecifier NNS) {
224 ScopedIncrement ScopedDepth(&CurrentDepth);
230 ScopedIncrement ScopedDepth(&CurrentDepth);
231 if (!
match(NNS.getNestedNameSpecifier()))
235 bool TraverseConstructorInitializer(CXXCtorInitializer *CtorInit) {
238 ScopedIncrement ScopedDepth(&CurrentDepth);
241 bool TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL) {
242 ScopedIncrement ScopedDepth(&CurrentDepth);
245 bool TraverseCXXForRangeStmt(CXXForRangeStmt *Node) {
246 if (!Finder->isTraversalIgnoringImplicitNodes())
247 return VisitorBase::TraverseCXXForRangeStmt(Node);
250 ScopedIncrement ScopedDepth(&CurrentDepth);
251 if (
auto *
Init = Node->getInit())
254 if (!
match(*Node->getLoopVariable()))
256 if (
match(*Node->getRangeInit()))
259 if (!
match(*Node->getBody()))
263 bool TraverseCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *Node) {
264 if (!Finder->isTraversalIgnoringImplicitNodes())
265 return VisitorBase::TraverseCXXRewrittenBinaryOperator(Node);
268 ScopedIncrement ScopedDepth(&CurrentDepth);
270 return match(*Node->getLHS()) &&
match(*Node->getRHS());
272 bool TraverseAttr(Attr *A) {
275 Finder->getASTContext().getParentMapContext().getTraversalKind() ==
278 ScopedIncrement ScopedDepth(&CurrentDepth);
282 if (!Finder->isTraversalIgnoringImplicitNodes())
283 return VisitorBase::TraverseLambdaExpr(Node);
286 ScopedIncrement ScopedDepth(&CurrentDepth);
288 for (
unsigned I = 0, N = Node->capture_size(); I != N; ++I) {
289 const LambdaCapture *
C = Node->capture_begin() + I;
290 if (!
C->isExplicit())
292 if (Node->isInitCapture(
C) && !
match(*
C->getCapturedVar()))
294 const Expr *CIE = Node->capture_init_begin()[I];
295 if (CIE !=
nullptr && !
match(*CIE))
299 if (
const auto *TPL = Node->getTemplateParameterList()) {
300 for (
const auto *TP : *TPL) {
306 for (
const auto *P : Node->getCallOperator()->parameters()) {
311 if (!
match(*Node->getBody()))
317 bool shouldVisitTemplateInstantiations()
const {
return true; }
318 bool shouldVisitImplicitCode()
const {
return !IgnoreImplicitChildren; }
322 struct ScopedIncrement {
323 explicit ScopedIncrement(
int *Depth) : Depth(Depth) { ++(*Depth); }
324 ~ScopedIncrement() { --(*Depth); }
338 bool baseTraverse(
const Decl &DeclNode) {
341 bool baseTraverse(
const Stmt &StmtNode) {
344 bool baseTraverse(QualType TypeNode,
bool TraverseQualifier) {
347 bool baseTraverse(TypeLoc TypeLocNode,
bool TraverseQualifier) {
350 bool baseTraverse(NestedNameSpecifier NNS) {
353 bool baseTraverse(NestedNameSpecifierLoc NNS) {
356 bool baseTraverse(
const CXXCtorInitializer &CtorInit) {
358 const_cast<CXXCtorInitializer *
>(&CtorInit));
360 bool baseTraverse(TemplateArgumentLoc TAL) {
363 bool baseTraverse(
const Attr &AttrNode) {
372 template <
typename T>
373 bool match(
const T &Node) {
374 if (CurrentDepth == 0 || CurrentDepth > MaxDepth) {
377 if (Bind != ASTMatchFinder::BK_All) {
378 BoundNodesTreeBuilder RecursiveBuilder(*Builder);
380 &RecursiveBuilder)) {
382 ResultBindings.addMatch(RecursiveBuilder);
386 BoundNodesTreeBuilder RecursiveBuilder(*Builder);
388 &RecursiveBuilder)) {
391 ResultBindings.addMatch(RecursiveBuilder);
399 template <
typename T,
class... Args>
400 bool traverse(
const T &Node, Args &&...args) {
401 static_assert(IsBaseType<T>::value,
402 "traverse can only be instantiated with base type");
405 return baseTraverse(Node, std::forward<Args>(args)...);
408 const DynTypedMatcher *
const Matcher;
409 ASTMatchFinder *
const Finder;
410 BoundNodesTreeBuilder *
const Builder;
411 BoundNodesTreeBuilder ResultBindings;
414 const bool IgnoreImplicitChildren;
415 const ASTMatchFinder::BindKind Bind;
421class MatchASTVisitor :
public RecursiveASTVisitor<MatchASTVisitor>,
422 public ASTMatchFinder {
424 MatchASTVisitor(
const MatchFinder::MatchersByType *Matchers,
425 const MatchFinder::MatchFinderOptions &Options)
426 : Matchers(Matchers), Options(Options), ActiveASTContext(
nullptr) {}
428 ~MatchASTVisitor()
override {
429 if (Options.CheckProfiling) {
430 Options.CheckProfiling->Records = std::move(TimeByBucket);
434 void onStartOfTranslationUnit() {
435 const bool EnableCheckProfiling = Options.CheckProfiling.has_value();
436 TimeBucketRegion Timer;
437 for (MatchCallback *MC : Matchers->AllCallbacks) {
438 if (EnableCheckProfiling)
439 Timer.setBucket(&TimeByBucket[MC->getID()]);
440 MC->onStartOfTranslationUnit();
444 void onEndOfTranslationUnit() {
445 const bool EnableCheckProfiling = Options.CheckProfiling.has_value();
446 TimeBucketRegion Timer;
447 for (MatchCallback *MC : Matchers->AllCallbacks) {
448 if (EnableCheckProfiling)
449 Timer.setBucket(&TimeByBucket[MC->getID()]);
450 MC->onEndOfTranslationUnit();
454 void set_active_ast_context(ASTContext *NewActiveASTContext) {
455 ActiveASTContext = NewActiveASTContext;
461 bool VisitTypedefNameDecl(TypedefNameDecl *DeclNode) {
489 const Type *TypeNode = DeclNode->getUnderlyingType().getTypePtr();
490 const Type *CanonicalType =
492 TypeAliases[CanonicalType].insert(DeclNode);
496 bool VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) {
497 const ObjCInterfaceDecl *InterfaceDecl = CAD->getClassInterface();
498 CompatibleAliases[InterfaceDecl].insert(CAD);
502 bool TraverseDecl(Decl *DeclNode);
503 bool TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue =
nullptr);
504 bool TraverseType(QualType TypeNode,
bool TraverseQualifier =
true);
505 bool TraverseTypeLoc(TypeLoc TypeNode,
bool TraverseQualifier =
true);
506 bool TraverseNestedNameSpecifier(NestedNameSpecifier NNS);
508 bool TraverseConstructorInitializer(CXXCtorInitializer *CtorInit);
509 bool TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL);
510 bool TraverseAttr(Attr *AttrNode);
512 bool dataTraverseNode(Stmt *S, DataRecursionQueue *Queue) {
513 if (
auto *RF = dyn_cast<CXXForRangeStmt>(S)) {
515 ASTNodeNotAsIsSourceScope RAII(
this,
true);
516 TraverseStmt(RF->getInit());
518 match(*RF->getLoopVariable());
519 TraverseStmt(RF->getRangeInit());
522 ASTNodeNotSpelledInSourceScope RAII(
this,
true);
523 for (
auto *SubStmt : RF->children()) {
524 if (SubStmt != RF->getBody())
525 TraverseStmt(SubStmt);
528 TraverseStmt(RF->getBody());
530 }
else if (
auto *RBO = dyn_cast<CXXRewrittenBinaryOperator>(S)) {
532 ASTNodeNotAsIsSourceScope RAII(
this,
true);
533 TraverseStmt(
const_cast<Expr *
>(RBO->getLHS()));
534 TraverseStmt(
const_cast<Expr *
>(RBO->getRHS()));
537 ASTNodeNotSpelledInSourceScope RAII(
this,
true);
538 for (
auto *SubStmt : RBO->children()) {
539 TraverseStmt(SubStmt);
543 }
else if (
auto *LE = dyn_cast<LambdaExpr>(S)) {
544 for (
auto I : llvm::zip(
LE->captures(),
LE->capture_inits())) {
545 auto C = std::get<0>(I);
546 ASTNodeNotSpelledInSourceScope RAII(
547 this, TraversingASTNodeNotSpelledInSource || !
C.isExplicit());
548 TraverseLambdaCapture(LE, &
C, std::get<1>(I));
552 ASTNodeNotSpelledInSourceScope RAII(
this,
true);
553 TraverseDecl(
LE->getLambdaClass());
556 ASTNodeNotAsIsSourceScope RAII(
this,
true);
560 TypeLoc TL =
LE->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
561 FunctionProtoTypeLoc Proto = TL.getAsAdjusted<FunctionProtoTypeLoc>();
563 if (
auto *TPL =
LE->getTemplateParameterList()) {
564 for (NamedDecl *D : *TPL) {
567 if (Expr *RequiresClause = TPL->getRequiresClause()) {
568 TraverseStmt(RequiresClause);
572 if (
LE->hasExplicitParameters()) {
574 for (ParmVarDecl *Param : Proto.getParams())
578 const auto *T = Proto.getTypePtr();
579 for (
const auto &E : T->exceptions())
580 TraverseType(E,
true);
582 if (Expr *NE = T->getNoexceptExpr())
583 TraverseStmt(NE, Queue);
585 if (
LE->hasExplicitResultType())
586 TraverseTypeLoc(Proto.getReturnLoc(),
true);
588 const_cast<Expr *
>(
LE->getTrailingRequiresClause().ConstraintExpr));
591 TraverseStmt(
LE->getBody());
598 bool memoizedMatchesRecursively(
const DynTypedNode &Node, ASTContext &Ctx,
599 const DynTypedMatcher &Matcher,
600 BoundNodesTreeBuilder *Builder,
int MaxDepth,
603 if (!Node.getMemoizationData() || !Builder->isComparable())
604 return matchesRecursively(Node, Matcher, Builder, MaxDepth,
Bind);
607 Key.MatcherID = Matcher.getID();
610 Key.BoundNodes = *Builder;
613 Key.Type = MaxDepth == 1 ? MatchType::Child : MatchType::Descendants;
614 MemoizationMap::iterator I = ResultCache.find(Key);
615 if (I != ResultCache.end()) {
616 *Builder = I->second.Nodes;
617 return I->second.ResultOfMatch;
620 MemoizedMatchResult
Result;
623 matchesRecursively(Node, Matcher, &
Result.Nodes, MaxDepth,
Bind);
625 MemoizedMatchResult &CachedResult = ResultCache[Key];
626 CachedResult = std::move(
Result);
628 *Builder = CachedResult.Nodes;
629 return CachedResult.ResultOfMatch;
633 bool matchesRecursively(
const DynTypedNode &Node,
634 const DynTypedMatcher &Matcher,
635 BoundNodesTreeBuilder *Builder,
int MaxDepth,
637 bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
638 TraversingASTChildrenNotSpelledInSource;
640 bool IgnoreImplicitChildren =
false;
642 if (isTraversalIgnoringImplicitNodes()) {
643 IgnoreImplicitChildren =
true;
646 ASTNodeNotSpelledInSourceScope RAII(
this, ScopedTraversal);
648 MatchChildASTVisitor Visitor(&Matcher,
this, Builder, MaxDepth,
649 IgnoreImplicitChildren,
Bind);
650 return Visitor.findMatch(Node);
653 bool classIsDerivedFrom(
const CXXRecordDecl *
Declaration,
654 const Matcher<NamedDecl> &Base,
655 BoundNodesTreeBuilder *Builder,
656 bool Directly)
override;
660 classIsDerivedFromImpl(
const CXXRecordDecl *
Declaration,
661 const Matcher<NamedDecl> &Base,
662 BoundNodesTreeBuilder *Builder,
bool Directly,
663 llvm::SmallPtrSetImpl<const CXXRecordDecl *> &Visited);
666 bool objcClassIsDerivedFrom(
const ObjCInterfaceDecl *
Declaration,
667 const Matcher<NamedDecl> &Base,
668 BoundNodesTreeBuilder *Builder,
669 bool Directly)
override;
673 bool matchesChildOf(
const DynTypedNode &Node, ASTContext &Ctx,
674 const DynTypedMatcher &Matcher,
675 BoundNodesTreeBuilder *Builder, BindKind
Bind)
override {
676 if (ResultCache.size() > MaxMemoizationEntries)
678 return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder, 1,
Bind);
681 bool matchesDescendantOf(
const DynTypedNode &Node, ASTContext &Ctx,
682 const DynTypedMatcher &Matcher,
683 BoundNodesTreeBuilder *Builder,
684 BindKind
Bind)
override {
685 if (ResultCache.size() > MaxMemoizationEntries)
687 return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder,
INT_MAX,
691 bool matchesAncestorOf(
const DynTypedNode &Node, ASTContext &Ctx,
692 const DynTypedMatcher &Matcher,
693 BoundNodesTreeBuilder *Builder,
694 AncestorMatchMode MatchMode)
override {
697 if (ResultCache.size() > MaxMemoizationEntries)
699 if (MatchMode == AncestorMatchMode::AMM_ParentOnly)
700 return matchesParentOf(Node, Matcher, Builder);
701 return matchesAnyAncestorOf(Node, Ctx, Matcher, Builder);
706 void match(
const DynTypedNode &Node) {
708 if (
auto *N = Node.get<Decl>()) {
710 }
else if (
auto *N = Node.get<Stmt>()) {
712 }
else if (
auto *N = Node.get<
Type>()) {
714 }
else if (
auto *N = Node.get<QualType>()) {
716 }
else if (
auto *N = Node.get<NestedNameSpecifier>()) {
718 }
else if (
auto *N = Node.get<NestedNameSpecifierLoc>()) {
720 }
else if (
auto *N = Node.get<TypeLoc>()) {
722 }
else if (
auto *N = Node.get<CXXCtorInitializer>()) {
724 }
else if (
auto *N = Node.get<TemplateArgumentLoc>()) {
726 }
else if (
auto *N = Node.get<Attr>()) {
731 template <
typename T>
void match(
const T &Node) {
732 matchDispatch(&Node);
736 ASTContext &getASTContext()
const override {
return *ActiveASTContext; }
738 bool shouldVisitTemplateInstantiations()
const {
return true; }
739 bool shouldVisitImplicitCode()
const {
return true; }
743 bool shouldVisitLambdaBody()
const {
return false; }
745 bool IsMatchingInASTNodeNotSpelledInSource()
const override {
746 return TraversingASTNodeNotSpelledInSource;
748 bool isMatchingChildrenNotSpelledInSource()
const override {
749 return TraversingASTChildrenNotSpelledInSource;
751 void setMatchingChildrenNotSpelledInSource(
bool Set)
override {
752 TraversingASTChildrenNotSpelledInSource =
Set;
755 bool IsMatchingInASTNodeNotAsIs()
const override {
756 return TraversingASTNodeNotAsIs;
759 bool TraverseTemplateInstantiations(ClassTemplateDecl *D) {
760 ASTNodeNotSpelledInSourceScope RAII(
this,
true);
761 return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
765 bool TraverseTemplateInstantiations(VarTemplateDecl *D) {
766 ASTNodeNotSpelledInSourceScope RAII(
this,
true);
767 return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
771 bool TraverseTemplateInstantiations(FunctionTemplateDecl *D) {
772 ASTNodeNotSpelledInSourceScope RAII(
this,
true);
773 return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
778 bool TraversingASTNodeNotSpelledInSource =
false;
779 bool TraversingASTNodeNotAsIs =
false;
780 bool TraversingASTChildrenNotSpelledInSource =
false;
787 const QualType *, const TypeLoc *, const NestedNameSpecifier *, \
788 const NestedNameSpecifierLoc *
790 const CXXCtorInitializer *, const TemplateArgumentLoc *, const Attr *, \
794 template <typename NodeType> \
796 llvm::is_one_of<const NodeType *, CMD_TYPES_##Index>::value> \
797 SetCallbackAndRawNode(const MatchCallback *CB, const NodeType &N) { \
799 Callback.setPointerAndInt(CB, Index); \
803 template <typename T> \
804 std::enable_if_t<llvm::is_one_of<const T *, CMD_TYPES_##Index>::value, \
807 assertHoldsState(); \
808 return Callback.getInt() == (Index) ? Node##Index.dyn_cast<const T *>() \
813 CurMatchData() : Node0(
nullptr) {}
818 const MatchCallback *getCallback()
const {
return Callback.getPointer(); }
820 void SetBoundNodes(
const BoundNodes &BN) {
825 void clearBoundNodes() {
830 const BoundNodes *getBoundNodes()
const {
837 Callback.setPointerAndInt(
nullptr, 0);
842 void assertHoldsState()
const {
843 assert(Callback.getPointer() !=
nullptr && !Node0.isNull());
846 void assertEmpty()
const {
847 assert(Callback.getPointer() ==
nullptr && Node0.isNull() &&
851 llvm::PointerIntPair<const MatchCallback *, 1> Callback;
853 llvm::PointerUnion<CMD_TYPES_0> Node0;
854 llvm::PointerUnion<CMD_TYPES_1> Node1;
856 const BoundNodes *BNodes =
nullptr;
863 struct CurMatchRAII {
864 template <
typename NodeType>
865 CurMatchRAII(MatchASTVisitor &MV,
const MatchCallback *CB,
868 MV.CurMatchState.SetCallbackAndRawNode(CB, NT);
871 ~CurMatchRAII() { MV.CurMatchState.reset(); }
878 class TraceReporter : llvm::PrettyStackTraceEntry {
879 static void dumpNode(
const ASTContext &Ctx,
const DynTypedNode &Node,
881 if (
const auto *D = Node.get<Decl>()) {
882 OS << D->getDeclKindName() <<
"Decl ";
883 if (
const auto *ND = dyn_cast<NamedDecl>(D)) {
884 ND->printQualifiedName(OS);
889 }
else if (
const auto *S = Node.get<Stmt>()) {
890 OS << S->getStmtClassName() <<
" : ";
892 }
else if (
const auto *T = Node.get<
Type>()) {
893 OS << T->getTypeClassName() <<
"Type : ";
895 }
else if (
const auto *QT = Node.get<QualType>()) {
899 OS << Node.getNodeKind().asStringRef() <<
" : ";
904 static void dumpNodeFromState(
const ASTContext &Ctx,
905 const CurMatchData &State, raw_ostream &OS) {
906 if (
const DynTypedNode *MatchNode = State.getNode<DynTypedNode>()) {
907 dumpNode(Ctx, *MatchNode, OS);
908 }
else if (
const auto *QT = State.getNode<QualType>()) {
910 }
else if (
const auto *TL = State.getNode<TypeLoc>()) {
912 }
else if (
const auto *NNS = State.getNode<NestedNameSpecifier>()) {
914 }
else if (
const auto *NNSL = State.getNode<NestedNameSpecifierLoc>()) {
916 }
else if (
const auto *CtorInit = State.getNode<CXXCtorInitializer>()) {
918 }
else if (
const auto *TAL = State.getNode<TemplateArgumentLoc>()) {
920 }
else if (
const auto *At = State.getNode<Attr>()) {
926 TraceReporter(
const MatchASTVisitor &MV) : MV(MV) {}
927 void print(raw_ostream &OS)
const override {
928 const CurMatchData &State = MV.CurMatchState;
929 const MatchCallback *CB = State.getCallback();
931 OS <<
"ASTMatcher: Not currently matching\n";
935 assert(MV.ActiveASTContext &&
936 "ActiveASTContext should be set if there is a matched callback");
938 ASTContext &Ctx = MV.getASTContext();
940 if (
const BoundNodes *Nodes = State.getBoundNodes()) {
941 OS <<
"ASTMatcher: Processing '" << CB->getID() <<
"' against:\n\t";
942 dumpNodeFromState(Ctx, State, OS);
945 OS <<
"\nNo bound nodes\n";
948 OS <<
"\n--- Bound Nodes Begin ---\n";
949 for (
const auto &Item : Map) {
950 OS <<
" " << Item.first <<
" - { ";
951 dumpNode(Ctx, Item.second, OS);
954 OS <<
"--- Bound Nodes End ---\n";
956 OS <<
"ASTMatcher: Matching '" << CB->getID() <<
"' against:\n\t";
957 dumpNodeFromState(Ctx, State, OS);
963 const MatchASTVisitor &MV;
967 struct ASTNodeNotSpelledInSourceScope {
968 ASTNodeNotSpelledInSourceScope(MatchASTVisitor *
V,
bool B)
969 : MV(
V), MB(
V->TraversingASTNodeNotSpelledInSource) {
970 V->TraversingASTNodeNotSpelledInSource = B;
972 ~ASTNodeNotSpelledInSourceScope() {
973 MV->TraversingASTNodeNotSpelledInSource = MB;
981 struct ASTNodeNotAsIsSourceScope {
982 ASTNodeNotAsIsSourceScope(MatchASTVisitor *
V,
bool B)
983 : MV(
V), MB(
V->TraversingASTNodeNotAsIs) {
984 V->TraversingASTNodeNotAsIs = B;
986 ~ASTNodeNotAsIsSourceScope() { MV->TraversingASTNodeNotAsIs = MB; }
993 class TimeBucketRegion {
995 TimeBucketRegion() =
default;
996 ~TimeBucketRegion() { setBucket(
nullptr); }
1006 void setBucket(llvm::TimeRecord *NewBucket) {
1007 if (Bucket != NewBucket) {
1008 auto Now = llvm::TimeRecord::getCurrentTime(
true);
1018 llvm::TimeRecord *Bucket =
nullptr;
1024 template <
typename T,
typename MC>
1025 void matchWithoutFilter(
const T &Node,
const MC &Matchers) {
1026 const bool EnableCheckProfiling = Options.CheckProfiling.has_value();
1027 TimeBucketRegion Timer;
1028 for (
const auto &MP : Matchers) {
1029 if (EnableCheckProfiling)
1030 Timer.setBucket(&TimeByBucket[MP.second->getID()]);
1031 BoundNodesTreeBuilder Builder;
1032 CurMatchRAII RAII(*
this, MP.second, Node);
1033 if (MP.first.matches(Node,
this, &Builder)) {
1034 MatchVisitor Visitor(*
this, ActiveASTContext, MP.second);
1035 Builder.visitMatches(&Visitor);
1040 void matchWithFilter(
const DynTypedNode &DynNode) {
1041 auto Kind = DynNode.getNodeKind();
1042 auto it = MatcherFiltersMap.find(Kind);
1044 it != MatcherFiltersMap.end() ? it->second : getFilterForKind(Kind);
1049 const bool EnableCheckProfiling = Options.CheckProfiling.has_value();
1050 TimeBucketRegion Timer;
1051 auto &Matchers = this->Matchers->DeclOrStmt;
1052 for (
unsigned short I : Filter) {
1053 auto &MP = Matchers[I];
1054 if (EnableCheckProfiling)
1055 Timer.setBucket(&TimeByBucket[MP.second->getID()]);
1056 BoundNodesTreeBuilder Builder;
1059 TraversalKindScope RAII(getASTContext(), MP.first.getTraversalKind());
1060 if (getASTContext().getParentMapContext().traverseIgnored(DynNode) !=
1065 CurMatchRAII RAII(*
this, MP.second, DynNode);
1066 if (MP.first.matches(DynNode,
this, &Builder)) {
1067 MatchVisitor Visitor(*
this, ActiveASTContext, MP.second);
1068 Builder.visitMatches(&Visitor);
1073 const std::vector<unsigned short> &getFilterForKind(ASTNodeKind Kind) {
1075 auto &Matchers = this->Matchers->DeclOrStmt;
1076 assert((Matchers.size() <
USHRT_MAX) &&
"Too many matchers.");
1077 for (
unsigned I = 0, E = Matchers.size(); I != E; ++I) {
1078 if (Matchers[I].first.canMatchNodesOfKind(Kind)) {
1087 void matchDispatch(
const Decl *Node) {
1090 void matchDispatch(
const Stmt *Node) {
1094 void matchDispatch(
const Type *Node) {
1095 matchWithoutFilter(QualType(Node, 0), Matchers->Type);
1097 void matchDispatch(
const TypeLoc *Node) {
1098 matchWithoutFilter(*Node, Matchers->TypeLoc);
1100 void matchDispatch(
const QualType *Node) {
1101 matchWithoutFilter(*Node, Matchers->Type);
1103 void matchDispatch(
const NestedNameSpecifier *Node) {
1104 matchWithoutFilter(*Node, Matchers->NestedNameSpecifier);
1106 void matchDispatch(
const NestedNameSpecifierLoc *Node) {
1107 matchWithoutFilter(*Node, Matchers->NestedNameSpecifierLoc);
1109 void matchDispatch(
const CXXCtorInitializer *Node) {
1110 matchWithoutFilter(*Node, Matchers->CtorInit);
1112 void matchDispatch(
const TemplateArgumentLoc *Node) {
1113 matchWithoutFilter(*Node, Matchers->TemplateArgumentLoc);
1115 void matchDispatch(
const Attr *Node) {
1116 matchWithoutFilter(*Node, Matchers->Attr);
1118 void matchDispatch(
const void *) { }
1123 bool matchesParentOf(
const DynTypedNode &Node,
const DynTypedMatcher &Matcher,
1124 BoundNodesTreeBuilder *Builder) {
1125 for (
const auto &Parent : ActiveASTContext->getParents(Node)) {
1126 BoundNodesTreeBuilder BuilderCopy = *Builder;
1127 if (Matcher.matches(Parent,
this, &BuilderCopy)) {
1128 *Builder = std::move(BuilderCopy);
1151 bool matchesAnyAncestorOf(DynTypedNode Node, ASTContext &Ctx,
1152 const DynTypedMatcher &Matcher,
1153 BoundNodesTreeBuilder *Builder) {
1158 std::vector<MatchKey> Keys;
1160 auto Finish = [&](
bool Matched) {
1161 for (
const auto &Key : Keys) {
1162 MemoizedMatchResult &CachedResult = ResultCache[Key];
1163 CachedResult.ResultOfMatch = Matched;
1164 CachedResult.Nodes = *Builder;
1170 DynTypedNodeList Parents{ArrayRef<DynTypedNode>()};
1173 if (Builder->isComparable()) {
1174 Keys.emplace_back();
1175 Keys.back().MatcherID = Matcher.getID();
1176 Keys.back().Node = Node;
1177 Keys.back().BoundNodes = *Builder;
1179 Keys.back().Type = MatchType::Ancestors;
1182 MemoizationMap::iterator I = ResultCache.find(Keys.back());
1183 if (I != ResultCache.end()) {
1185 *Builder = I->second.Nodes;
1186 return Finish(I->second.ResultOfMatch);
1190 Parents = ActiveASTContext->getParents(Node);
1193 if (Parents.size() != 1)
1197 Node = *Parents.begin();
1198 BoundNodesTreeBuilder BuilderCopy = *Builder;
1199 if (Matcher.matches(Node,
this, &BuilderCopy)) {
1200 *Builder = std::move(BuilderCopy);
1201 return Finish(
true);
1206 if (Parents.empty()) {
1214 if (!Node.get<TranslationUnitDecl>() &&
1216 llvm::any_of(ActiveASTContext->getTraversalScope(), [](Decl *D) {
1217 return D->getKind() == Decl::TranslationUnit;
1219 llvm::errs() <<
"Tried to match orphan node:\n";
1220 Node.dump(llvm::errs(), *ActiveASTContext);
1221 llvm_unreachable(
"Parent map should be complete!");
1225 assert(Parents.size() > 1);
1229 std::deque<DynTypedNode> Queue(Parents.begin(), Parents.end());
1230 llvm::DenseSet<const void *> Visited;
1231 while (!Queue.empty()) {
1232 BoundNodesTreeBuilder BuilderCopy = *Builder;
1233 if (Matcher.matches(Queue.front(),
this, &BuilderCopy)) {
1234 *Builder = std::move(BuilderCopy);
1235 return Finish(
true);
1237 for (
const auto &Parent : ActiveASTContext->getParents(Queue.front())) {
1241 if (Visited.insert(Parent.getMemoizationData()).second)
1242 Queue.push_back(Parent);
1247 return Finish(
false);
1252 class MatchVisitor :
public BoundNodesTreeBuilder::Visitor {
1253 struct CurBoundScope {
1254 CurBoundScope(MatchASTVisitor::CurMatchData &State,
const BoundNodes &BN)
1256 State.SetBoundNodes(BN);
1259 ~CurBoundScope() { State.clearBoundNodes(); }
1262 MatchASTVisitor::CurMatchData &State;
1266 MatchVisitor(MatchASTVisitor &MV, ASTContext *Context,
1267 MatchFinder::MatchCallback *Callback)
1268 : State(MV.CurMatchState), Context(Context), Callback(Callback) {}
1270 void visitMatch(
const BoundNodes& BoundNodesView)
override {
1271 TraversalKindScope RAII(*Context, Callback->getCheckTraversalKind());
1272 CurBoundScope RAII2(State, BoundNodesView);
1273 Callback->run(MatchFinder::MatchResult(BoundNodesView, Context));
1277 MatchASTVisitor::CurMatchData &State;
1278 ASTContext* Context;
1279 MatchFinder::MatchCallback* Callback;
1283 bool typeHasMatchingAlias(
const Type *TypeNode,
1284 const Matcher<NamedDecl> &Matcher,
1285 BoundNodesTreeBuilder *Builder) {
1286 const Type *
const CanonicalType =
1287 ActiveASTContext->getCanonicalType(TypeNode);
1288 auto Aliases = TypeAliases.find(CanonicalType);
1289 if (Aliases == TypeAliases.end())
1292 auto matches = [&](
const TypedefNameDecl *Alias) {
1293 BoundNodesTreeBuilder
Result(*Builder);
1294 if (Matcher.matches(*Alias,
this, &
Result)) {
1295 *Builder = std::move(
Result);
1301 if (
const auto *T = TypeNode->getAs<TypedefType>()) {
1302 const auto *TD = T->getDecl()->getCanonicalDecl();
1305 SmallVector<const TypedefNameDecl *, 8> NonExactMatches;
1306 for (
const TypedefNameDecl *Alias : Aliases->second) {
1308 NonExactMatches.push_back(Alias);
1315 for (
const TypedefNameDecl *Alias : NonExactMatches) {
1316 BoundNodesTreeBuilder
Result(*Builder);
1317 if (Matcher.matches(*Alias,
this, &
Result)) {
1318 *Builder = std::move(
Result);
1325 for (
const TypedefNameDecl *Alias : Aliases->second)
1332 objcClassHasMatchingCompatibilityAlias(
const ObjCInterfaceDecl *InterfaceDecl,
1333 const Matcher<NamedDecl> &Matcher,
1334 BoundNodesTreeBuilder *Builder) {
1335 auto Aliases = CompatibleAliases.find(InterfaceDecl);
1336 if (Aliases == CompatibleAliases.end())
1338 for (
const ObjCCompatibleAliasDecl *Alias : Aliases->second) {
1339 BoundNodesTreeBuilder
Result(*Builder);
1340 if (Matcher.matches(*Alias,
this, &
Result)) {
1341 *Builder = std::move(
Result);
1348 template <
typename T>
static SourceLocation getNodeLocation(
const T &Node) {
1349 return Node.getBeginLoc();
1352 static SourceLocation getNodeLocation(
const CXXCtorInitializer &Node) {
1353 return Node.getSourceLocation();
1356 static SourceLocation getNodeLocation(
const TemplateArgumentLoc &Node) {
1357 return Node.getLocation();
1360 static SourceLocation getNodeLocation(
const Attr &Node) {
1361 return Node.getLocation();
1364 bool isInSystemHeader(SourceLocation Loc) {
1365 const SourceManager &
SM = getASTContext().getSourceManager();
1366 return SM.isInSystemHeader(Loc);
1369 template <
typename T>
bool shouldSkipNode(T &Node) {
1370 if (Options.IgnoreSystemHeaders && isInSystemHeader(getNodeLocation(Node)))
1375 template <
typename T>
bool shouldSkipNode(T *Node) {
1376 return (Node ==
nullptr) || shouldSkipNode(*Node);
1379 bool shouldSkipNode(QualType &) {
return false; }
1381 bool shouldSkipNode(NestedNameSpecifier &) {
return false; }
1386 llvm::StringMap<llvm::TimeRecord> TimeByBucket;
1388 const MatchFinder::MatchersByType *Matchers;
1396 llvm::DenseMap<ASTNodeKind, std::vector<unsigned short>> MatcherFiltersMap;
1398 const MatchFinder::MatchFinderOptions &Options;
1399 ASTContext *ActiveASTContext;
1402 llvm::DenseMap<const Type*, std::set<const TypedefNameDecl*> > TypeAliases;
1405 llvm::DenseMap<
const ObjCInterfaceDecl *,
1406 llvm::SmallPtrSet<const ObjCCompatibleAliasDecl *, 2>>
1410 typedef std::map<MatchKey, MemoizedMatchResult> MemoizationMap;
1411 MemoizationMap ResultCache;
1414static CXXRecordDecl *
1415getAsCXXRecordDeclOrPrimaryTemplate(
const Type *TypeNode) {
1416 if (
auto *RD = TypeNode->getAsCXXRecordDecl())
1420 auto *TemplateType = TypeNode->getAs<TemplateSpecializationType>();
1421 while (TemplateType && TemplateType->isTypeAlias())
1423 TemplateType->getAliasedType()->getAs<TemplateSpecializationType>();
1428 if (
auto *ClassTemplate = dyn_cast_or_null<ClassTemplateDecl>(
1429 TemplateType->getTemplateName().getAsTemplateDecl()))
1430 return ClassTemplate->getTemplatedDecl();
1438bool MatchASTVisitor::classIsDerivedFrom(
const CXXRecordDecl *
Declaration,
1439 const Matcher<NamedDecl> &Base,
1440 BoundNodesTreeBuilder *Builder,
1442 llvm::SmallPtrSet<const CXXRecordDecl *, 8> Visited;
1443 return classIsDerivedFromImpl(Declaration, Base, Builder, Directly, Visited);
1446bool MatchASTVisitor::classIsDerivedFromImpl(
1447 const CXXRecordDecl *
Declaration,
const Matcher<NamedDecl> &Base,
1448 BoundNodesTreeBuilder *Builder,
bool Directly,
1449 llvm::SmallPtrSetImpl<const CXXRecordDecl *> &Visited) {
1452 if (!Visited.insert(Declaration).second)
1455 const Type *TypeNode = It.getType().getTypePtr();
1457 if (typeHasMatchingAlias(TypeNode, Base, Builder))
1463 CXXRecordDecl *ClassDecl = getAsCXXRecordDeclOrPrimaryTemplate(TypeNode);
1466 if (ClassDecl == Declaration) {
1470 BoundNodesTreeBuilder
Result(*Builder);
1471 if (
Base.matches(*ClassDecl,
this, &Result)) {
1472 *Builder = std::move(Result);
1476 classIsDerivedFromImpl(ClassDecl, Base, Builder, Directly, Visited))
1485bool MatchASTVisitor::objcClassIsDerivedFrom(
1486 const ObjCInterfaceDecl *
Declaration,
const Matcher<NamedDecl> &Base,
1487 BoundNodesTreeBuilder *Builder,
bool Directly) {
1489 for (
const ObjCInterfaceDecl *ClassDecl =
Declaration->getSuperClass();
1490 ClassDecl !=
nullptr; ClassDecl = ClassDecl->getSuperClass()) {
1492 if (objcClassHasMatchingCompatibilityAlias(ClassDecl, Base, Builder))
1496 const Type *TypeNode = ClassDecl->getTypeForDecl();
1497 if (typeHasMatchingAlias(TypeNode, Base, Builder))
1500 if (
Base.matches(*ClassDecl,
this, Builder))
1511bool MatchASTVisitor::TraverseDecl(Decl *DeclNode) {
1512 if (shouldSkipNode(DeclNode))
1518 bool ScopedTraversal =
1519 TraversingASTNodeNotSpelledInSource || DeclNode->isImplicit();
1520 bool ScopedChildren = TraversingASTChildrenNotSpelledInSource;
1522 if (
const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(DeclNode)) {
1523 auto SK = CTSD->getSpecializationKind();
1524 if (SK == TSK_ExplicitInstantiationDeclaration ||
1525 SK == TSK_ExplicitInstantiationDefinition)
1526 ScopedChildren =
true;
1527 }
else if (
const auto *FD = dyn_cast<FunctionDecl>(DeclNode)) {
1528 if (FD->isDefaulted())
1529 ScopedChildren =
true;
1530 if (FD->isTemplateInstantiation())
1531 ScopedTraversal =
true;
1532 }
else if (isa<BindingDecl>(DeclNode)) {
1533 ScopedChildren =
true;
1536 ASTNodeNotSpelledInSourceScope RAII1(
this, ScopedTraversal);
1537 ASTChildrenNotSpelledInSourceScope RAII2(
this, ScopedChildren);
1540 return RecursiveASTVisitor<MatchASTVisitor>::TraverseDecl(DeclNode);
1543bool MatchASTVisitor::TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue) {
1544 if (shouldSkipNode(StmtNode))
1547 bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
1548 TraversingASTChildrenNotSpelledInSource;
1550 ASTNodeNotSpelledInSourceScope RAII(
this, ScopedTraversal);
1552 return RecursiveASTVisitor<MatchASTVisitor>::TraverseStmt(StmtNode, Queue);
1555bool MatchASTVisitor::TraverseType(QualType TypeNode,
bool TraverseQualifier) {
1556 if (shouldSkipNode(TypeNode))
1560 return RecursiveASTVisitor<MatchASTVisitor>::TraverseType(TypeNode,
1564bool MatchASTVisitor::TraverseTypeLoc(TypeLoc TypeLocNode,
1565 bool TraverseQualifier) {
1566 if (shouldSkipNode(TypeLocNode))
1574 match(TypeLocNode.getType());
1575 return RecursiveASTVisitor<MatchASTVisitor>::TraverseTypeLoc(
1576 TypeLocNode, TraverseQualifier);
1579bool MatchASTVisitor::TraverseNestedNameSpecifier(NestedNameSpecifier NNS) {
1580 if (shouldSkipNode(NNS))
1584 return RecursiveASTVisitor<MatchASTVisitor>::TraverseNestedNameSpecifier(NNS);
1587bool MatchASTVisitor::TraverseNestedNameSpecifierLoc(
1588 NestedNameSpecifierLoc NNS) {
1592 if (shouldSkipNode(NNS))
1599 if (NNS.hasQualifier())
1600 match(NNS.getNestedNameSpecifier());
1602 RecursiveASTVisitor<MatchASTVisitor>::TraverseNestedNameSpecifierLoc(NNS);
1605bool MatchASTVisitor::TraverseConstructorInitializer(
1606 CXXCtorInitializer *CtorInit) {
1607 if (shouldSkipNode(CtorInit))
1610 bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
1611 TraversingASTChildrenNotSpelledInSource;
1613 if (!CtorInit->isWritten())
1614 ScopedTraversal =
true;
1616 ASTNodeNotSpelledInSourceScope RAII1(
this, ScopedTraversal);
1620 return RecursiveASTVisitor<MatchASTVisitor>::TraverseConstructorInitializer(
1624bool MatchASTVisitor::TraverseTemplateArgumentLoc(TemplateArgumentLoc Loc) {
1625 if (shouldSkipNode(Loc))
1629 return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateArgumentLoc(Loc);
1632bool MatchASTVisitor::TraverseAttr(Attr *AttrNode) {
1633 if (shouldSkipNode(AttrNode))
1637 return RecursiveASTVisitor<MatchASTVisitor>::TraverseAttr(AttrNode);
1640class MatchASTConsumer :
public ASTConsumer {
1642 MatchASTConsumer(MatchFinder *Finder,
1643 MatchFinder::ParsingDoneTestCallback *ParsingDone)
1644 : Finder(Finder), ParsingDone(ParsingDone) {}
1647 void HandleTranslationUnit(ASTContext &Context)
override {
1648 if (ParsingDone !=
nullptr) {
1654 MatchFinder *Finder;
1655 MatchFinder::ParsingDoneTestCallback *ParsingDone;
1661template <
typename T>
1662static internal::Matcher<T>
1680 : Options(
std::move(Options)), ParsingDone(
nullptr) {}
1688 Matchers.AllCallbacks.insert(Action);
1694 Matchers.AllCallbacks.insert(Action);
1701 Matchers.AllCallbacks.insert(Action);
1706 Matchers.NestedNameSpecifier.emplace_back(
1708 Matchers.AllCallbacks.insert(Action);
1713 Matchers.NestedNameSpecifierLoc.emplace_back(
1715 Matchers.AllCallbacks.insert(Action);
1721 Matchers.AllCallbacks.insert(Action);
1728 Matchers.AllCallbacks.insert(Action);
1733 Matchers.TemplateArgumentLoc.emplace_back(
1735 Matchers.AllCallbacks.insert(Action);
1741 Matchers.AllCallbacks.insert(Action);
1746 if (NodeMatch.canConvertTo<
Decl>()) {
1749 }
else if (NodeMatch.canConvertTo<
QualType>()) {
1752 }
else if (NodeMatch.canConvertTo<
Stmt>()) {
1761 }
else if (NodeMatch.canConvertTo<
TypeLoc>()) {
1770 }
else if (NodeMatch.canConvertTo<
Attr>()) {
1778 return std::make_unique<internal::MatchASTConsumer>(
this, ParsingDone);
1782 internal::MatchASTVisitor Visitor(&Matchers, Options);
1783 Visitor.set_active_ast_context(&Context);
1784 Visitor.match(Node);
1788 internal::MatchASTVisitor Visitor(&Matchers, Options);
1789 internal::MatchASTVisitor::TraceReporter StackTrace(Visitor);
1790 Visitor.set_active_ast_context(&Context);
1791 Visitor.onStartOfTranslationUnit();
1792 Visitor.TraverseAST(Context);
1793 Visitor.onEndOfTranslationUnit();
1798 ParsingDone = NewParsingDone;
1803std::optional<TraversalKind>
1805 return std::nullopt;
Defines the clang::ASTContext interface.
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)
Defines the clang::Module class, which describes a module in the source code.
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.
A C++ nested-name-specifier augmented with source location information.
Represents a C++ nested name specifier, such as "\::std::vector<int>::".
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.
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.
virtual StringRef getID() const
An id used to group the matchers.
Called when parsing is finished. Intended for testing only.
virtual ~ParsingDoneTestCallback()
MatchFinder(MatchFinderOptions Options=MatchFinderOptions())
bool addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch, MatchCallback *Action)
Adds a matcher to execute when running over the AST.
void addMatcher(const DeclarationMatcher &NodeMatch, MatchCallback *Action)
Adds a matcher to execute when running over the AST.
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.
std::unique_ptr< clang::ASTConsumer > newASTConsumer()
Creates a clang ASTConsumer that finds all matches.
void matchAST(ASTContext &Context)
Finds all matches in the given AST.
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
static internal::Matcher< T > adjustTraversalKind(const internal::Matcher< T > &NodeMatch, MatchFinder::MatchCallback *Action)
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.
@ 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)
const BoundNodes Nodes
Contains the nodes bound on the current match.
clang::ASTContext *const Context
Utilities for interpreting the matched AST structures.