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();
580 TraverseType(E,
true);
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) ? dyn_cast<const T *>(Node##Index) \
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>()) {
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;
1053 const bool IsExpr = DynNode.get<Expr>() !=
nullptr;
1054 for (
unsigned short I : Filter) {
1055 auto &MP = Matchers[I];
1056 if (EnableCheckProfiling)
1057 Timer.setBucket(&TimeByBucket[MP.second->getID()]);
1058 BoundNodesTreeBuilder Builder;
1061 TraversalKindScope RAII(getASTContext(), MP.first.getTraversalKind());
1062 if (getASTContext().getParentMapContext().traverseIgnored(DynNode) !=
1067 CurMatchRAII RAII(*
this, MP.second, DynNode);
1068 if (MP.first.matches(DynNode,
this, &Builder)) {
1069 MatchVisitor Visitor(*
this, ActiveASTContext, MP.second);
1070 Builder.visitMatches(&Visitor);
1075 const std::vector<unsigned short> &getFilterForKind(ASTNodeKind Kind) {
1077 auto &Matchers = this->Matchers->DeclOrStmt;
1078 assert((Matchers.size() <
USHRT_MAX) &&
"Too many matchers.");
1079 for (
unsigned I = 0, E = Matchers.size(); I != E; ++I) {
1080 if (Matchers[I].first.canMatchNodesOfKind(Kind)) {
1089 void matchDispatch(
const Decl *Node) {
1092 void matchDispatch(
const Stmt *Node) {
1096 void matchDispatch(
const Type *Node) {
1097 matchWithoutFilter(QualType(Node, 0), Matchers->Type);
1099 void matchDispatch(
const TypeLoc *Node) {
1100 matchWithoutFilter(*Node, Matchers->TypeLoc);
1102 void matchDispatch(
const QualType *Node) {
1103 matchWithoutFilter(*Node, Matchers->Type);
1105 void matchDispatch(
const NestedNameSpecifier *Node) {
1106 matchWithoutFilter(*Node, Matchers->NestedNameSpecifier);
1108 void matchDispatch(
const NestedNameSpecifierLoc *Node) {
1109 matchWithoutFilter(*Node, Matchers->NestedNameSpecifierLoc);
1111 void matchDispatch(
const CXXCtorInitializer *Node) {
1112 matchWithoutFilter(*Node, Matchers->CtorInit);
1114 void matchDispatch(
const TemplateArgumentLoc *Node) {
1115 matchWithoutFilter(*Node, Matchers->TemplateArgumentLoc);
1117 void matchDispatch(
const Attr *Node) {
1118 matchWithoutFilter(*Node, Matchers->Attr);
1120 void matchDispatch(
const void *) { }
1125 bool matchesParentOf(
const DynTypedNode &Node,
const DynTypedMatcher &Matcher,
1126 BoundNodesTreeBuilder *Builder) {
1127 for (
const auto &Parent : ActiveASTContext->getParents(Node)) {
1128 BoundNodesTreeBuilder BuilderCopy = *Builder;
1129 if (Matcher.matches(Parent,
this, &BuilderCopy)) {
1130 *Builder = std::move(BuilderCopy);
1153 bool matchesAnyAncestorOf(DynTypedNode Node, ASTContext &Ctx,
1154 const DynTypedMatcher &Matcher,
1155 BoundNodesTreeBuilder *Builder) {
1160 std::vector<MatchKey> Keys;
1162 auto Finish = [&](
bool Matched) {
1163 for (
const auto &Key : Keys) {
1164 MemoizedMatchResult &CachedResult = ResultCache[Key];
1165 CachedResult.ResultOfMatch = Matched;
1166 CachedResult.Nodes = *Builder;
1172 DynTypedNodeList Parents{ArrayRef<DynTypedNode>()};
1175 if (Builder->isComparable()) {
1176 Keys.emplace_back();
1177 Keys.back().MatcherID = Matcher.getID();
1178 Keys.back().Node = Node;
1179 Keys.back().BoundNodes = *Builder;
1181 Keys.back().Type = MatchType::Ancestors;
1184 MemoizationMap::iterator I = ResultCache.find(Keys.back());
1185 if (I != ResultCache.end()) {
1187 *Builder = I->second.Nodes;
1188 return Finish(I->second.ResultOfMatch);
1192 Parents = ActiveASTContext->getParents(Node);
1195 if (Parents.size() != 1)
1199 Node = *Parents.begin();
1200 BoundNodesTreeBuilder BuilderCopy = *Builder;
1201 if (Matcher.matches(Node,
this, &BuilderCopy)) {
1202 *Builder = std::move(BuilderCopy);
1203 return Finish(
true);
1208 if (Parents.empty()) {
1216 if (!Node.get<TranslationUnitDecl>() &&
1218 llvm::any_of(ActiveASTContext->getTraversalScope(), [](Decl *D) {
1219 return D->getKind() == Decl::TranslationUnit;
1221 llvm::errs() <<
"Tried to match orphan node:\n";
1222 Node.dump(llvm::errs(), *ActiveASTContext);
1223 llvm_unreachable(
"Parent map should be complete!");
1227 assert(Parents.size() > 1);
1231 std::deque<DynTypedNode> Queue(Parents.begin(), Parents.end());
1232 llvm::DenseSet<const void *> Visited;
1233 while (!Queue.empty()) {
1234 BoundNodesTreeBuilder BuilderCopy = *Builder;
1235 if (Matcher.matches(Queue.front(),
this, &BuilderCopy)) {
1236 *Builder = std::move(BuilderCopy);
1237 return Finish(
true);
1239 for (
const auto &Parent : ActiveASTContext->getParents(Queue.front())) {
1243 if (Visited.insert(Parent.getMemoizationData()).second)
1244 Queue.push_back(Parent);
1249 return Finish(
false);
1254 class MatchVisitor :
public BoundNodesTreeBuilder::Visitor {
1255 struct CurBoundScope {
1256 CurBoundScope(MatchASTVisitor::CurMatchData &State,
const BoundNodes &BN)
1258 State.SetBoundNodes(BN);
1261 ~CurBoundScope() { State.clearBoundNodes(); }
1264 MatchASTVisitor::CurMatchData &State;
1268 MatchVisitor(MatchASTVisitor &MV, ASTContext *Context,
1269 MatchFinder::MatchCallback *Callback)
1270 : State(MV.CurMatchState), Context(Context), Callback(Callback) {}
1272 void visitMatch(
const BoundNodes& BoundNodesView)
override {
1273 TraversalKindScope RAII(*Context, Callback->getCheckTraversalKind());
1274 CurBoundScope RAII2(State, BoundNodesView);
1275 Callback->run(MatchFinder::MatchResult(BoundNodesView, Context));
1279 MatchASTVisitor::CurMatchData &State;
1280 ASTContext* Context;
1281 MatchFinder::MatchCallback* Callback;
1285 bool typeHasMatchingAlias(
const Type *TypeNode,
1286 const Matcher<NamedDecl> &Matcher,
1287 BoundNodesTreeBuilder *Builder) {
1288 const Type *
const CanonicalType =
1289 ActiveASTContext->getCanonicalType(TypeNode);
1290 auto Aliases = TypeAliases.find(CanonicalType);
1291 if (Aliases == TypeAliases.end())
1294 auto matches = [&](
const TypedefNameDecl *Alias) {
1295 BoundNodesTreeBuilder
Result(*Builder);
1296 if (Matcher.matches(*Alias,
this, &
Result)) {
1297 *Builder = std::move(
Result);
1303 if (
const auto *
T = TypeNode->getAs<TypedefType>()) {
1304 const auto *TD =
T->getDecl()->getCanonicalDecl();
1307 SmallVector<const TypedefNameDecl *, 8> NonExactMatches;
1308 for (
const TypedefNameDecl *Alias : Aliases->second) {
1310 NonExactMatches.push_back(Alias);
1317 for (
const TypedefNameDecl *Alias : NonExactMatches) {
1318 BoundNodesTreeBuilder
Result(*Builder);
1319 if (Matcher.matches(*Alias,
this, &
Result)) {
1320 *Builder = std::move(
Result);
1327 for (
const TypedefNameDecl *Alias : Aliases->second)
1334 objcClassHasMatchingCompatibilityAlias(
const ObjCInterfaceDecl *InterfaceDecl,
1335 const Matcher<NamedDecl> &Matcher,
1336 BoundNodesTreeBuilder *Builder) {
1337 auto Aliases = CompatibleAliases.find(InterfaceDecl);
1338 if (Aliases == CompatibleAliases.end())
1340 for (
const ObjCCompatibleAliasDecl *Alias : Aliases->second) {
1341 BoundNodesTreeBuilder
Result(*Builder);
1342 if (Matcher.matches(*Alias,
this, &
Result)) {
1343 *Builder = std::move(
Result);
1350 template <
typename T>
static SourceLocation getNodeLocation(
const T &Node) {
1351 return Node.getBeginLoc();
1354 static SourceLocation getNodeLocation(
const CXXCtorInitializer &Node) {
1355 return Node.getSourceLocation();
1358 static SourceLocation getNodeLocation(
const TemplateArgumentLoc &Node) {
1359 return Node.getLocation();
1362 static SourceLocation getNodeLocation(
const Attr &Node) {
1363 return Node.getLocation();
1366 bool isInSystemHeader(SourceLocation Loc) {
1367 const SourceManager &SM = getASTContext().getSourceManager();
1368 return SM.isInSystemHeader(Loc);
1371 template <
typename T>
bool shouldSkipNode(
T &Node) {
1372 if (Options.IgnoreSystemHeaders && isInSystemHeader(getNodeLocation(Node)))
1377 template <
typename T>
bool shouldSkipNode(
T *Node) {
1378 return (Node ==
nullptr) || shouldSkipNode(*Node);
1381 bool shouldSkipNode(QualType &) {
return false; }
1383 bool shouldSkipNode(NestedNameSpecifier &) {
return false; }
1388 llvm::StringMap<llvm::TimeRecord> TimeByBucket;
1390 const MatchFinder::MatchersByType *Matchers;
1398 llvm::DenseMap<ASTNodeKind, std::vector<unsigned short>> MatcherFiltersMap;
1400 const MatchFinder::MatchFinderOptions &Options;
1401 ASTContext *ActiveASTContext;
1404 llvm::DenseMap<const Type*, std::set<const TypedefNameDecl*> > TypeAliases;
1407 llvm::DenseMap<
const ObjCInterfaceDecl *,
1408 llvm::SmallPtrSet<const ObjCCompatibleAliasDecl *, 2>>
1412 typedef std::map<MatchKey, MemoizedMatchResult> MemoizationMap;
1413 MemoizationMap ResultCache;
1416static CXXRecordDecl *
1417getAsCXXRecordDeclOrPrimaryTemplate(
const Type *TypeNode) {
1418 if (
auto *RD = TypeNode->getAsCXXRecordDecl())
1422 auto *TemplateType = TypeNode->getAs<TemplateSpecializationType>();
1423 while (TemplateType && TemplateType->isTypeAlias())
1425 TemplateType->getAliasedType()->getAs<TemplateSpecializationType>();
1430 if (
auto *ClassTemplate = dyn_cast_or_null<ClassTemplateDecl>(
1431 TemplateType->getTemplateName().getAsTemplateDecl()))
1432 return ClassTemplate->getTemplatedDecl();
1440bool MatchASTVisitor::classIsDerivedFrom(
const CXXRecordDecl *
Declaration,
1441 const Matcher<NamedDecl> &Base,
1442 BoundNodesTreeBuilder *Builder,
1444 llvm::SmallPtrSet<const CXXRecordDecl *, 8> Visited;
1445 return classIsDerivedFromImpl(Declaration, Base, Builder, Directly, Visited);
1448bool MatchASTVisitor::classIsDerivedFromImpl(
1449 const CXXRecordDecl *
Declaration,
const Matcher<NamedDecl> &Base,
1450 BoundNodesTreeBuilder *Builder,
bool Directly,
1451 llvm::SmallPtrSetImpl<const CXXRecordDecl *> &Visited) {
1454 if (!Visited.insert(Declaration).second)
1457 const Type *TypeNode = It.getType().getTypePtr();
1459 if (typeHasMatchingAlias(TypeNode, Base, Builder))
1465 CXXRecordDecl *ClassDecl = getAsCXXRecordDeclOrPrimaryTemplate(TypeNode);
1468 if (ClassDecl == Declaration) {
1472 BoundNodesTreeBuilder
Result(*Builder);
1473 if (
Base.matches(*ClassDecl,
this, &
Result)) {
1474 *Builder = std::move(
Result);
1478 classIsDerivedFromImpl(ClassDecl, Base, Builder, Directly, Visited))
1487bool MatchASTVisitor::objcClassIsDerivedFrom(
1488 const ObjCInterfaceDecl *
Declaration,
const Matcher<NamedDecl> &Base,
1489 BoundNodesTreeBuilder *Builder,
bool Directly) {
1491 for (
const ObjCInterfaceDecl *ClassDecl =
Declaration->getSuperClass();
1492 ClassDecl !=
nullptr; ClassDecl = ClassDecl->getSuperClass()) {
1494 if (objcClassHasMatchingCompatibilityAlias(ClassDecl, Base, Builder))
1498 const Type *TypeNode = ClassDecl->getTypeForDecl();
1499 if (typeHasMatchingAlias(TypeNode, Base, Builder))
1502 if (
Base.matches(*ClassDecl,
this, Builder))
1513bool MatchASTVisitor::TraverseDecl(Decl *DeclNode) {
1514 if (shouldSkipNode(DeclNode))
1520 bool ScopedTraversal =
1521 TraversingASTNodeNotSpelledInSource || DeclNode->isImplicit();
1522 bool ScopedChildren = TraversingASTChildrenNotSpelledInSource;
1524 if (
const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(DeclNode)) {
1525 auto SK = CTSD->getSpecializationKind();
1526 if (SK == TSK_ExplicitInstantiationDeclaration ||
1527 SK == TSK_ExplicitInstantiationDefinition)
1528 ScopedChildren =
true;
1529 }
else if (
const auto *FD = dyn_cast<FunctionDecl>(DeclNode)) {
1530 if (FD->isDefaulted())
1531 ScopedChildren =
true;
1532 if (FD->isTemplateInstantiation())
1533 ScopedTraversal =
true;
1534 }
else if (isa<BindingDecl>(DeclNode)) {
1535 ScopedChildren =
true;
1538 ASTNodeNotSpelledInSourceScope RAII1(
this, ScopedTraversal);
1539 ASTChildrenNotSpelledInSourceScope RAII2(
this, ScopedChildren);
1542 return RecursiveASTVisitor<MatchASTVisitor>::TraverseDecl(DeclNode);
1545bool MatchASTVisitor::TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue) {
1546 if (shouldSkipNode(StmtNode))
1549 bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
1550 TraversingASTChildrenNotSpelledInSource;
1552 ASTNodeNotSpelledInSourceScope RAII(
this, ScopedTraversal);
1554 return RecursiveASTVisitor<MatchASTVisitor>::TraverseStmt(StmtNode, Queue);
1557bool MatchASTVisitor::TraverseType(QualType TypeNode,
bool TraverseQualifier) {
1558 if (shouldSkipNode(TypeNode))
1562 return RecursiveASTVisitor<MatchASTVisitor>::TraverseType(TypeNode,
1566bool MatchASTVisitor::TraverseTypeLoc(TypeLoc TypeLocNode,
1567 bool TraverseQualifier) {
1568 if (shouldSkipNode(TypeLocNode))
1576 match(TypeLocNode.getType());
1577 return RecursiveASTVisitor<MatchASTVisitor>::TraverseTypeLoc(
1578 TypeLocNode, TraverseQualifier);
1581bool MatchASTVisitor::TraverseNestedNameSpecifier(NestedNameSpecifier NNS) {
1582 if (shouldSkipNode(NNS))
1586 return RecursiveASTVisitor<MatchASTVisitor>::TraverseNestedNameSpecifier(NNS);
1589bool MatchASTVisitor::TraverseNestedNameSpecifierLoc(
1590 NestedNameSpecifierLoc NNS) {
1594 if (shouldSkipNode(NNS))
1601 if (NNS.hasQualifier())
1602 match(NNS.getNestedNameSpecifier());
1604 RecursiveASTVisitor<MatchASTVisitor>::TraverseNestedNameSpecifierLoc(NNS);
1607bool MatchASTVisitor::TraverseConstructorInitializer(
1608 CXXCtorInitializer *CtorInit) {
1609 if (shouldSkipNode(CtorInit))
1612 bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
1613 TraversingASTChildrenNotSpelledInSource;
1615 if (!CtorInit->isWritten())
1616 ScopedTraversal =
true;
1618 ASTNodeNotSpelledInSourceScope RAII1(
this, ScopedTraversal);
1622 return RecursiveASTVisitor<MatchASTVisitor>::TraverseConstructorInitializer(
1626bool MatchASTVisitor::TraverseTemplateArgumentLoc(TemplateArgumentLoc Loc) {
1627 if (shouldSkipNode(Loc))
1631 return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateArgumentLoc(Loc);
1634bool MatchASTVisitor::TraverseAttr(Attr *AttrNode) {
1635 if (shouldSkipNode(AttrNode))
1639 return RecursiveASTVisitor<MatchASTVisitor>::TraverseAttr(AttrNode);
1642class MatchASTConsumer :
public ASTConsumer {
1644 MatchASTConsumer(MatchFinder *Finder,
1645 MatchFinder::ParsingDoneTestCallback *ParsingDone)
1646 : Finder(Finder), ParsingDone(ParsingDone) {}
1649 void HandleTranslationUnit(ASTContext &Context)
override {
1650 if (ParsingDone !=
nullptr) {
1656 MatchFinder *Finder;
1657 MatchFinder::ParsingDoneTestCallback *ParsingDone;
1663template <
typename T>
1664static internal::Matcher<T>
1682 : Options(
std::move(Options)), ParsingDone(
nullptr) {}
1690 Matchers.AllCallbacks.insert(Action);
1696 Matchers.AllCallbacks.insert(Action);
1703 Matchers.AllCallbacks.insert(Action);
1708 Matchers.NestedNameSpecifier.emplace_back(
1710 Matchers.AllCallbacks.insert(Action);
1715 Matchers.NestedNameSpecifierLoc.emplace_back(
1717 Matchers.AllCallbacks.insert(Action);
1723 Matchers.AllCallbacks.insert(Action);
1730 Matchers.AllCallbacks.insert(Action);
1735 Matchers.TemplateArgumentLoc.emplace_back(
1737 Matchers.AllCallbacks.insert(Action);
1743 Matchers.AllCallbacks.insert(Action);
1748 if (NodeMatch.canConvertTo<
Decl>()) {
1751 }
else if (NodeMatch.canConvertTo<
QualType>()) {
1754 }
else if (NodeMatch.canConvertTo<
Stmt>()) {
1763 }
else if (NodeMatch.canConvertTo<
TypeLoc>()) {
1772 }
else if (NodeMatch.canConvertTo<
Attr>()) {
1780 return std::make_unique<internal::MatchASTConsumer>(
this, ParsingDone);
1784 internal::MatchASTVisitor Visitor(&Matchers, Options);
1785 Visitor.set_active_ast_context(&Context);
1786 Visitor.match(Node);
1790 internal::MatchASTVisitor Visitor(&Matchers, Options);
1791 internal::MatchASTVisitor::TraceReporter StackTrace(Visitor);
1792 Visitor.set_active_ast_context(&Context);
1793 Visitor.onStartOfTranslationUnit();
1794 Visitor.TraverseAST(Context);
1795 Visitor.onEndOfTranslationUnit();
1800 ParsingDone = NewParsingDone;
1805std::optional<TraversalKind>
1807 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....
Result
Implement __builtin_bit_cast and related operations.
static void print(llvm::raw_ostream &OS, const T &V, const Context &Ctx, QualType Ty)
Defines the clang::Module class, which describes a module in the source code.
SourceManager & getSourceManager()
static CanQualType getCanonicalType(QualType T)
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
const clang::PrintingPolicy & getPrintingPolicy() const
ParentMapContext & getParentMapContext()
Returns the dynamic AST node parent map context.
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<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.
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.
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)
Top level wrappers for InstallAPI frontend operations.
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
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.