23 #include "llvm/ADT/DenseMap.h"
24 #include "llvm/ADT/StringMap.h"
25 #include "llvm/Support/Timer.h"
31 namespace ast_matchers {
35 typedef MatchFinder::MatchCallback MatchCallback;
45 static const unsigned MaxMemoizationEntries = 10000;
61 ast_type_traits::DynTypedNode
Node;
64 bool operator<(
const MatchKey &Other)
const {
66 std::tie(Other.MatcherID, Other.Node, Other.BoundNodes);
71 struct MemoizedMatchResult {
78 class MatchChildASTVisitor
81 typedef RecursiveASTVisitor<MatchChildASTVisitor> VisitorBase;
87 MatchChildASTVisitor(
const DynTypedMatcher *
Matcher,
92 ASTMatchFinder::BindKind
Bind)
113 bool findMatch(
const ast_type_traits::DynTypedNode &DynNode) {
115 if (
const Decl *D = DynNode.get<Decl>())
117 else if (
const Stmt *
S = DynNode.get<
Stmt>())
119 else if (
const NestedNameSpecifier *NNS =
120 DynNode.get<NestedNameSpecifier>())
122 else if (
const NestedNameSpecifierLoc *NNSLoc =
123 DynNode.get<NestedNameSpecifierLoc>())
125 else if (
const QualType *Q = DynNode.get<QualType>())
127 else if (
const TypeLoc *T = DynNode.get<TypeLoc>())
142 bool TraverseDecl(Decl *DeclNode) {
144 return (DeclNode ==
nullptr) || traverse(*DeclNode);
146 bool TraverseStmt(
Stmt *StmtNode) {
148 const Stmt *StmtToTraverse = StmtNode;
150 ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses) {
151 const Expr *ExprNode = dyn_cast_or_null<Expr>(StmtNode);
153 StmtToTraverse = ExprNode->IgnoreParenImpCasts();
156 return (StmtToTraverse ==
nullptr) || traverse(*StmtToTraverse);
160 bool TraverseType(QualType TypeNode) {
161 if (TypeNode.isNull())
165 if (!
match(*TypeNode))
168 return traverse(TypeNode);
172 bool TraverseTypeLoc(TypeLoc TypeLocNode) {
173 if (TypeLocNode.isNull())
177 if (!
match(*TypeLocNode.getType()))
180 if (!
match(TypeLocNode.getType()))
183 return traverse(TypeLocNode);
185 bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {
187 return (NNS ==
nullptr) || traverse(*NNS);
189 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
193 if (!
match(*NNS.getNestedNameSpecifier()))
195 return traverse(NNS);
198 bool shouldVisitTemplateInstantiations()
const {
return true; }
199 bool shouldVisitImplicitCode()
const {
return true; }
202 bool shouldUseDataRecursionFor(clang::Stmt *
S)
const {
return false; }
206 struct ScopedIncrement {
207 explicit ScopedIncrement(
int *
Depth) : Depth(Depth) { ++(*Depth); }
208 ~ScopedIncrement() { --(*Depth); }
222 bool baseTraverse(
const Decl &DeclNode) {
225 bool baseTraverse(
const Stmt &StmtNode) {
228 bool baseTraverse(QualType TypeNode) {
231 bool baseTraverse(TypeLoc TypeLocNode) {
234 bool baseTraverse(
const NestedNameSpecifier &NNS) {
236 const_cast<NestedNameSpecifier*>(&NNS));
238 bool baseTraverse(NestedNameSpecifierLoc NNS) {
247 template <
typename T>
252 if (Bind != ASTMatchFinder::BK_All) {
253 BoundNodesTreeBuilder RecursiveBuilder(*Builder);
255 &RecursiveBuilder)) {
261 BoundNodesTreeBuilder RecursiveBuilder(*Builder);
263 &RecursiveBuilder)) {
274 template <
typename T>
275 bool traverse(
const T &Node) {
276 static_assert(IsBaseType<T>::value,
277 "traverse can only be instantiated with base type");
280 return baseTraverse(Node);
290 const ASTMatchFinder::BindKind
Bind;
297 public ASTMatchFinder {
299 MatchASTVisitor(
const MatchFinder::MatchersByType *
Matchers,
300 const MatchFinder::MatchFinderOptions &
Options)
303 ~MatchASTVisitor()
override {
304 if (Options.CheckProfiling) {
305 Options.CheckProfiling->Records = std::move(
TimeByBucket);
309 void onStartOfTranslationUnit() {
310 const bool EnableCheckProfiling = Options.CheckProfiling.hasValue();
311 TimeBucketRegion Timer;
312 for (MatchCallback *MC : Matchers->AllCallbacks) {
313 if (EnableCheckProfiling)
315 MC->onStartOfTranslationUnit();
319 void onEndOfTranslationUnit() {
320 const bool EnableCheckProfiling = Options.CheckProfiling.hasValue();
321 TimeBucketRegion Timer;
322 for (MatchCallback *MC : Matchers->AllCallbacks) {
323 if (EnableCheckProfiling)
325 MC->onEndOfTranslationUnit();
329 void set_active_ast_context(ASTContext *NewActiveASTContext) {
336 bool VisitTypedefNameDecl(TypedefNameDecl *DeclNode) {
364 const Type *TypeNode = DeclNode->getUnderlyingType().getTypePtr();
365 const Type *CanonicalType =
371 bool TraverseDecl(Decl *DeclNode);
372 bool TraverseStmt(
Stmt *StmtNode);
373 bool TraverseType(QualType TypeNode);
374 bool TraverseTypeLoc(TypeLoc TypeNode);
375 bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS);
376 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);
379 bool memoizedMatchesRecursively(
const ast_type_traits::DynTypedNode &Node,
380 const DynTypedMatcher &Matcher,
381 BoundNodesTreeBuilder *Builder,
int MaxDepth,
382 TraversalKind Traversal, BindKind Bind) {
384 if (!Node.getMemoizationData() || !Builder->isComparable())
385 return matchesRecursively(Node, Matcher, Builder, MaxDepth, Traversal,
389 Key.MatcherID = Matcher.getID();
394 MemoizationMap::iterator I =
ResultCache.find(Key);
396 *Builder = I->second.Nodes;
397 return I->second.ResultOfMatch;
400 MemoizedMatchResult
Result;
402 Result.ResultOfMatch = matchesRecursively(Node, Matcher, &Result.Nodes,
403 MaxDepth, Traversal, Bind);
405 MemoizedMatchResult &CachedResult =
ResultCache[Key];
406 CachedResult = std::move(Result);
408 *Builder = CachedResult.Nodes;
409 return CachedResult.ResultOfMatch;
413 bool matchesRecursively(
const ast_type_traits::DynTypedNode &Node,
414 const DynTypedMatcher &Matcher,
415 BoundNodesTreeBuilder *Builder,
int MaxDepth,
416 TraversalKind Traversal, BindKind Bind) {
417 MatchChildASTVisitor Visitor(
418 &Matcher,
this, Builder, MaxDepth, Traversal, Bind);
419 return Visitor.findMatch(Node);
422 bool classIsDerivedFrom(
const CXXRecordDecl *Declaration,
423 const Matcher<NamedDecl> &
Base,
424 BoundNodesTreeBuilder *Builder)
override;
427 bool matchesChildOf(
const ast_type_traits::DynTypedNode &Node,
428 const DynTypedMatcher &Matcher,
429 BoundNodesTreeBuilder *Builder,
430 TraversalKind Traversal,
431 BindKind Bind)
override {
434 return memoizedMatchesRecursively(Node, Matcher, Builder, 1, Traversal,
438 bool matchesDescendantOf(
const ast_type_traits::DynTypedNode &Node,
439 const DynTypedMatcher &Matcher,
440 BoundNodesTreeBuilder *Builder,
441 BindKind Bind)
override {
444 return memoizedMatchesRecursively(Node, Matcher, Builder,
INT_MAX,
448 bool matchesAncestorOf(
const ast_type_traits::DynTypedNode &Node,
449 const DynTypedMatcher &Matcher,
450 BoundNodesTreeBuilder *Builder,
451 AncestorMatchMode MatchMode)
override {
456 return memoizedMatchesAncestorOfRecursively(Node, Matcher, Builder,
462 void match(
const ast_type_traits::DynTypedNode &Node) {
464 if (
auto *N = Node.get<Decl>()) {
466 }
else if (
auto *N = Node.get<
Stmt>()) {
468 }
else if (
auto *N = Node.get<Type>()) {
470 }
else if (
auto *N = Node.get<QualType>()) {
472 }
else if (
auto *N = Node.get<NestedNameSpecifier>()) {
474 }
else if (
auto *N = Node.get<NestedNameSpecifierLoc>()) {
476 }
else if (
auto *N = Node.get<TypeLoc>()) {
481 template <
typename T>
void match(
const T &Node) {
482 matchDispatch(&Node);
488 bool shouldVisitTemplateInstantiations()
const {
return true; }
489 bool shouldVisitImplicitCode()
const {
return true; }
492 bool shouldUseDataRecursionFor(clang::Stmt *
S)
const {
return false; }
495 class TimeBucketRegion {
497 TimeBucketRegion() :
Bucket(nullptr) {}
498 ~TimeBucketRegion() { setBucket(
nullptr); }
508 void setBucket(llvm::TimeRecord *NewBucket) {
509 if (
Bucket != NewBucket) {
510 auto Now = llvm::TimeRecord::getCurrentTime(
true);
526 template <
typename T,
typename MC>
527 void matchWithoutFilter(
const T &Node,
const MC &Matchers) {
528 const bool EnableCheckProfiling = Options.CheckProfiling.hasValue();
529 TimeBucketRegion Timer;
530 for (
const auto &MP : Matchers) {
531 if (EnableCheckProfiling)
534 if (MP.first.matches(Node,
this, &Builder)) {
536 Builder.visitMatches(&Visitor);
541 void matchWithFilter(
const ast_type_traits::DynTypedNode &DynNode) {
542 auto Kind = DynNode.getNodeKind();
550 const bool EnableCheckProfiling = Options.CheckProfiling.hasValue();
551 TimeBucketRegion Timer;
552 auto &Matchers = this->Matchers->DeclOrStmt;
553 for (
unsigned short I : Filter) {
554 auto &MP = Matchers[I];
555 if (EnableCheckProfiling)
558 if (MP.first.matchesNoKindCheck(DynNode,
this, &Builder)) {
560 Builder.visitMatches(&Visitor);
565 const std::vector<unsigned short> &
566 getFilterForKind(ast_type_traits::ASTNodeKind
Kind) {
568 auto &Matchers = this->Matchers->DeclOrStmt;
569 assert((Matchers.size() <
USHRT_MAX) &&
"Too many matchers.");
570 for (
unsigned I = 0, E = Matchers.size(); I != E; ++I) {
571 if (Matchers[I].first.canMatchNodesOfKind(Kind)) {
580 void matchDispatch(
const Decl *Node) {
583 void matchDispatch(
const Stmt *Node) {
587 void matchDispatch(
const Type *Node) {
588 matchWithoutFilter(QualType(Node, 0), Matchers->Type);
590 void matchDispatch(
const TypeLoc *Node) {
591 matchWithoutFilter(*Node, Matchers->TypeLoc);
593 void matchDispatch(
const QualType *Node) {
594 matchWithoutFilter(*Node, Matchers->Type);
596 void matchDispatch(
const NestedNameSpecifier *Node) {
597 matchWithoutFilter(*Node, Matchers->NestedNameSpecifier);
599 void matchDispatch(
const NestedNameSpecifierLoc *Node) {
600 matchWithoutFilter(*Node, Matchers->NestedNameSpecifierLoc);
602 void matchDispatch(
const void *) { }
618 bool memoizedMatchesAncestorOfRecursively(
619 const ast_type_traits::DynTypedNode &Node,
const DynTypedMatcher &Matcher,
620 BoundNodesTreeBuilder *Builder, AncestorMatchMode MatchMode) {
621 if (Node.get<TranslationUnitDecl>() ==
624 assert(Node.getMemoizationData() &&
625 "Invariant broken: only nodes that support memoization may be "
626 "used in the parent map.");
629 Key.MatcherID = Matcher.getID();
635 MemoizationMap::iterator I =
ResultCache.find(Key);
637 *Builder = I->second.Nodes;
638 return I->second.ResultOfMatch;
641 MemoizedMatchResult
Result;
642 Result.ResultOfMatch =
false;
646 assert(!Parents.empty() &&
"Found node that is not in the parent map.");
647 if (Parents.size() == 1) {
649 const ast_type_traits::DynTypedNode Parent = Parents[0];
650 if (Matcher.matches(Parent,
this, &Result.Nodes)) {
651 Result.ResultOfMatch =
true;
652 }
else if (MatchMode != ASTMatchFinder::AMM_ParentOnly) {
656 Result.ResultOfMatch = memoizedMatchesAncestorOfRecursively(
657 Parent, Matcher, &Result.Nodes, MatchMode);
664 std::deque<ast_type_traits::DynTypedNode> Queue(Parents.begin(),
666 while (!Queue.empty()) {
668 if (Matcher.matches(Queue.front(),
this, &Result.Nodes)) {
669 Result.ResultOfMatch =
true;
672 if (MatchMode != ASTMatchFinder::AMM_ParentOnly) {
673 for (
const auto &Parent :
678 if (Visited.insert(Parent.getMemoizationData()).second)
679 Queue.push_back(Parent);
686 MemoizedMatchResult &CachedResult =
ResultCache[Key];
687 CachedResult = std::move(Result);
689 *Builder = CachedResult.Nodes;
690 return CachedResult.ResultOfMatch;
695 class MatchVisitor :
public BoundNodesTreeBuilder::Visitor {
697 MatchVisitor(ASTContext*
Context,
698 MatchFinder::MatchCallback*
Callback)
700 Callback(Callback) {}
702 void visitMatch(
const BoundNodes& BoundNodesView)
override {
712 bool typeHasMatchingAlias(
const Type *TypeNode,
713 const Matcher<NamedDecl> Matcher,
714 BoundNodesTreeBuilder *Builder) {
715 const Type *
const CanonicalType =
717 for (
const TypedefNameDecl *Alias :
TypeAliases.lookup(CanonicalType)) {
718 BoundNodesTreeBuilder Result(*Builder);
719 if (Matcher.matches(*Alias,
this, &Result)) {
720 *Builder = std::move(Result);
742 llvm::DenseMap<ast_type_traits::ASTNodeKind, std::vector<unsigned short>>
745 const MatchFinder::MatchFinderOptions &
Options;
749 llvm::DenseMap<const Type*, std::set<const TypedefNameDecl*> >
TypeAliases;
752 typedef std::map<MatchKey, MemoizedMatchResult> MemoizationMap;
756 static CXXRecordDecl *getAsCXXRecordDecl(
const Type *TypeNode) {
758 if (TypeNode->getAs<DependentNameType>() !=
nullptr ||
759 TypeNode->getAs<DependentTemplateSpecializationType>() !=
nullptr ||
760 TypeNode->getAs<TemplateTypeParmType>() !=
nullptr)
764 TemplateSpecializationType
const *TemplateType =
765 TypeNode->getAs<TemplateSpecializationType>();
767 return TypeNode->getAsCXXRecordDecl();
769 if (TemplateType->getTemplateName().isDependent())
783 CXXRecordDecl *SpecializationDecl = TemplateType->getAsCXXRecordDecl();
784 if (SpecializationDecl) {
785 return SpecializationDecl;
787 NamedDecl *Templated =
788 TemplateType->getTemplateName().getAsTemplateDecl()->getTemplatedDecl();
789 if (CXXRecordDecl *TemplatedRecord = dyn_cast<CXXRecordDecl>(Templated)) {
790 return TemplatedRecord;
793 TypeAliasDecl *AliasDecl = dyn_cast<TypeAliasDecl>(Templated);
795 return getAsCXXRecordDecl(AliasDecl->getUnderlyingType().getTypePtr());
801 bool MatchASTVisitor::classIsDerivedFrom(
const CXXRecordDecl *Declaration,
802 const Matcher<NamedDecl> &
Base,
803 BoundNodesTreeBuilder *Builder) {
804 if (!Declaration->hasDefinition())
806 for (
const auto &It : Declaration->bases()) {
807 const Type *TypeNode = It.getType().getTypePtr();
809 if (typeHasMatchingAlias(TypeNode, Base, Builder))
812 CXXRecordDecl *ClassDecl = getAsCXXRecordDecl(TypeNode);
815 if (ClassDecl == Declaration) {
820 BoundNodesTreeBuilder Result(*Builder);
821 if (Base.matches(*ClassDecl,
this, &Result)) {
822 *Builder = std::move(Result);
825 if (classIsDerivedFrom(ClassDecl, Base, Builder))
831 bool MatchASTVisitor::TraverseDecl(Decl *DeclNode) {
839 bool MatchASTVisitor::TraverseStmt(
Stmt *StmtNode) {
847 bool MatchASTVisitor::TraverseType(QualType TypeNode) {
852 bool MatchASTVisitor::TraverseTypeLoc(TypeLoc TypeLocNode) {
859 match(TypeLocNode.getType());
863 bool MatchASTVisitor::TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {
868 bool MatchASTVisitor::TraverseNestedNameSpecifierLoc(
869 NestedNameSpecifierLoc NNS) {
873 if (NNS.hasQualifier())
874 match(*NNS.getNestedNameSpecifier());
879 class MatchASTConsumer :
public ASTConsumer {
881 MatchASTConsumer(MatchFinder *Finder,
883 : Finder(Finder), ParsingDone(ParsingDone) {}
886 void HandleTranslationUnit(ASTContext &
Context)
override {
890 Finder->matchAST(Context);
902 : Nodes(Nodes), Context(Context),
909 : Options(std::move(Options)), ParsingDone(nullptr) {}
915 Matchers.DeclOrStmt.emplace_back(NodeMatch, Action);
916 Matchers.AllCallbacks.push_back(Action);
921 Matchers.Type.emplace_back(NodeMatch, Action);
922 Matchers.AllCallbacks.push_back(Action);
927 Matchers.DeclOrStmt.emplace_back(NodeMatch, Action);
928 Matchers.AllCallbacks.push_back(Action);
933 Matchers.NestedNameSpecifier.emplace_back(NodeMatch, Action);
934 Matchers.AllCallbacks.push_back(Action);
939 Matchers.NestedNameSpecifierLoc.emplace_back(NodeMatch, Action);
940 Matchers.AllCallbacks.push_back(Action);
945 Matchers.TypeLoc.emplace_back(NodeMatch, Action);
946 Matchers.AllCallbacks.push_back(Action);
951 if (NodeMatch.canConvertTo<
Decl>()) {
954 }
else if (NodeMatch.canConvertTo<
QualType>()) {
957 }
else if (NodeMatch.canConvertTo<
Stmt>()) {
966 }
else if (NodeMatch.canConvertTo<
TypeLoc>()) {
974 return llvm::make_unique<internal::MatchASTConsumer>(
this, ParsingDone);
979 internal::MatchASTVisitor Visitor(&Matchers, Options);
980 Visitor.set_active_ast_context(&Context);
985 internal::MatchASTVisitor Visitor(&Matchers, Options);
986 Visitor.set_active_ast_context(&Context);
987 Visitor.onStartOfTranslationUnit();
989 Visitor.onEndOfTranslationUnit();
994 ParsingDone = NewParsingDone;
Defines the clang::ASTContext interface.
const MatchFinder::MatchersByType * Matchers
MatchFinder::ParsingDoneTestCallback * ParsingDone
internal::Matcher< Decl > DeclarationMatcher
Types of matchers for the top-level classes in the AST class hierarchy.
const DynTypedMatcher *const Matcher
Called when parsing is finished. Intended for testing only.
MatchFinder(MatchFinderOptions Options=MatchFinderOptions())
BoundNodesTreeBuilder Nodes
bool TraverseDecl(Decl *D)
Recursively visit a declaration, by dispatching to Traverse*Decl() based on the argument's dynamic ty...
Base wrapper for a particular "section" of type source info.
virtual ~ParsingDoneTestCallback()
void match(const T &Node, ASTContext &Context)
Calls the registered callbacks on all matches on the given Node.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
A C++ nested-name-specifier augmented with source location information.
const ASTMatchFinder::BindKind Bind
ASTContext * ActiveASTContext
#define RecursiveASTVisitor
void addMatcher(const DeclarationMatcher &NodeMatch, MatchCallback *Action)
Adds a matcher to execute when running over the AST.
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
internal::Matcher< Stmt > StatementMatcher
BoundNodesTreeBuilder ResultBindings
DynTypedMatcher::MatcherIDType MatcherID
internal::Matcher< NestedNameSpecifierLoc > NestedNameSpecifierLocMatcher
virtual StringRef getID() const
An id used to group the matchers.
MatchFinder::MatchCallback * Callback
TranslationUnitDecl * getTranslationUnitDecl() const
llvm::DenseMap< ast_type_traits::ASTNodeKind, std::vector< unsigned short > > MatcherFiltersMap
Filtered list of matcher indices for each matcher kind.
void registerTestCallbackAfterParsing(ParsingDoneTestCallback *ParsingDone)
Registers a callback to notify the end of parsing.
MatchResult(const BoundNodes &Nodes, clang::ASTContext *Context)
The result type of a method or function.
std::unique_ptr< clang::ASTConsumer > newASTConsumer()
Creates a clang ASTConsumer that finds all matches.
Maps string IDs to AST nodes matched by parts of a matcher.
const MatchFinder::MatchFinderOptions & Options
ASTMatchFinder *const Finder
bool TraverseTypeLoc(TypeLoc TL)
Recursively visit a type with location, by dispatching to Traverse*TypeLoc() based on the argument ty...
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS)
Recursively visit a C++ nested-name-specifier with location information.
const ASTMatchFinder::TraversalKind Traversal
Represents a C++ nested name specifier, such as "\::std::vector<int>::".
internal::Matcher< TypeLoc > TypeLocMatcher
void matchAST(ASTContext &Context)
Finds all matches in the given AST.
bool operator<(DeclarationName LHS, DeclarationName RHS)
bool TraverseType(QualType T)
Recursively visit a type, by dispatching to Traverse*Type() based on the argument's getTypeClass() pr...
static DynTypedNode create(const T &Node)
Creates a DynTypedNode from Node.
BoundNodesTreeBuilder BoundNodes
ast_type_traits::DynTypedNode Node
internal::Matcher< NestedNameSpecifier > NestedNameSpecifierMatcher
A dynamically typed AST node container.
bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS)
Recursively visit a C++ nested-name-specifier.
MemoizationMap ResultCache
internal::Matcher< QualType > TypeMatcher
BoundNodesTreeBuilder *const Builder
bool TraverseStmt(Stmt *S)
Recursively visit a statement or expression, by dispatching to Traverse*() based on the argument's dy...
llvm::DenseMap< const Type *, std::set< const TypedefNameDecl * > > TypeAliases
This class handles loading and caching of source files into memory.
bool addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch, MatchCallback *Action)
Adds a matcher to execute when running over the AST.
llvm::StringMap< llvm::TimeRecord > TimeByBucket
Bucket to record map.
llvm::TimeRecord * Bucket