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) {
198 if (TypeNode.isNull())
200 ScopedIncrement ScopedDepth(&CurrentDepth);
202 if (!
match(*TypeNode))
209 bool TraverseTypeLoc(TypeLoc TypeLocNode) {
210 if (TypeLocNode.isNull())
212 ScopedIncrement ScopedDepth(&CurrentDepth);
214 if (!
match(*TypeLocNode.getType()))
217 if (!
match(TypeLocNode.getType()))
222 bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {
223 ScopedIncrement ScopedDepth(&CurrentDepth);
224 return (NNS ==
nullptr) ||
traverse(*NNS);
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 auto *
C =
Node->capture_begin() + I;
289 if (!
C->isExplicit())
291 if (
Node->isInitCapture(
C) && !
match(*
C->getCapturedVar()))
293 if (!
match(*
Node->capture_init_begin()[I]))
297 if (
const auto *TPL =
Node->getTemplateParameterList()) {
298 for (
const auto *TP : *TPL) {
304 for (
const auto *
P :
Node->getCallOperator()->parameters()) {
315 bool shouldVisitTemplateInstantiations()
const {
return true; }
316 bool shouldVisitImplicitCode()
const {
return !IgnoreImplicitChildren; }
320 struct ScopedIncrement {
321 explicit ScopedIncrement(
int *Depth) : Depth(Depth) { ++(*Depth); }
322 ~ScopedIncrement() { --(*Depth); }
336 bool baseTraverse(
const Decl &DeclNode) {
339 bool baseTraverse(
const Stmt &StmtNode) {
342 bool baseTraverse(QualType TypeNode) {
345 bool baseTraverse(TypeLoc TypeLocNode) {
348 bool baseTraverse(
const NestedNameSpecifier &NNS) {
350 const_cast<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>
400 static_assert(IsBaseType<T>::value,
401 "traverse can only be instantiated with base type");
404 return baseTraverse(
Node);
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);
504 bool TraverseTypeLoc(TypeLoc TypeNode);
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();
582 TraverseStmt(NE, Queue);
584 if (
LE->hasExplicitResultType())
585 TraverseTypeLoc(Proto.getReturnLoc());
586 TraverseStmt(
LE->getTrailingRequiresClause());
589 TraverseStmt(
LE->getBody());
596 bool memoizedMatchesRecursively(
const DynTypedNode &
Node, ASTContext &Ctx,
597 const DynTypedMatcher &Matcher,
598 BoundNodesTreeBuilder *Builder,
int MaxDepth,
601 if (!
Node.getMemoizationData() || !Builder->isComparable())
602 return matchesRecursively(
Node, Matcher, Builder, MaxDepth,
Bind);
605 Key.MatcherID = Matcher.getID();
608 Key.BoundNodes = *Builder;
609 Key.Traversal = Ctx.getParentMapContext().getTraversalKind();
611 Key.Type = MaxDepth == 1 ? MatchType::Child : MatchType::Descendants;
612 MemoizationMap::iterator I = ResultCache.find(Key);
613 if (I != ResultCache.end()) {
614 *Builder = I->second.Nodes;
615 return I->second.ResultOfMatch;
618 MemoizedMatchResult
Result;
623 MemoizedMatchResult &CachedResult = ResultCache[Key];
624 CachedResult = std::move(
Result);
626 *Builder = CachedResult.Nodes;
627 return CachedResult.ResultOfMatch;
631 bool matchesRecursively(
const DynTypedNode &
Node,
632 const DynTypedMatcher &Matcher,
633 BoundNodesTreeBuilder *Builder,
int MaxDepth,
635 bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
636 TraversingASTChildrenNotSpelledInSource;
638 bool IgnoreImplicitChildren =
false;
640 if (isTraversalIgnoringImplicitNodes()) {
641 IgnoreImplicitChildren =
true;
644 ASTNodeNotSpelledInSourceScope RAII(
this, ScopedTraversal);
646 MatchChildASTVisitor Visitor(&Matcher,
this, Builder, MaxDepth,
647 IgnoreImplicitChildren,
Bind);
648 return Visitor.findMatch(
Node);
651 bool classIsDerivedFrom(
const CXXRecordDecl *
Declaration,
652 const Matcher<NamedDecl> &
Base,
653 BoundNodesTreeBuilder *Builder,
654 bool Directly)
override;
658 classIsDerivedFromImpl(
const CXXRecordDecl *
Declaration,
659 const Matcher<NamedDecl> &
Base,
660 BoundNodesTreeBuilder *Builder,
bool Directly,
661 llvm::SmallPtrSetImpl<const CXXRecordDecl *> &
Visited);
664 bool objcClassIsDerivedFrom(
const ObjCInterfaceDecl *
Declaration,
665 const Matcher<NamedDecl> &
Base,
666 BoundNodesTreeBuilder *Builder,
667 bool Directly)
override;
671 bool matchesChildOf(
const DynTypedNode &
Node, ASTContext &Ctx,
672 const DynTypedMatcher &Matcher,
673 BoundNodesTreeBuilder *Builder, BindKind
Bind)
override {
674 if (ResultCache.size() > MaxMemoizationEntries)
676 return memoizedMatchesRecursively(
Node, Ctx, Matcher, Builder, 1,
Bind);
679 bool matchesDescendantOf(
const DynTypedNode &
Node, ASTContext &Ctx,
680 const DynTypedMatcher &Matcher,
681 BoundNodesTreeBuilder *Builder,
682 BindKind
Bind)
override {
683 if (ResultCache.size() > MaxMemoizationEntries)
685 return memoizedMatchesRecursively(
Node, Ctx, Matcher, Builder,
INT_MAX,
689 bool matchesAncestorOf(
const DynTypedNode &
Node, ASTContext &Ctx,
690 const DynTypedMatcher &Matcher,
691 BoundNodesTreeBuilder *Builder,
692 AncestorMatchMode MatchMode)
override {
695 if (ResultCache.size() > MaxMemoizationEntries)
697 if (MatchMode == AncestorMatchMode::AMM_ParentOnly)
698 return matchesParentOf(
Node, Matcher, Builder);
699 return matchesAnyAncestorOf(
Node, Ctx, Matcher, Builder);
706 if (
auto *N =
Node.get<Decl>()) {
708 }
else if (
auto *N =
Node.get<Stmt>()) {
710 }
else if (
auto *N =
Node.get<Type>()) {
712 }
else if (
auto *N =
Node.get<QualType>()) {
714 }
else if (
auto *N =
Node.get<NestedNameSpecifier>()) {
716 }
else if (
auto *N =
Node.get<NestedNameSpecifierLoc>()) {
718 }
else if (
auto *N =
Node.get<TypeLoc>()) {
720 }
else if (
auto *N =
Node.get<CXXCtorInitializer>()) {
722 }
else if (
auto *N =
Node.get<TemplateArgumentLoc>()) {
724 }
else if (
auto *N =
Node.get<Attr>()) {
729 template <
typename T>
void match(
const T &
Node) {
730 matchDispatch(&
Node);
734 ASTContext &getASTContext()
const override {
return *ActiveASTContext; }
736 bool shouldVisitTemplateInstantiations()
const {
return true; }
737 bool shouldVisitImplicitCode()
const {
return true; }
741 bool shouldVisitLambdaBody()
const {
return false; }
743 bool IsMatchingInASTNodeNotSpelledInSource()
const override {
744 return TraversingASTNodeNotSpelledInSource;
746 bool isMatchingChildrenNotSpelledInSource()
const override {
747 return TraversingASTChildrenNotSpelledInSource;
749 void setMatchingChildrenNotSpelledInSource(
bool Set)
override {
750 TraversingASTChildrenNotSpelledInSource =
Set;
753 bool IsMatchingInASTNodeNotAsIs()
const override {
754 return TraversingASTNodeNotAsIs;
757 bool TraverseTemplateInstantiations(ClassTemplateDecl *
D) {
758 ASTNodeNotSpelledInSourceScope RAII(
this,
true);
759 return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
763 bool TraverseTemplateInstantiations(VarTemplateDecl *
D) {
764 ASTNodeNotSpelledInSourceScope RAII(
this,
true);
765 return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
769 bool TraverseTemplateInstantiations(FunctionTemplateDecl *
D) {
770 ASTNodeNotSpelledInSourceScope RAII(
this,
true);
771 return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
776 bool TraversingASTNodeNotSpelledInSource =
false;
777 bool TraversingASTNodeNotAsIs =
false;
778 bool TraversingASTChildrenNotSpelledInSource =
false;
785 const QualType *, const TypeLoc *, const NestedNameSpecifier *, \
786 const NestedNameSpecifierLoc *
788 const CXXCtorInitializer *, const TemplateArgumentLoc *, const Attr *, \
792 template <typename NodeType> \
794 llvm::is_one_of<const NodeType *, CMD_TYPES_##Index>::value> \
795 SetCallbackAndRawNode(const MatchCallback *CB, const NodeType &N) { \
797 Callback.setPointerAndInt(CB, Index); \
801 template <typename T> \
802 std::enable_if_t<llvm::is_one_of<const T *, CMD_TYPES_##Index>::value, \
805 assertHoldsState(); \
806 return Callback.getInt() == (Index) ? Node##Index.dyn_cast<const T *>() \
811 CurMatchData() :
Node0(nullptr) {}
816 const MatchCallback *getCallback()
const {
return Callback.getPointer(); }
818 void SetBoundNodes(
const BoundNodes &BN) {
823 void clearBoundNodes() {
835 Callback.setPointerAndInt(
nullptr, 0);
840 void assertHoldsState()
const {
841 assert(Callback.getPointer() !=
nullptr && !
Node0.isNull());
844 void assertEmpty()
const {
845 assert(Callback.getPointer() ==
nullptr &&
Node0.isNull() &&
849 llvm::PointerIntPair<const MatchCallback *, 1> Callback;
851 llvm::PointerUnion<CMD_TYPES_0>
Node0;
852 llvm::PointerUnion<CMD_TYPES_1>
Node1;
861 struct CurMatchRAII {
862 template <
typename NodeType>
863 CurMatchRAII(MatchASTVisitor &MV,
const MatchCallback *CB,
866 MV.CurMatchState.SetCallbackAndRawNode(CB, NT);
869 ~CurMatchRAII() { MV.CurMatchState.reset(); }
876 class TraceReporter : llvm::PrettyStackTraceEntry {
877 static void dumpNode(
const ASTContext &Ctx,
const DynTypedNode &
Node,
879 if (
const auto *
D =
Node.get<Decl>()) {
880 OS <<
D->getDeclKindName() <<
"Decl ";
881 if (
const auto *ND = dyn_cast<NamedDecl>(
D)) {
882 ND->printQualifiedName(OS);
886 D->getSourceRange().print(OS, Ctx.getSourceManager());
887 }
else if (
const auto *S =
Node.get<Stmt>()) {
888 OS << S->getStmtClassName() <<
" : ";
889 S->getSourceRange().print(OS, Ctx.getSourceManager());
890 }
else if (
const auto *
T =
Node.get<Type>()) {
892 QualType(
T, 0).print(OS, Ctx.getPrintingPolicy());
893 }
else if (
const auto *QT =
Node.get<QualType>()) {
895 QT->print(OS, Ctx.getPrintingPolicy());
897 OS <<
Node.getNodeKind().asStringRef() <<
" : ";
898 Node.getSourceRange().print(OS, Ctx.getSourceManager());
902 static void dumpNodeFromState(
const ASTContext &Ctx,
903 const CurMatchData &State, raw_ostream &OS) {
904 if (
const DynTypedNode *MatchNode = State.getNode<DynTypedNode>()) {
905 dumpNode(Ctx, *MatchNode, OS);
906 }
else if (
const auto *QT = State.getNode<QualType>()) {
908 }
else if (
const auto *TL = State.getNode<TypeLoc>()) {
910 }
else if (
const auto *NNS = State.getNode<NestedNameSpecifier>()) {
912 }
else if (
const auto *NNSL = State.getNode<NestedNameSpecifierLoc>()) {
914 }
else if (
const auto *CtorInit = State.getNode<CXXCtorInitializer>()) {
916 }
else if (
const auto *TAL = State.getNode<TemplateArgumentLoc>()) {
918 }
else if (
const auto *At = State.getNode<Attr>()) {
924 TraceReporter(
const MatchASTVisitor &MV) : MV(MV) {}
925 void print(raw_ostream &OS)
const override {
926 const CurMatchData &State = MV.CurMatchState;
927 const MatchCallback *CB = State.getCallback();
929 OS <<
"ASTMatcher: Not currently matching\n";
933 assert(MV.ActiveASTContext &&
934 "ActiveASTContext should be set if there is a matched callback");
936 ASTContext &Ctx = MV.getASTContext();
938 if (
const BoundNodes *
Nodes = State.getBoundNodes()) {
939 OS <<
"ASTMatcher: Processing '" << CB->getID() <<
"' against:\n\t";
940 dumpNodeFromState(Ctx, State, OS);
943 OS <<
"\nNo bound nodes\n";
946 OS <<
"\n--- Bound Nodes Begin ---\n";
947 for (
const auto &Item : Map) {
948 OS <<
" " << Item.first <<
" - { ";
949 dumpNode(Ctx, Item.second, OS);
952 OS <<
"--- Bound Nodes End ---\n";
954 OS <<
"ASTMatcher: Matching '" << CB->getID() <<
"' against:\n\t";
955 dumpNodeFromState(Ctx, State, OS);
961 const MatchASTVisitor &MV;
965 struct ASTNodeNotSpelledInSourceScope {
966 ASTNodeNotSpelledInSourceScope(MatchASTVisitor *
V,
bool B)
967 : MV(
V), MB(
V->TraversingASTNodeNotSpelledInSource) {
968 V->TraversingASTNodeNotSpelledInSource = B;
970 ~ASTNodeNotSpelledInSourceScope() {
971 MV->TraversingASTNodeNotSpelledInSource = MB;
979 struct ASTNodeNotAsIsSourceScope {
980 ASTNodeNotAsIsSourceScope(MatchASTVisitor *
V,
bool B)
981 : MV(
V), MB(
V->TraversingASTNodeNotAsIs) {
982 V->TraversingASTNodeNotAsIs = B;
984 ~ASTNodeNotAsIsSourceScope() { MV->TraversingASTNodeNotAsIs = MB; }
991 class TimeBucketRegion {
993 TimeBucketRegion() =
default;
994 ~TimeBucketRegion() { setBucket(
nullptr); }
1004 void setBucket(llvm::TimeRecord *NewBucket) {
1005 if (Bucket != NewBucket) {
1006 auto Now = llvm::TimeRecord::getCurrentTime(
true);
1016 llvm::TimeRecord *Bucket =
nullptr;
1022 template <
typename T,
typename MC>
1023 void matchWithoutFilter(
const T &
Node,
const MC &Matchers) {
1024 const bool EnableCheckProfiling = Options.CheckProfiling.has_value();
1025 TimeBucketRegion Timer;
1026 for (
const auto &MP : Matchers) {
1027 if (EnableCheckProfiling)
1028 Timer.setBucket(&TimeByBucket[MP.second->getID()]);
1029 BoundNodesTreeBuilder Builder;
1030 CurMatchRAII RAII(*
this, MP.second,
Node);
1031 if (MP.first.matches(
Node,
this, &Builder)) {
1032 MatchVisitor Visitor(*
this, ActiveASTContext, MP.second);
1033 Builder.visitMatches(&Visitor);
1038 void matchWithFilter(
const DynTypedNode &DynNode) {
1039 auto Kind = DynNode.getNodeKind();
1040 auto it = MatcherFiltersMap.find(
Kind);
1042 it != MatcherFiltersMap.end() ? it->second : getFilterForKind(
Kind);
1047 const bool EnableCheckProfiling = Options.CheckProfiling.has_value();
1048 TimeBucketRegion Timer;
1049 auto &Matchers = this->Matchers->DeclOrStmt;
1050 for (
unsigned short I : Filter) {
1051 auto &MP = Matchers[I];
1052 if (EnableCheckProfiling)
1053 Timer.setBucket(&TimeByBucket[MP.second->getID()]);
1054 BoundNodesTreeBuilder Builder;
1057 TraversalKindScope RAII(getASTContext(), MP.first.getTraversalKind());
1058 if (getASTContext().getParentMapContext().traverseIgnored(DynNode) !=
1063 CurMatchRAII RAII(*
this, MP.second, DynNode);
1064 if (MP.first.matches(DynNode,
this, &Builder)) {
1065 MatchVisitor Visitor(*
this, ActiveASTContext, MP.second);
1066 Builder.visitMatches(&Visitor);
1071 const std::vector<unsigned short> &getFilterForKind(ASTNodeKind
Kind) {
1073 auto &Matchers = this->Matchers->DeclOrStmt;
1074 assert((Matchers.size() <
USHRT_MAX) &&
"Too many matchers.");
1075 for (
unsigned I = 0,
E = Matchers.size(); I !=
E; ++I) {
1076 if (Matchers[I].first.canMatchNodesOfKind(
Kind)) {
1085 void matchDispatch(
const Decl *
Node) {
1088 void matchDispatch(
const Stmt *
Node) {
1092 void matchDispatch(
const Type *
Node) {
1093 matchWithoutFilter(QualType(
Node, 0), Matchers->Type);
1095 void matchDispatch(
const TypeLoc *
Node) {
1096 matchWithoutFilter(*
Node, Matchers->TypeLoc);
1098 void matchDispatch(
const QualType *
Node) {
1099 matchWithoutFilter(*
Node, Matchers->Type);
1101 void matchDispatch(
const NestedNameSpecifier *
Node) {
1102 matchWithoutFilter(*
Node, Matchers->NestedNameSpecifier);
1104 void matchDispatch(
const NestedNameSpecifierLoc *
Node) {
1105 matchWithoutFilter(*
Node, Matchers->NestedNameSpecifierLoc);
1107 void matchDispatch(
const CXXCtorInitializer *
Node) {
1108 matchWithoutFilter(*
Node, Matchers->CtorInit);
1110 void matchDispatch(
const TemplateArgumentLoc *
Node) {
1111 matchWithoutFilter(*
Node, Matchers->TemplateArgumentLoc);
1113 void matchDispatch(
const Attr *
Node) {
1114 matchWithoutFilter(*
Node, Matchers->Attr);
1116 void matchDispatch(
const void *) { }
1121 bool matchesParentOf(
const DynTypedNode &
Node,
const DynTypedMatcher &Matcher,
1122 BoundNodesTreeBuilder *Builder) {
1123 for (
const auto &
Parent : ActiveASTContext->getParents(
Node)) {
1124 BoundNodesTreeBuilder BuilderCopy = *Builder;
1125 if (Matcher.matches(
Parent,
this, &BuilderCopy)) {
1126 *Builder = std::move(BuilderCopy);
1149 bool matchesAnyAncestorOf(DynTypedNode
Node, ASTContext &Ctx,
1150 const DynTypedMatcher &Matcher,
1151 BoundNodesTreeBuilder *Builder) {
1156 std::vector<MatchKey> Keys;
1158 auto Finish = [&](
bool Matched) {
1159 for (
const auto &Key : Keys) {
1160 MemoizedMatchResult &CachedResult = ResultCache[Key];
1161 CachedResult.ResultOfMatch = Matched;
1162 CachedResult.Nodes = *Builder;
1168 DynTypedNodeList Parents{ArrayRef<DynTypedNode>()};
1171 if (Builder->isComparable()) {
1172 Keys.emplace_back();
1173 Keys.back().MatcherID = Matcher.getID();
1174 Keys.back().Node =
Node;
1175 Keys.back().BoundNodes = *Builder;
1176 Keys.back().Traversal = Ctx.getParentMapContext().getTraversalKind();
1177 Keys.back().Type = MatchType::Ancestors;
1180 MemoizationMap::iterator I = ResultCache.find(Keys.back());
1181 if (I != ResultCache.end()) {
1183 *Builder = I->second.Nodes;
1184 return Finish(I->second.ResultOfMatch);
1188 Parents = ActiveASTContext->getParents(
Node);
1191 if (Parents.size() != 1)
1195 Node = *Parents.begin();
1196 BoundNodesTreeBuilder BuilderCopy = *Builder;
1197 if (Matcher.matches(
Node,
this, &BuilderCopy)) {
1198 *Builder = std::move(BuilderCopy);
1199 return Finish(
true);
1204 if (Parents.empty()) {
1212 if (!
Node.get<TranslationUnitDecl>() &&
1214 llvm::any_of(ActiveASTContext->getTraversalScope(), [](Decl *
D) {
1215 return D->getKind() == Decl::TranslationUnit;
1217 llvm::errs() <<
"Tried to match orphan node:\n";
1218 Node.dump(llvm::errs(), *ActiveASTContext);
1219 llvm_unreachable(
"Parent map should be complete!");
1223 assert(Parents.size() > 1);
1227 std::deque<DynTypedNode> Queue(Parents.begin(), Parents.end());
1228 llvm::DenseSet<const void *>
Visited;
1229 while (!Queue.empty()) {
1230 BoundNodesTreeBuilder BuilderCopy = *Builder;
1231 if (Matcher.matches(Queue.front(),
this, &BuilderCopy)) {
1232 *Builder = std::move(BuilderCopy);
1233 return Finish(
true);
1235 for (
const auto &
Parent : ActiveASTContext->getParents(Queue.front())) {
1245 return Finish(
false);
1250 class MatchVisitor :
public BoundNodesTreeBuilder::Visitor {
1251 struct CurBoundScope {
1252 CurBoundScope(MatchASTVisitor::CurMatchData &State,
const BoundNodes &BN)
1254 State.SetBoundNodes(BN);
1257 ~CurBoundScope() { State.clearBoundNodes(); }
1260 MatchASTVisitor::CurMatchData &State;
1264 MatchVisitor(MatchASTVisitor &MV, ASTContext *Context,
1265 MatchFinder::MatchCallback *Callback)
1266 : State(MV.CurMatchState), Context(Context), Callback(Callback) {}
1268 void visitMatch(
const BoundNodes& BoundNodesView)
override {
1269 TraversalKindScope RAII(*Context, Callback->getCheckTraversalKind());
1270 CurBoundScope RAII2(State, BoundNodesView);
1271 Callback->run(MatchFinder::MatchResult(BoundNodesView, Context));
1275 MatchASTVisitor::CurMatchData &State;
1276 ASTContext* Context;
1277 MatchFinder::MatchCallback* Callback;
1281 bool typeHasMatchingAlias(
const Type *TypeNode,
1282 const Matcher<NamedDecl> &Matcher,
1283 BoundNodesTreeBuilder *Builder) {
1284 const Type *
const CanonicalType =
1285 ActiveASTContext->getCanonicalType(TypeNode);
1286 auto Aliases = TypeAliases.find(CanonicalType);
1287 if (Aliases == TypeAliases.end())
1289 for (
const TypedefNameDecl *Alias : Aliases->second) {
1290 BoundNodesTreeBuilder
Result(*Builder);
1291 if (Matcher.matches(*Alias,
this, &
Result)) {
1292 *Builder = std::move(
Result);
1300 objcClassHasMatchingCompatibilityAlias(
const ObjCInterfaceDecl *InterfaceDecl,
1301 const Matcher<NamedDecl> &Matcher,
1302 BoundNodesTreeBuilder *Builder) {
1303 auto Aliases = CompatibleAliases.find(InterfaceDecl);
1304 if (Aliases == CompatibleAliases.end())
1306 for (
const ObjCCompatibleAliasDecl *Alias : Aliases->second) {
1307 BoundNodesTreeBuilder
Result(*Builder);
1308 if (Matcher.matches(*Alias,
this, &
Result)) {
1309 *Builder = std::move(
Result);
1319 llvm::StringMap<llvm::TimeRecord> TimeByBucket;
1321 const MatchFinder::MatchersByType *Matchers;
1329 llvm::DenseMap<ASTNodeKind, std::vector<unsigned short>> MatcherFiltersMap;
1331 const MatchFinder::MatchFinderOptions &Options;
1332 ASTContext *ActiveASTContext;
1335 llvm::DenseMap<const Type*, std::set<const TypedefNameDecl*> > TypeAliases;
1338 llvm::DenseMap<
const ObjCInterfaceDecl *,
1343 typedef std::map<MatchKey, MemoizedMatchResult> MemoizationMap;
1344 MemoizationMap ResultCache;
1347static CXXRecordDecl *
1348getAsCXXRecordDeclOrPrimaryTemplate(
const Type *TypeNode) {
1349 if (
auto *RD = TypeNode->getAsCXXRecordDecl())
1353 auto *TemplateType = TypeNode->getAs<TemplateSpecializationType>();
1354 while (TemplateType && TemplateType->isTypeAlias())
1356 TemplateType->getAliasedType()->getAs<TemplateSpecializationType>();
1361 if (
auto *ClassTemplate = dyn_cast_or_null<ClassTemplateDecl>(
1362 TemplateType->getTemplateName().getAsTemplateDecl()))
1363 return ClassTemplate->getTemplatedDecl();
1371bool MatchASTVisitor::classIsDerivedFrom(
const CXXRecordDecl *
Declaration,
1372 const Matcher<NamedDecl> &
Base,
1373 BoundNodesTreeBuilder *Builder,
1379bool MatchASTVisitor::classIsDerivedFromImpl(
1381 BoundNodesTreeBuilder *Builder,
bool Directly,
1382 llvm::SmallPtrSetImpl<const CXXRecordDecl *> &
Visited) {
1388 const Type *TypeNode = It.getType().getTypePtr();
1390 if (typeHasMatchingAlias(TypeNode,
Base, Builder))
1396 CXXRecordDecl *ClassDecl = getAsCXXRecordDeclOrPrimaryTemplate(TypeNode);
1403 BoundNodesTreeBuilder
Result(*Builder);
1404 if (
Base.matches(*ClassDecl,
this, &
Result)) {
1405 *Builder = std::move(
Result);
1409 classIsDerivedFromImpl(ClassDecl,
Base, Builder, Directly,
Visited))
1418bool MatchASTVisitor::objcClassIsDerivedFrom(
1420 BoundNodesTreeBuilder *Builder,
bool Directly) {
1422 for (
const ObjCInterfaceDecl *ClassDecl =
Declaration->getSuperClass();
1423 ClassDecl !=
nullptr; ClassDecl = ClassDecl->getSuperClass()) {
1425 if (objcClassHasMatchingCompatibilityAlias(ClassDecl,
Base, Builder))
1429 const Type *TypeNode = ClassDecl->getTypeForDecl();
1430 if (typeHasMatchingAlias(TypeNode,
Base, Builder))
1433 if (
Base.matches(*ClassDecl,
this, Builder))
1444bool MatchASTVisitor::TraverseDecl(Decl *DeclNode) {
1449 bool ScopedTraversal =
1450 TraversingASTNodeNotSpelledInSource || DeclNode->isImplicit();
1451 bool ScopedChildren = TraversingASTChildrenNotSpelledInSource;
1453 if (
const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(DeclNode)) {
1454 auto SK = CTSD->getSpecializationKind();
1457 ScopedChildren =
true;
1458 }
else if (
const auto *FD = dyn_cast<FunctionDecl>(DeclNode)) {
1459 if (FD->isDefaulted())
1460 ScopedChildren =
true;
1461 if (FD->isTemplateInstantiation())
1462 ScopedTraversal =
true;
1463 }
else if (isa<BindingDecl>(DeclNode)) {
1464 ScopedChildren =
true;
1467 ASTNodeNotSpelledInSourceScope RAII1(
this, ScopedTraversal);
1468 ASTChildrenNotSpelledInSourceScope RAII2(
this, ScopedChildren);
1474bool MatchASTVisitor::TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue) {
1478 bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
1479 TraversingASTChildrenNotSpelledInSource;
1481 ASTNodeNotSpelledInSourceScope RAII(
this, ScopedTraversal);
1486bool MatchASTVisitor::TraverseType(QualType TypeNode) {
1491bool MatchASTVisitor::TraverseTypeLoc(TypeLoc TypeLocNode) {
1498 match(TypeLocNode.getType());
1502bool MatchASTVisitor::TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {
1507bool MatchASTVisitor::TraverseNestedNameSpecifierLoc(
1508 NestedNameSpecifierLoc NNS) {
1516 if (NNS.hasQualifier())
1517 match(*NNS.getNestedNameSpecifier());
1522bool MatchASTVisitor::TraverseConstructorInitializer(
1523 CXXCtorInitializer *CtorInit) {
1527 bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
1528 TraversingASTChildrenNotSpelledInSource;
1530 if (!CtorInit->isWritten())
1531 ScopedTraversal =
true;
1533 ASTNodeNotSpelledInSourceScope RAII1(
this, ScopedTraversal);
1541bool MatchASTVisitor::TraverseTemplateArgumentLoc(TemplateArgumentLoc
Loc) {
1546bool MatchASTVisitor::TraverseAttr(Attr *AttrNode) {
1551class MatchASTConsumer :
public ASTConsumer {
1553 MatchASTConsumer(MatchFinder *Finder,
1554 MatchFinder::ParsingDoneTestCallback *ParsingDone)
1555 : Finder(Finder), ParsingDone(ParsingDone) {}
1558 void HandleTranslationUnit(ASTContext &Context)
override {
1559 if (ParsingDone !=
nullptr) {
1562 Finder->matchAST(Context);
1565 MatchFinder *Finder;
1566 MatchFinder::ParsingDoneTestCallback *ParsingDone;
1581 : Options(
std::move(Options)), ParsingDone(nullptr) {}
1587 std::optional<TraversalKind> TK;
1591 Matchers.DeclOrStmt.emplace_back(
traverse(*TK, NodeMatch), Action);
1593 Matchers.DeclOrStmt.emplace_back(NodeMatch, Action);
1594 Matchers.AllCallbacks.insert(Action);
1599 Matchers.Type.emplace_back(NodeMatch, Action);
1600 Matchers.AllCallbacks.insert(Action);
1605 std::optional<TraversalKind> TK;
1609 Matchers.DeclOrStmt.emplace_back(
traverse(*TK, NodeMatch), Action);
1611 Matchers.DeclOrStmt.emplace_back(NodeMatch, Action);
1612 Matchers.AllCallbacks.insert(Action);
1617 Matchers.NestedNameSpecifier.emplace_back(NodeMatch, Action);
1618 Matchers.AllCallbacks.insert(Action);
1623 Matchers.NestedNameSpecifierLoc.emplace_back(NodeMatch, Action);
1624 Matchers.AllCallbacks.insert(Action);
1629 Matchers.TypeLoc.emplace_back(NodeMatch, Action);
1630 Matchers.AllCallbacks.insert(Action);
1635 Matchers.CtorInit.emplace_back(NodeMatch, Action);
1636 Matchers.AllCallbacks.insert(Action);
1641 Matchers.TemplateArgumentLoc.emplace_back(NodeMatch, Action);
1642 Matchers.AllCallbacks.insert(Action);
1647 Matchers.Attr.emplace_back(AttrMatch, Action);
1648 Matchers.AllCallbacks.insert(Action);
1653 if (NodeMatch.canConvertTo<
Decl>()) {
1656 }
else if (NodeMatch.canConvertTo<
QualType>()) {
1659 }
else if (NodeMatch.canConvertTo<
Stmt>()) {
1668 }
else if (NodeMatch.canConvertTo<
TypeLoc>()) {
1677 }
else if (NodeMatch.canConvertTo<
Attr>()) {
1685 return std::make_unique<internal::MatchASTConsumer>(
this, ParsingDone);
1689 internal::MatchASTVisitor Visitor(&Matchers, Options);
1690 Visitor.set_active_ast_context(&Context);
1691 Visitor.match(
Node);
1695 internal::MatchASTVisitor Visitor(&Matchers, Options);
1696 internal::MatchASTVisitor::TraceReporter StackTrace(Visitor);
1697 Visitor.set_active_ast_context(&Context);
1698 Visitor.onStartOfTranslationUnit();
1699 Visitor.TraverseAST(Context);
1700 Visitor.onEndOfTranslationUnit();
1705 ParsingDone = NewParsingDone;
1710std::optional<TraversalKind>
1712 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::@1655::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 TraverseType(QualType T)
Recursively visit a type, by dispatching to Traverse*Type() based on the argument's getTypeClass() pr...
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 TraverseNestedNameSpecifier(NestedNameSpecifier *NNS)
Recursively visit a C++ nested-name-specifier.
bool TraverseStmt(Stmt *S, DataRecursionQueue *Queue=nullptr)
Recursively visit a statement or expression, by dispatching to Traverse*() based on the argument's dy...
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 TraverseTypeLoc(TypeLoc TL)
Recursively visit a type with location, by dispatching to Traverse*TypeLoc() based on the argument ty...
bool TraverseAttr(Attr *At)
Recursively visit an attribute, by dispatching to Traverse*Attr() based on the argument's dynamic typ...
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
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.
@ Decl
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
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)
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
@ 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)