23#include "llvm/ADT/DenseMap.h"
24#include "llvm/ADT/SmallPtrSet.h"
25#include "llvm/ADT/StringMap.h"
26#include "llvm/Support/PrettyStackTrace.h"
27#include "llvm/Support/Timer.h"
33namespace ast_matchers {
37typedef MatchFinder::MatchCallback MatchCallback;
47static const unsigned MaxMemoizationEntries = 10000;
83struct MemoizedMatchResult {
90class MatchChildASTVisitor
91 :
public RecursiveASTVisitor<MatchChildASTVisitor> {
93 typedef RecursiveASTVisitor<MatchChildASTVisitor> VisitorBase;
99 MatchChildASTVisitor(
const DynTypedMatcher *Matcher, ASTMatchFinder *Finder,
100 BoundNodesTreeBuilder *Builder,
int MaxDepth,
101 bool IgnoreImplicitChildren,
102 ASTMatchFinder::BindKind Bind)
103 : Matcher(Matcher), Finder(Finder), Builder(Builder), CurrentDepth(0),
104 MaxDepth(MaxDepth), IgnoreImplicitChildren(IgnoreImplicitChildren),
105 Bind(Bind), Matches(
false) {}
118 bool findMatch(
const DynTypedNode &DynNode) {
120 if (
const Decl *
D = DynNode.get<Decl>())
122 else if (
const Stmt *S = DynNode.get<Stmt>())
124 else if (
const NestedNameSpecifier *NNS =
125 DynNode.get<NestedNameSpecifier>())
127 else if (
const NestedNameSpecifierLoc *NNSLoc =
128 DynNode.get<NestedNameSpecifierLoc>())
130 else if (
const QualType *Q = DynNode.get<QualType>())
132 else if (
const TypeLoc *
T = DynNode.get<TypeLoc>())
134 else if (
const auto *
C = DynNode.get<CXXCtorInitializer>())
136 else if (
const TemplateArgumentLoc *TALoc =
137 DynNode.get<TemplateArgumentLoc>())
139 else if (
const Attr *A = DynNode.get<Attr>())
146 *Builder = ResultBindings;
154 bool TraverseDecl(Decl *DeclNode) {
156 if (DeclNode && DeclNode->isImplicit() &&
157 Finder->isTraversalIgnoringImplicitNodes())
158 return baseTraverse(*DeclNode);
160 ScopedIncrement ScopedDepth(&CurrentDepth);
161 return (DeclNode ==
nullptr) ||
traverse(*DeclNode);
164 Stmt *getStmtToTraverse(Stmt *StmtNode) {
165 Stmt *StmtToTraverse = StmtNode;
166 if (
auto *ExprNode = dyn_cast_or_null<Expr>(StmtNode)) {
167 auto *LambdaNode = dyn_cast_or_null<LambdaExpr>(StmtNode);
168 if (LambdaNode && Finder->isTraversalIgnoringImplicitNodes())
169 StmtToTraverse = LambdaNode;
172 Finder->getASTContext().getParentMapContext().traverseIgnored(
175 return StmtToTraverse;
178 bool TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue =
nullptr) {
180 if (CurrentDepth == 0 || (CurrentDepth <= MaxDepth && MaxDepth <
INT_MAX))
183 ScopedIncrement ScopedDepth(&CurrentDepth);
184 Stmt *StmtToTraverse = getStmtToTraverse(StmtNode);
188 if (IgnoreImplicitChildren && isa<CXXDefaultArgExpr>(StmtNode))
191 if (!
match(*StmtToTraverse))
197 bool TraverseType(QualType TypeNode,
bool TraverseQualifier =
true) {
198 if (TypeNode.isNull())
200 ScopedIncrement ScopedDepth(&CurrentDepth);
202 if (!
match(*TypeNode))
205 return traverse(TypeNode, TraverseQualifier);
209 bool TraverseTypeLoc(TypeLoc TypeLocNode,
bool TraverseQualifier =
true) {
210 if (TypeLocNode.isNull())
212 ScopedIncrement ScopedDepth(&CurrentDepth);
214 if (!
match(*TypeLocNode.getType()))
217 if (!
match(TypeLocNode.getType()))
220 return traverse(TypeLocNode, TraverseQualifier);
222 bool TraverseNestedNameSpecifier(NestedNameSpecifier NNS) {
223 ScopedIncrement ScopedDepth(&CurrentDepth);
226 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
229 ScopedIncrement ScopedDepth(&CurrentDepth);
230 if (!
match(NNS.getNestedNameSpecifier()))
234 bool TraverseConstructorInitializer(CXXCtorInitializer *CtorInit) {
237 ScopedIncrement ScopedDepth(&CurrentDepth);
240 bool TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL) {
241 ScopedIncrement ScopedDepth(&CurrentDepth);
244 bool TraverseCXXForRangeStmt(CXXForRangeStmt *
Node) {
245 if (!Finder->isTraversalIgnoringImplicitNodes())
246 return VisitorBase::TraverseCXXForRangeStmt(
Node);
249 ScopedIncrement ScopedDepth(&CurrentDepth);
262 bool TraverseCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *
Node) {
263 if (!Finder->isTraversalIgnoringImplicitNodes())
264 return VisitorBase::TraverseCXXRewrittenBinaryOperator(
Node);
267 ScopedIncrement ScopedDepth(&CurrentDepth);
271 bool TraverseAttr(Attr *A) {
274 Finder->getASTContext().getParentMapContext().getTraversalKind() ==
277 ScopedIncrement ScopedDepth(&CurrentDepth);
280 bool TraverseLambdaExpr(LambdaExpr *
Node) {
281 if (!Finder->isTraversalIgnoringImplicitNodes())
282 return VisitorBase::TraverseLambdaExpr(
Node);
285 ScopedIncrement ScopedDepth(&CurrentDepth);
287 for (
unsigned I = 0, N =
Node->capture_size(); I != N; ++I) {
288 const LambdaCapture *
C =
Node->capture_begin() + I;
289 if (!
C->isExplicit())
291 if (
Node->isInitCapture(
C) && !
match(*
C->getCapturedVar()))
293 const Expr *CIE =
Node->capture_init_begin()[I];
294 if (CIE !=
nullptr && !
match(*CIE))
298 if (
const auto *TPL =
Node->getTemplateParameterList()) {
299 for (
const auto *TP : *TPL) {
305 for (
const auto *
P :
Node->getCallOperator()->parameters()) {
316 bool shouldVisitTemplateInstantiations()
const {
return true; }
317 bool shouldVisitImplicitCode()
const {
return !IgnoreImplicitChildren; }
321 struct ScopedIncrement {
322 explicit ScopedIncrement(
int *Depth) : Depth(Depth) { ++(*Depth); }
323 ~ScopedIncrement() { --(*Depth); }
337 bool baseTraverse(
const Decl &DeclNode) {
340 bool baseTraverse(
const Stmt &StmtNode) {
343 bool baseTraverse(QualType TypeNode,
bool TraverseQualifier) {
346 bool baseTraverse(TypeLoc TypeLocNode,
bool TraverseQualifier) {
349 bool baseTraverse(NestedNameSpecifier NNS) {
352 bool baseTraverse(NestedNameSpecifierLoc NNS) {
355 bool baseTraverse(
const CXXCtorInitializer &CtorInit) {
357 const_cast<CXXCtorInitializer *
>(&CtorInit));
359 bool baseTraverse(TemplateArgumentLoc TAL) {
362 bool baseTraverse(
const Attr &AttrNode) {
371 template <
typename T>
373 if (CurrentDepth == 0 || CurrentDepth > MaxDepth) {
376 if (Bind != ASTMatchFinder::BK_All) {
377 BoundNodesTreeBuilder RecursiveBuilder(*Builder);
379 &RecursiveBuilder)) {
381 ResultBindings.addMatch(RecursiveBuilder);
385 BoundNodesTreeBuilder RecursiveBuilder(*Builder);
387 &RecursiveBuilder)) {
390 ResultBindings.addMatch(RecursiveBuilder);
398 template <
typename T,
class... Args>
400 static_assert(IsBaseType<T>::value,
401 "traverse can only be instantiated with base type");
404 return baseTraverse(
Node, std::forward<Args>(args)...);
407 const DynTypedMatcher *
const Matcher;
408 ASTMatchFinder *
const Finder;
409 BoundNodesTreeBuilder *
const Builder;
410 BoundNodesTreeBuilder ResultBindings;
413 const bool IgnoreImplicitChildren;
414 const ASTMatchFinder::BindKind Bind;
420class MatchASTVisitor :
public RecursiveASTVisitor<MatchASTVisitor>,
421 public ASTMatchFinder {
423 MatchASTVisitor(
const MatchFinder::MatchersByType *Matchers,
424 const MatchFinder::MatchFinderOptions &Options)
425 : Matchers(Matchers), Options(Options), ActiveASTContext(nullptr) {}
427 ~MatchASTVisitor()
override {
428 if (Options.CheckProfiling) {
429 Options.CheckProfiling->Records = std::move(TimeByBucket);
433 void onStartOfTranslationUnit() {
434 const bool EnableCheckProfiling = Options.CheckProfiling.has_value();
435 TimeBucketRegion Timer;
436 for (MatchCallback *MC : Matchers->AllCallbacks) {
437 if (EnableCheckProfiling)
438 Timer.setBucket(&TimeByBucket[MC->getID()]);
439 MC->onStartOfTranslationUnit();
443 void onEndOfTranslationUnit() {
444 const bool EnableCheckProfiling = Options.CheckProfiling.has_value();
445 TimeBucketRegion Timer;
446 for (MatchCallback *MC : Matchers->AllCallbacks) {
447 if (EnableCheckProfiling)
448 Timer.setBucket(&TimeByBucket[MC->getID()]);
449 MC->onEndOfTranslationUnit();
453 void set_active_ast_context(ASTContext *NewActiveASTContext) {
454 ActiveASTContext = NewActiveASTContext;
460 bool VisitTypedefNameDecl(TypedefNameDecl *DeclNode) {
488 const Type *TypeNode = DeclNode->getUnderlyingType().getTypePtr();
489 const Type *CanonicalType =
490 ActiveASTContext->getCanonicalType(TypeNode);
491 TypeAliases[CanonicalType].insert(DeclNode);
495 bool VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) {
496 const ObjCInterfaceDecl *InterfaceDecl = CAD->getClassInterface();
497 CompatibleAliases[InterfaceDecl].insert(CAD);
501 bool TraverseDecl(Decl *DeclNode);
502 bool TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue =
nullptr);
503 bool TraverseType(QualType TypeNode,
bool TraverseQualifier =
true);
504 bool TraverseTypeLoc(TypeLoc TypeNode,
bool TraverseQualifier =
true);
505 bool TraverseNestedNameSpecifier(NestedNameSpecifier NNS);
506 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);
507 bool TraverseConstructorInitializer(CXXCtorInitializer *CtorInit);
508 bool TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL);
509 bool TraverseAttr(Attr *AttrNode);
511 bool dataTraverseNode(Stmt *S, DataRecursionQueue *Queue) {
512 if (
auto *RF = dyn_cast<CXXForRangeStmt>(S)) {
514 ASTNodeNotAsIsSourceScope RAII(
this,
true);
515 TraverseStmt(RF->getInit());
517 match(*RF->getLoopVariable());
518 TraverseStmt(RF->getRangeInit());
521 ASTNodeNotSpelledInSourceScope RAII(
this,
true);
522 for (
auto *SubStmt : RF->children()) {
523 if (SubStmt != RF->getBody())
524 TraverseStmt(SubStmt);
527 TraverseStmt(RF->getBody());
529 }
else if (
auto *RBO = dyn_cast<CXXRewrittenBinaryOperator>(S)) {
531 ASTNodeNotAsIsSourceScope RAII(
this,
true);
532 TraverseStmt(
const_cast<Expr *
>(RBO->getLHS()));
533 TraverseStmt(
const_cast<Expr *
>(RBO->getRHS()));
536 ASTNodeNotSpelledInSourceScope RAII(
this,
true);
537 for (
auto *SubStmt : RBO->children()) {
538 TraverseStmt(SubStmt);
542 }
else if (
auto *LE = dyn_cast<LambdaExpr>(S)) {
543 for (
auto I : llvm::zip(
LE->captures(),
LE->capture_inits())) {
544 auto C = std::get<0>(I);
545 ASTNodeNotSpelledInSourceScope RAII(
546 this, TraversingASTNodeNotSpelledInSource || !
C.isExplicit());
547 TraverseLambdaCapture(LE, &
C, std::get<1>(I));
551 ASTNodeNotSpelledInSourceScope RAII(
this,
true);
552 TraverseDecl(
LE->getLambdaClass());
555 ASTNodeNotAsIsSourceScope RAII(
this,
true);
559 TypeLoc TL =
LE->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
560 FunctionProtoTypeLoc Proto = TL.getAsAdjusted<FunctionProtoTypeLoc>();
562 if (
auto *TPL =
LE->getTemplateParameterList()) {
563 for (NamedDecl *
D : *TPL) {
566 if (Expr *RequiresClause = TPL->getRequiresClause()) {
567 TraverseStmt(RequiresClause);
571 if (
LE->hasExplicitParameters()) {
573 for (ParmVarDecl *Param : Proto.getParams())
577 const auto *
T = Proto.getTypePtr();
579 TraverseType(
E,
true);
582 TraverseStmt(NE, Queue);
584 if (
LE->hasExplicitResultType())
585 TraverseTypeLoc(Proto.getReturnLoc(),
true);
587 const_cast<Expr *
>(
LE->getTrailingRequiresClause().ConstraintExpr));
590 TraverseStmt(
LE->getBody());
597 bool memoizedMatchesRecursively(
const DynTypedNode &
Node, ASTContext &Ctx,
598 const DynTypedMatcher &Matcher,
599 BoundNodesTreeBuilder *Builder,
int MaxDepth,
602 if (!
Node.getMemoizationData() || !Builder->isComparable())
603 return matchesRecursively(
Node, Matcher, Builder, MaxDepth,
Bind);
606 Key.MatcherID = Matcher.getID();
609 Key.BoundNodes = *Builder;
610 Key.Traversal = Ctx.getParentMapContext().getTraversalKind();
612 Key.Type = MaxDepth == 1 ? MatchType::Child : MatchType::Descendants;
613 MemoizationMap::iterator I = ResultCache.find(Key);
614 if (I != ResultCache.end()) {
615 *Builder = I->second.Nodes;
616 return I->second.ResultOfMatch;
619 MemoizedMatchResult
Result;
624 MemoizedMatchResult &CachedResult = ResultCache[Key];
625 CachedResult = std::move(
Result);
627 *Builder = CachedResult.Nodes;
628 return CachedResult.ResultOfMatch;
632 bool matchesRecursively(
const DynTypedNode &
Node,
633 const DynTypedMatcher &Matcher,
634 BoundNodesTreeBuilder *Builder,
int MaxDepth,
636 bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
637 TraversingASTChildrenNotSpelledInSource;
639 bool IgnoreImplicitChildren =
false;
641 if (isTraversalIgnoringImplicitNodes()) {
642 IgnoreImplicitChildren =
true;
645 ASTNodeNotSpelledInSourceScope RAII(
this, ScopedTraversal);
647 MatchChildASTVisitor Visitor(&Matcher,
this, Builder, MaxDepth,
648 IgnoreImplicitChildren,
Bind);
649 return Visitor.findMatch(
Node);
652 bool classIsDerivedFrom(
const CXXRecordDecl *
Declaration,
653 const Matcher<NamedDecl> &
Base,
654 BoundNodesTreeBuilder *Builder,
655 bool Directly)
override;
659 classIsDerivedFromImpl(
const CXXRecordDecl *
Declaration,
660 const Matcher<NamedDecl> &
Base,
661 BoundNodesTreeBuilder *Builder,
bool Directly,
662 llvm::SmallPtrSetImpl<const CXXRecordDecl *> &
Visited);
665 bool objcClassIsDerivedFrom(
const ObjCInterfaceDecl *
Declaration,
666 const Matcher<NamedDecl> &
Base,
667 BoundNodesTreeBuilder *Builder,
668 bool Directly)
override;
672 bool matchesChildOf(
const DynTypedNode &
Node, ASTContext &Ctx,
673 const DynTypedMatcher &Matcher,
674 BoundNodesTreeBuilder *Builder, BindKind
Bind)
override {
675 if (ResultCache.size() > MaxMemoizationEntries)
677 return memoizedMatchesRecursively(
Node, Ctx, Matcher, Builder, 1,
Bind);
680 bool matchesDescendantOf(
const DynTypedNode &
Node, ASTContext &Ctx,
681 const DynTypedMatcher &Matcher,
682 BoundNodesTreeBuilder *Builder,
683 BindKind
Bind)
override {
684 if (ResultCache.size() > MaxMemoizationEntries)
686 return memoizedMatchesRecursively(
Node, Ctx, Matcher, Builder,
INT_MAX,
690 bool matchesAncestorOf(
const DynTypedNode &
Node, ASTContext &Ctx,
691 const DynTypedMatcher &Matcher,
692 BoundNodesTreeBuilder *Builder,
693 AncestorMatchMode MatchMode)
override {
696 if (ResultCache.size() > MaxMemoizationEntries)
698 if (MatchMode == AncestorMatchMode::AMM_ParentOnly)
699 return matchesParentOf(
Node, Matcher, Builder);
700 return matchesAnyAncestorOf(
Node, Ctx, Matcher, Builder);
707 if (
auto *N =
Node.get<Decl>()) {
709 }
else if (
auto *N =
Node.get<Stmt>()) {
711 }
else if (
auto *N =
Node.get<Type>()) {
713 }
else if (
auto *N =
Node.get<QualType>()) {
715 }
else if (
auto *N =
Node.get<NestedNameSpecifier>()) {
717 }
else if (
auto *N =
Node.get<NestedNameSpecifierLoc>()) {
719 }
else if (
auto *N =
Node.get<TypeLoc>()) {
721 }
else if (
auto *N =
Node.get<CXXCtorInitializer>()) {
723 }
else if (
auto *N =
Node.get<TemplateArgumentLoc>()) {
725 }
else if (
auto *N =
Node.get<Attr>()) {
730 template <
typename T>
void match(
const T &
Node) {
731 matchDispatch(&
Node);
735 ASTContext &getASTContext()
const override {
return *ActiveASTContext; }
737 bool shouldVisitTemplateInstantiations()
const {
return true; }
738 bool shouldVisitImplicitCode()
const {
return true; }
742 bool shouldVisitLambdaBody()
const {
return false; }
744 bool IsMatchingInASTNodeNotSpelledInSource()
const override {
745 return TraversingASTNodeNotSpelledInSource;
747 bool isMatchingChildrenNotSpelledInSource()
const override {
748 return TraversingASTChildrenNotSpelledInSource;
750 void setMatchingChildrenNotSpelledInSource(
bool Set)
override {
751 TraversingASTChildrenNotSpelledInSource =
Set;
754 bool IsMatchingInASTNodeNotAsIs()
const override {
755 return TraversingASTNodeNotAsIs;
758 bool TraverseTemplateInstantiations(ClassTemplateDecl *
D) {
759 ASTNodeNotSpelledInSourceScope RAII(
this,
true);
760 return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
764 bool TraverseTemplateInstantiations(VarTemplateDecl *
D) {
765 ASTNodeNotSpelledInSourceScope RAII(
this,
true);
766 return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
770 bool TraverseTemplateInstantiations(FunctionTemplateDecl *
D) {
771 ASTNodeNotSpelledInSourceScope RAII(
this,
true);
772 return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
777 bool TraversingASTNodeNotSpelledInSource =
false;
778 bool TraversingASTNodeNotAsIs =
false;
779 bool TraversingASTChildrenNotSpelledInSource =
false;
786 const QualType *, const TypeLoc *, const NestedNameSpecifier *, \
787 const NestedNameSpecifierLoc *
789 const CXXCtorInitializer *, const TemplateArgumentLoc *, const Attr *, \
793 template <typename NodeType> \
795 llvm::is_one_of<const NodeType *, CMD_TYPES_##Index>::value> \
796 SetCallbackAndRawNode(const MatchCallback *CB, const NodeType &N) { \
798 Callback.setPointerAndInt(CB, Index); \
802 template <typename T> \
803 std::enable_if_t<llvm::is_one_of<const T *, CMD_TYPES_##Index>::value, \
806 assertHoldsState(); \
807 return Callback.getInt() == (Index) ? Node##Index.dyn_cast<const T *>() \
812 CurMatchData() :
Node0(nullptr) {}
817 const MatchCallback *getCallback()
const {
return Callback.getPointer(); }
819 void SetBoundNodes(
const BoundNodes &BN) {
824 void clearBoundNodes() {
836 Callback.setPointerAndInt(
nullptr, 0);
841 void assertHoldsState()
const {
842 assert(Callback.getPointer() !=
nullptr && !
Node0.isNull());
845 void assertEmpty()
const {
846 assert(Callback.getPointer() ==
nullptr &&
Node0.isNull() &&
850 llvm::PointerIntPair<const MatchCallback *, 1> Callback;
852 llvm::PointerUnion<CMD_TYPES_0>
Node0;
853 llvm::PointerUnion<CMD_TYPES_1>
Node1;
862 struct CurMatchRAII {
863 template <
typename NodeType>
864 CurMatchRAII(MatchASTVisitor &MV,
const MatchCallback *CB,
867 MV.CurMatchState.SetCallbackAndRawNode(CB, NT);
870 ~CurMatchRAII() { MV.CurMatchState.reset(); }
877 class TraceReporter : llvm::PrettyStackTraceEntry {
878 static void dumpNode(
const ASTContext &Ctx,
const DynTypedNode &
Node,
880 if (
const auto *
D =
Node.get<Decl>()) {
881 OS <<
D->getDeclKindName() <<
"Decl ";
882 if (
const auto *ND = dyn_cast<NamedDecl>(
D)) {
883 ND->printQualifiedName(OS);
887 D->getSourceRange().print(OS, Ctx.getSourceManager());
888 }
else if (
const auto *S =
Node.get<Stmt>()) {
889 OS << S->getStmtClassName() <<
" : ";
890 S->getSourceRange().print(OS, Ctx.getSourceManager());
891 }
else if (
const auto *
T =
Node.get<Type>()) {
893 QualType(
T, 0).print(OS, Ctx.getPrintingPolicy());
894 }
else if (
const auto *QT =
Node.get<QualType>()) {
896 QT->print(OS, Ctx.getPrintingPolicy());
898 OS <<
Node.getNodeKind().asStringRef() <<
" : ";
899 Node.getSourceRange().print(OS, Ctx.getSourceManager());
903 static void dumpNodeFromState(
const ASTContext &Ctx,
904 const CurMatchData &State, raw_ostream &OS) {
905 if (
const DynTypedNode *MatchNode = State.getNode<DynTypedNode>()) {
906 dumpNode(Ctx, *MatchNode, OS);
907 }
else if (
const auto *QT = State.getNode<QualType>()) {
909 }
else if (
const auto *TL = State.getNode<TypeLoc>()) {
911 }
else if (
const auto *NNS = State.getNode<NestedNameSpecifier>()) {
913 }
else if (
const auto *NNSL = State.getNode<NestedNameSpecifierLoc>()) {
915 }
else if (
const auto *CtorInit = State.getNode<CXXCtorInitializer>()) {
917 }
else if (
const auto *TAL = State.getNode<TemplateArgumentLoc>()) {
919 }
else if (
const auto *At = State.getNode<Attr>()) {
925 TraceReporter(
const MatchASTVisitor &MV) : MV(MV) {}
926 void print(raw_ostream &OS)
const override {
927 const CurMatchData &State = MV.CurMatchState;
928 const MatchCallback *CB = State.getCallback();
930 OS <<
"ASTMatcher: Not currently matching\n";
934 assert(MV.ActiveASTContext &&
935 "ActiveASTContext should be set if there is a matched callback");
937 ASTContext &Ctx = MV.getASTContext();
939 if (
const BoundNodes *
Nodes = State.getBoundNodes()) {
940 OS <<
"ASTMatcher: Processing '" << CB->getID() <<
"' against:\n\t";
941 dumpNodeFromState(Ctx, State, OS);
944 OS <<
"\nNo bound nodes\n";
947 OS <<
"\n--- Bound Nodes Begin ---\n";
948 for (
const auto &Item : Map) {
949 OS <<
" " << Item.first <<
" - { ";
950 dumpNode(Ctx, Item.second, OS);
953 OS <<
"--- Bound Nodes End ---\n";
955 OS <<
"ASTMatcher: Matching '" << CB->getID() <<
"' against:\n\t";
956 dumpNodeFromState(Ctx, State, OS);
962 const MatchASTVisitor &MV;
966 struct ASTNodeNotSpelledInSourceScope {
967 ASTNodeNotSpelledInSourceScope(MatchASTVisitor *
V,
bool B)
968 : MV(
V), MB(
V->TraversingASTNodeNotSpelledInSource) {
969 V->TraversingASTNodeNotSpelledInSource = B;
971 ~ASTNodeNotSpelledInSourceScope() {
972 MV->TraversingASTNodeNotSpelledInSource = MB;
980 struct ASTNodeNotAsIsSourceScope {
981 ASTNodeNotAsIsSourceScope(MatchASTVisitor *
V,
bool B)
982 : MV(
V), MB(
V->TraversingASTNodeNotAsIs) {
983 V->TraversingASTNodeNotAsIs = B;
985 ~ASTNodeNotAsIsSourceScope() { MV->TraversingASTNodeNotAsIs = MB; }
992 class TimeBucketRegion {
994 TimeBucketRegion() =
default;
995 ~TimeBucketRegion() { setBucket(
nullptr); }
1005 void setBucket(llvm::TimeRecord *NewBucket) {
1006 if (Bucket != NewBucket) {
1007 auto Now = llvm::TimeRecord::getCurrentTime(
true);
1017 llvm::TimeRecord *Bucket =
nullptr;
1023 template <
typename T,
typename MC>
1024 void matchWithoutFilter(
const T &
Node,
const MC &Matchers) {
1025 const bool EnableCheckProfiling = Options.CheckProfiling.has_value();
1026 TimeBucketRegion Timer;
1027 for (
const auto &MP : Matchers) {
1028 if (EnableCheckProfiling)
1029 Timer.setBucket(&TimeByBucket[MP.second->getID()]);
1030 BoundNodesTreeBuilder Builder;
1031 CurMatchRAII RAII(*
this, MP.second,
Node);
1032 if (MP.first.matches(
Node,
this, &Builder)) {
1033 MatchVisitor Visitor(*
this, ActiveASTContext, MP.second);
1034 Builder.visitMatches(&Visitor);
1039 void matchWithFilter(
const DynTypedNode &DynNode) {
1040 auto Kind = DynNode.getNodeKind();
1041 auto it = MatcherFiltersMap.find(
Kind);
1043 it != MatcherFiltersMap.end() ? it->second : getFilterForKind(
Kind);
1048 const bool EnableCheckProfiling = Options.CheckProfiling.has_value();
1049 TimeBucketRegion Timer;
1050 auto &Matchers = this->Matchers->DeclOrStmt;
1051 for (
unsigned short I : Filter) {
1052 auto &MP = Matchers[I];
1053 if (EnableCheckProfiling)
1054 Timer.setBucket(&TimeByBucket[MP.second->getID()]);
1055 BoundNodesTreeBuilder Builder;
1058 TraversalKindScope RAII(getASTContext(), MP.first.getTraversalKind());
1059 if (getASTContext().getParentMapContext().traverseIgnored(DynNode) !=
1064 CurMatchRAII RAII(*
this, MP.second, DynNode);
1065 if (MP.first.matches(DynNode,
this, &Builder)) {
1066 MatchVisitor Visitor(*
this, ActiveASTContext, MP.second);
1067 Builder.visitMatches(&Visitor);
1072 const std::vector<unsigned short> &getFilterForKind(ASTNodeKind
Kind) {
1074 auto &Matchers = this->Matchers->DeclOrStmt;
1075 assert((Matchers.size() <
USHRT_MAX) &&
"Too many matchers.");
1076 for (
unsigned I = 0,
E = Matchers.size(); I !=
E; ++I) {
1077 if (Matchers[I].first.canMatchNodesOfKind(
Kind)) {
1086 void matchDispatch(
const Decl *
Node) {
1089 void matchDispatch(
const Stmt *
Node) {
1093 void matchDispatch(
const Type *
Node) {
1094 matchWithoutFilter(QualType(
Node, 0), Matchers->Type);
1096 void matchDispatch(
const TypeLoc *
Node) {
1097 matchWithoutFilter(*
Node, Matchers->TypeLoc);
1099 void matchDispatch(
const QualType *
Node) {
1100 matchWithoutFilter(*
Node, Matchers->Type);
1102 void matchDispatch(
const NestedNameSpecifier *
Node) {
1103 matchWithoutFilter(*
Node, Matchers->NestedNameSpecifier);
1105 void matchDispatch(
const NestedNameSpecifierLoc *
Node) {
1106 matchWithoutFilter(*
Node, Matchers->NestedNameSpecifierLoc);
1108 void matchDispatch(
const CXXCtorInitializer *
Node) {
1109 matchWithoutFilter(*
Node, Matchers->CtorInit);
1111 void matchDispatch(
const TemplateArgumentLoc *
Node) {
1112 matchWithoutFilter(*
Node, Matchers->TemplateArgumentLoc);
1114 void matchDispatch(
const Attr *
Node) {
1115 matchWithoutFilter(*
Node, Matchers->Attr);
1117 void matchDispatch(
const void *) { }
1122 bool matchesParentOf(
const DynTypedNode &
Node,
const DynTypedMatcher &Matcher,
1123 BoundNodesTreeBuilder *Builder) {
1124 for (
const auto &
Parent : ActiveASTContext->getParents(
Node)) {
1125 BoundNodesTreeBuilder BuilderCopy = *Builder;
1126 if (Matcher.matches(
Parent,
this, &BuilderCopy)) {
1127 *Builder = std::move(BuilderCopy);
1150 bool matchesAnyAncestorOf(DynTypedNode
Node, ASTContext &Ctx,
1151 const DynTypedMatcher &Matcher,
1152 BoundNodesTreeBuilder *Builder) {
1157 std::vector<MatchKey> Keys;
1159 auto Finish = [&](
bool Matched) {
1160 for (
const auto &Key : Keys) {
1161 MemoizedMatchResult &CachedResult = ResultCache[Key];
1162 CachedResult.ResultOfMatch = Matched;
1163 CachedResult.Nodes = *Builder;
1169 DynTypedNodeList Parents{ArrayRef<DynTypedNode>()};
1172 if (Builder->isComparable()) {
1173 Keys.emplace_back();
1174 Keys.back().MatcherID = Matcher.getID();
1175 Keys.back().Node =
Node;
1176 Keys.back().BoundNodes = *Builder;
1177 Keys.back().Traversal = Ctx.getParentMapContext().getTraversalKind();
1178 Keys.back().Type = MatchType::Ancestors;
1181 MemoizationMap::iterator I = ResultCache.find(Keys.back());
1182 if (I != ResultCache.end()) {
1184 *Builder = I->second.Nodes;
1185 return Finish(I->second.ResultOfMatch);
1189 Parents = ActiveASTContext->getParents(
Node);
1192 if (Parents.size() != 1)
1196 Node = *Parents.begin();
1197 BoundNodesTreeBuilder BuilderCopy = *Builder;
1198 if (Matcher.matches(
Node,
this, &BuilderCopy)) {
1199 *Builder = std::move(BuilderCopy);
1200 return Finish(
true);
1205 if (Parents.empty()) {
1213 if (!
Node.get<TranslationUnitDecl>() &&
1215 llvm::any_of(ActiveASTContext->getTraversalScope(), [](Decl *
D) {
1216 return D->getKind() == Decl::TranslationUnit;
1218 llvm::errs() <<
"Tried to match orphan node:\n";
1219 Node.dump(llvm::errs(), *ActiveASTContext);
1220 llvm_unreachable(
"Parent map should be complete!");
1224 assert(Parents.size() > 1);
1228 std::deque<DynTypedNode> Queue(Parents.begin(), Parents.end());
1229 llvm::DenseSet<const void *>
Visited;
1230 while (!Queue.empty()) {
1231 BoundNodesTreeBuilder BuilderCopy = *Builder;
1232 if (Matcher.matches(Queue.front(),
this, &BuilderCopy)) {
1233 *Builder = std::move(BuilderCopy);
1234 return Finish(
true);
1236 for (
const auto &
Parent : ActiveASTContext->getParents(Queue.front())) {
1246 return Finish(
false);
1251 class MatchVisitor :
public BoundNodesTreeBuilder::Visitor {
1252 struct CurBoundScope {
1253 CurBoundScope(MatchASTVisitor::CurMatchData &State,
const BoundNodes &BN)
1255 State.SetBoundNodes(BN);
1258 ~CurBoundScope() { State.clearBoundNodes(); }
1261 MatchASTVisitor::CurMatchData &State;
1265 MatchVisitor(MatchASTVisitor &MV, ASTContext *Context,
1266 MatchFinder::MatchCallback *Callback)
1267 : State(MV.CurMatchState), Context(Context), Callback(Callback) {}
1269 void visitMatch(
const BoundNodes& BoundNodesView)
override {
1270 TraversalKindScope RAII(*Context, Callback->getCheckTraversalKind());
1271 CurBoundScope RAII2(State, BoundNodesView);
1272 Callback->run(MatchFinder::MatchResult(BoundNodesView, Context));
1276 MatchASTVisitor::CurMatchData &State;
1277 ASTContext* Context;
1278 MatchFinder::MatchCallback* Callback;
1282 bool typeHasMatchingAlias(
const Type *TypeNode,
1283 const Matcher<NamedDecl> &Matcher,
1284 BoundNodesTreeBuilder *Builder) {
1285 const Type *
const CanonicalType =
1286 ActiveASTContext->getCanonicalType(TypeNode);
1287 auto Aliases = TypeAliases.find(CanonicalType);
1288 if (Aliases == TypeAliases.end())
1291 auto matches = [&](
const TypedefNameDecl *Alias) {
1292 BoundNodesTreeBuilder
Result(*Builder);
1293 if (Matcher.matches(*Alias,
this, &
Result)) {
1294 *Builder = std::move(
Result);
1300 if (
const auto *
T = TypeNode->
getAs<TypedefType>()) {
1301 const auto *TD =
T->getDecl()->getCanonicalDecl();
1304 SmallVector<const TypedefNameDecl *, 8> NonExactMatches;
1305 for (
const TypedefNameDecl *Alias : Aliases->second) {
1307 NonExactMatches.push_back(Alias);
1314 for (
const TypedefNameDecl *Alias : NonExactMatches) {
1315 BoundNodesTreeBuilder
Result(*Builder);
1316 if (Matcher.matches(*Alias,
this, &
Result)) {
1317 *Builder = std::move(
Result);
1324 for (
const TypedefNameDecl *Alias : Aliases->second)
1331 objcClassHasMatchingCompatibilityAlias(
const ObjCInterfaceDecl *InterfaceDecl,
1332 const Matcher<NamedDecl> &Matcher,
1333 BoundNodesTreeBuilder *Builder) {
1334 auto Aliases = CompatibleAliases.find(InterfaceDecl);
1335 if (Aliases == CompatibleAliases.end())
1337 for (
const ObjCCompatibleAliasDecl *Alias : Aliases->second) {
1338 BoundNodesTreeBuilder
Result(*Builder);
1339 if (Matcher.matches(*Alias,
this, &
Result)) {
1340 *Builder = std::move(
Result);
1347 template <
typename T>
static SourceLocation getNodeLocation(
const T &
Node) {
1348 return Node.getBeginLoc();
1351 static SourceLocation getNodeLocation(
const CXXCtorInitializer &
Node) {
1352 return Node.getSourceLocation();
1355 static SourceLocation getNodeLocation(
const TemplateArgumentLoc &
Node) {
1356 return Node.getLocation();
1359 static SourceLocation getNodeLocation(
const Attr &
Node) {
1360 return Node.getLocation();
1363 bool isInSystemHeader(SourceLocation
Loc) {
1364 const SourceManager &
SM = getASTContext().getSourceManager();
1365 return SM.isInSystemHeader(
Loc);
1368 template <
typename T>
bool shouldSkipNode(
T &
Node) {
1369 if (Options.IgnoreSystemHeaders && isInSystemHeader(getNodeLocation(
Node)))
1374 template <
typename T>
bool shouldSkipNode(
T *
Node) {
1375 return (
Node ==
nullptr) || shouldSkipNode(*
Node);
1378 bool shouldSkipNode(QualType &) {
return false; }
1380 bool shouldSkipNode(NestedNameSpecifier &) {
return false; }
1385 llvm::StringMap<llvm::TimeRecord> TimeByBucket;
1387 const MatchFinder::MatchersByType *Matchers;
1395 llvm::DenseMap<ASTNodeKind, std::vector<unsigned short>> MatcherFiltersMap;
1397 const MatchFinder::MatchFinderOptions &Options;
1398 ASTContext *ActiveASTContext;
1401 llvm::DenseMap<const Type*, std::set<const TypedefNameDecl*> > TypeAliases;
1404 llvm::DenseMap<
const ObjCInterfaceDecl *,
1409 typedef std::map<MatchKey, MemoizedMatchResult> MemoizationMap;
1410 MemoizationMap ResultCache;
1413static CXXRecordDecl *
1414getAsCXXRecordDeclOrPrimaryTemplate(
const Type *TypeNode) {
1415 if (
auto *RD = TypeNode->getAsCXXRecordDecl())
1419 auto *TemplateType = TypeNode->getAs<TemplateSpecializationType>();
1420 while (TemplateType && TemplateType->isTypeAlias())
1422 TemplateType->getAliasedType()->getAs<TemplateSpecializationType>();
1427 if (
auto *ClassTemplate = dyn_cast_or_null<ClassTemplateDecl>(
1428 TemplateType->getTemplateName().getAsTemplateDecl()))
1429 return ClassTemplate->getTemplatedDecl();
1437bool MatchASTVisitor::classIsDerivedFrom(
const CXXRecordDecl *
Declaration,
1438 const Matcher<NamedDecl> &
Base,
1439 BoundNodesTreeBuilder *Builder,
1445bool MatchASTVisitor::classIsDerivedFromImpl(
1447 BoundNodesTreeBuilder *Builder,
bool Directly,
1448 llvm::SmallPtrSetImpl<const CXXRecordDecl *> &
Visited) {
1454 const Type *TypeNode = It.getType().getTypePtr();
1456 if (typeHasMatchingAlias(TypeNode,
Base, Builder))
1462 CXXRecordDecl *ClassDecl = getAsCXXRecordDeclOrPrimaryTemplate(TypeNode);
1469 BoundNodesTreeBuilder
Result(*Builder);
1470 if (
Base.matches(*ClassDecl,
this, &
Result)) {
1471 *Builder = std::move(
Result);
1475 classIsDerivedFromImpl(ClassDecl,
Base, Builder, Directly,
Visited))
1484bool MatchASTVisitor::objcClassIsDerivedFrom(
1486 BoundNodesTreeBuilder *Builder,
bool Directly) {
1488 for (
const ObjCInterfaceDecl *ClassDecl =
Declaration->getSuperClass();
1489 ClassDecl !=
nullptr; ClassDecl = ClassDecl->getSuperClass()) {
1491 if (objcClassHasMatchingCompatibilityAlias(ClassDecl,
Base, Builder))
1495 const Type *TypeNode = ClassDecl->getTypeForDecl();
1496 if (typeHasMatchingAlias(TypeNode,
Base, Builder))
1499 if (
Base.matches(*ClassDecl,
this, Builder))
1510bool MatchASTVisitor::TraverseDecl(Decl *DeclNode) {
1511 if (shouldSkipNode(DeclNode))
1514 bool ScopedTraversal =
1515 TraversingASTNodeNotSpelledInSource || DeclNode->isImplicit();
1516 bool ScopedChildren = TraversingASTChildrenNotSpelledInSource;
1518 if (
const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(DeclNode)) {
1519 auto SK = CTSD->getSpecializationKind();
1522 ScopedChildren =
true;
1523 }
else if (
const auto *FD = dyn_cast<FunctionDecl>(DeclNode)) {
1524 if (FD->isDefaulted())
1525 ScopedChildren =
true;
1526 if (FD->isTemplateInstantiation())
1527 ScopedTraversal =
true;
1528 }
else if (isa<BindingDecl>(DeclNode)) {
1529 ScopedChildren =
true;
1532 ASTNodeNotSpelledInSourceScope RAII1(
this, ScopedTraversal);
1533 ASTChildrenNotSpelledInSourceScope RAII2(
this, ScopedChildren);
1539bool MatchASTVisitor::TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue) {
1540 if (shouldSkipNode(StmtNode))
1543 bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
1544 TraversingASTChildrenNotSpelledInSource;
1546 ASTNodeNotSpelledInSourceScope RAII(
this, ScopedTraversal);
1551bool MatchASTVisitor::TraverseType(QualType TypeNode,
bool TraverseQualifier) {
1552 if (shouldSkipNode(TypeNode))
1560bool MatchASTVisitor::TraverseTypeLoc(TypeLoc TypeLocNode,
1561 bool TraverseQualifier) {
1562 if (shouldSkipNode(TypeLocNode))
1570 match(TypeLocNode.getType());
1572 TypeLocNode, TraverseQualifier);
1575bool MatchASTVisitor::TraverseNestedNameSpecifier(NestedNameSpecifier NNS) {
1576 if (shouldSkipNode(NNS))
1583bool MatchASTVisitor::TraverseNestedNameSpecifierLoc(
1584 NestedNameSpecifierLoc NNS) {
1588 if (shouldSkipNode(NNS))
1595 if (NNS.hasQualifier())
1596 match(NNS.getNestedNameSpecifier());
1601bool MatchASTVisitor::TraverseConstructorInitializer(
1602 CXXCtorInitializer *CtorInit) {
1603 if (shouldSkipNode(CtorInit))
1606 bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
1607 TraversingASTChildrenNotSpelledInSource;
1609 if (!CtorInit->isWritten())
1610 ScopedTraversal =
true;
1612 ASTNodeNotSpelledInSourceScope RAII1(
this, ScopedTraversal);
1620bool MatchASTVisitor::TraverseTemplateArgumentLoc(TemplateArgumentLoc
Loc) {
1621 if (shouldSkipNode(
Loc))
1628bool MatchASTVisitor::TraverseAttr(Attr *AttrNode) {
1629 if (shouldSkipNode(AttrNode))
1636class MatchASTConsumer :
public ASTConsumer {
1638 MatchASTConsumer(MatchFinder *Finder,
1639 MatchFinder::ParsingDoneTestCallback *ParsingDone)
1640 : Finder(Finder), ParsingDone(ParsingDone) {}
1643 void HandleTranslationUnit(ASTContext &Context)
override {
1644 if (ParsingDone !=
nullptr) {
1647 Finder->matchAST(Context);
1650 MatchFinder *Finder;
1651 MatchFinder::ParsingDoneTestCallback *ParsingDone;
1666 : Options(
std::move(Options)), ParsingDone(nullptr) {}
1672 std::optional<TraversalKind> TK;
1676 Matchers.DeclOrStmt.emplace_back(
traverse(*TK, NodeMatch), Action);
1678 Matchers.DeclOrStmt.emplace_back(NodeMatch, Action);
1679 Matchers.AllCallbacks.insert(Action);
1684 Matchers.Type.emplace_back(NodeMatch, Action);
1685 Matchers.AllCallbacks.insert(Action);
1690 std::optional<TraversalKind> TK;
1694 Matchers.DeclOrStmt.emplace_back(
traverse(*TK, NodeMatch), Action);
1696 Matchers.DeclOrStmt.emplace_back(NodeMatch, Action);
1697 Matchers.AllCallbacks.insert(Action);
1702 Matchers.NestedNameSpecifier.emplace_back(NodeMatch, Action);
1703 Matchers.AllCallbacks.insert(Action);
1708 Matchers.NestedNameSpecifierLoc.emplace_back(NodeMatch, Action);
1709 Matchers.AllCallbacks.insert(Action);
1714 Matchers.TypeLoc.emplace_back(NodeMatch, Action);
1715 Matchers.AllCallbacks.insert(Action);
1720 Matchers.CtorInit.emplace_back(NodeMatch, Action);
1721 Matchers.AllCallbacks.insert(Action);
1726 Matchers.TemplateArgumentLoc.emplace_back(NodeMatch, Action);
1727 Matchers.AllCallbacks.insert(Action);
1732 Matchers.Attr.emplace_back(AttrMatch, Action);
1733 Matchers.AllCallbacks.insert(Action);
1738 if (NodeMatch.canConvertTo<
Decl>()) {
1741 }
else if (NodeMatch.canConvertTo<
QualType>()) {
1744 }
else if (NodeMatch.canConvertTo<
Stmt>()) {
1753 }
else if (NodeMatch.canConvertTo<
TypeLoc>()) {
1762 }
else if (NodeMatch.canConvertTo<
Attr>()) {
1770 return std::make_unique<internal::MatchASTConsumer>(
this, ParsingDone);
1774 internal::MatchASTVisitor Visitor(&Matchers, Options);
1775 Visitor.set_active_ast_context(&Context);
1776 Visitor.match(
Node);
1780 internal::MatchASTVisitor Visitor(&Matchers, Options);
1781 internal::MatchASTVisitor::TraceReporter StackTrace(Visitor);
1782 Visitor.set_active_ast_context(&Context);
1783 Visitor.onStartOfTranslationUnit();
1784 Visitor.TraverseAST(Context);
1785 Visitor.onEndOfTranslationUnit();
1790 ParsingDone = NewParsingDone;
1795std::optional<TraversalKind>
1797 return std::nullopt;
Defines the clang::ASTContext interface.
BoundNodesTreeBuilder BoundNodes
BoundNodesTreeBuilder Nodes
DynTypedMatcher::MatcherIDType MatcherID
llvm::PointerUnion< CMD_TYPES_1 > Node1
llvm::PointerUnion< CMD_TYPES_0 > Node0
enum clang::sema::@1840::IndirectLocalPathEntry::EntryKind Kind
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
llvm::DenseSet< const void * > Visited
static void print(llvm::raw_ostream &OS, const T &V, ASTContext &ASTCtx, QualType Ty)
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)
Recursively visit a statement or expression, by dispatching to Traverse*() based on the argument's dy...
bool TraverseNestedNameSpecifier(NestedNameSpecifier NNS)
Recursively visit a C++ nested-name-specifier.
bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc)
Recursively visit a template argument location and dispatch to the appropriate method for the argumen...
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS)
Recursively visit a C++ nested-name-specifier with location information.
bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier=true)
Recursively visit a type with location, by dispatching to Traverse*TypeLoc() based on the argument ty...
bool dataTraverseNode(Stmt *S, DataRecursionQueue *Queue)
bool TraverseDecl(Decl *D)
Recursively visit a declaration, by dispatching to Traverse*Decl() based on the argument's dynamic ty...
bool TraverseAttr(Attr *At)
Recursively visit an attribute, by dispatching to Traverse*Attr() based on the argument's dynamic typ...
bool TraverseType(QualType T, bool TraverseQualifier=true)
Recursively visit a type, by dispatching to Traverse*Type() based on the argument's getTypeClass() pr...
bool TraverseConstructorInitializer(CXXCtorInitializer *Init)
Recursively visit a constructor initializer.
This class handles loading and caching of source files into memory.
Stmt - This represents one statement.
Location wrapper for a TemplateArgument.
Base wrapper for a particular "section" of type source info.
const char * getTypeClassName() const
const T * getAs() const
Member-template getAs<specific type>'.
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.
internal::Matcher< NestedNameSpecifier > NestedNameSpecifierMatcher
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
internal::Matcher< CXXCtorInitializer > CXXCtorInitializerMatcher
internal::Matcher< Stmt > StatementMatcher
internal::Matcher< TypeLoc > TypeLocMatcher
internal::Matcher< TemplateArgumentLoc > TemplateArgumentLocMatcher
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< Attr > AttrMatcher
internal::Matcher< NestedNameSpecifierLoc > NestedNameSpecifierLocMatcher
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.
@ Bind
'bind' clause, allowed on routine constructs.
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.
@ TSK_ExplicitInstantiationDefinition
This template specialization was instantiated from a template due to an explicit instantiation defini...
@ TSK_ExplicitInstantiationDeclaration
This template specialization was instantiated from a template due to an explicit instantiation declar...
@ Other
Other implicit parameter.
MatchResult(const BoundNodes &Nodes, clang::ASTContext *Context)