1f4a2713aSLionel Sambuc //===--- ASTMatchFinder.cpp - Structural query framework ------------------===//
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc // The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc //
10f4a2713aSLionel Sambuc // Implements an algorithm to efficiently search for matches on AST nodes.
11f4a2713aSLionel Sambuc // Uses memoization to support recursive matches like HasDescendant.
12f4a2713aSLionel Sambuc //
13f4a2713aSLionel Sambuc // The general idea is to visit all AST nodes with a RecursiveASTVisitor,
14f4a2713aSLionel Sambuc // calling the Matches(...) method of each matcher we are running on each
15f4a2713aSLionel Sambuc // AST node. The matcher can recurse via the ASTMatchFinder interface.
16f4a2713aSLionel Sambuc //
17f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
18f4a2713aSLionel Sambuc
19f4a2713aSLionel Sambuc #include "clang/ASTMatchers/ASTMatchFinder.h"
20f4a2713aSLionel Sambuc #include "clang/AST/ASTConsumer.h"
21f4a2713aSLionel Sambuc #include "clang/AST/ASTContext.h"
22f4a2713aSLionel Sambuc #include "clang/AST/RecursiveASTVisitor.h"
23*0a6a1f1dSLionel Sambuc #include "llvm/ADT/DenseMap.h"
24*0a6a1f1dSLionel Sambuc #include "llvm/ADT/StringMap.h"
25*0a6a1f1dSLionel Sambuc #include "llvm/Support/Timer.h"
26f4a2713aSLionel Sambuc #include <deque>
27*0a6a1f1dSLionel Sambuc #include <memory>
28f4a2713aSLionel Sambuc #include <set>
29f4a2713aSLionel Sambuc
30f4a2713aSLionel Sambuc namespace clang {
31f4a2713aSLionel Sambuc namespace ast_matchers {
32f4a2713aSLionel Sambuc namespace internal {
33f4a2713aSLionel Sambuc namespace {
34f4a2713aSLionel Sambuc
35f4a2713aSLionel Sambuc typedef MatchFinder::MatchCallback MatchCallback;
36f4a2713aSLionel Sambuc
37f4a2713aSLionel Sambuc // The maximum number of memoization entries to store.
38f4a2713aSLionel Sambuc // 10k has been experimentally found to give a good trade-off
39f4a2713aSLionel Sambuc // of performance vs. memory consumption by running matcher
40f4a2713aSLionel Sambuc // that match on every statement over a very large codebase.
41f4a2713aSLionel Sambuc //
42f4a2713aSLionel Sambuc // FIXME: Do some performance optimization in general and
43f4a2713aSLionel Sambuc // revisit this number; also, put up micro-benchmarks that we can
44f4a2713aSLionel Sambuc // optimize this on.
45f4a2713aSLionel Sambuc static const unsigned MaxMemoizationEntries = 10000;
46f4a2713aSLionel Sambuc
47f4a2713aSLionel Sambuc // We use memoization to avoid running the same matcher on the same
48f4a2713aSLionel Sambuc // AST node twice. This struct is the key for looking up match
49f4a2713aSLionel Sambuc // result. It consists of an ID of the MatcherInterface (for
50f4a2713aSLionel Sambuc // identifying the matcher), a pointer to the AST node and the
51f4a2713aSLionel Sambuc // bound nodes before the matcher was executed.
52f4a2713aSLionel Sambuc //
53f4a2713aSLionel Sambuc // We currently only memoize on nodes whose pointers identify the
54f4a2713aSLionel Sambuc // nodes (\c Stmt and \c Decl, but not \c QualType or \c TypeLoc).
55f4a2713aSLionel Sambuc // For \c QualType and \c TypeLoc it is possible to implement
56f4a2713aSLionel Sambuc // generation of keys for each type.
57f4a2713aSLionel Sambuc // FIXME: Benchmark whether memoization of non-pointer typed nodes
58f4a2713aSLionel Sambuc // provides enough benefit for the additional amount of code.
59f4a2713aSLionel Sambuc struct MatchKey {
60*0a6a1f1dSLionel Sambuc DynTypedMatcher::MatcherIDType MatcherID;
61f4a2713aSLionel Sambuc ast_type_traits::DynTypedNode Node;
62f4a2713aSLionel Sambuc BoundNodesTreeBuilder BoundNodes;
63f4a2713aSLionel Sambuc
operator <clang::ast_matchers::internal::__anon0cad00880111::MatchKey64f4a2713aSLionel Sambuc bool operator<(const MatchKey &Other) const {
65*0a6a1f1dSLionel Sambuc return std::tie(MatcherID, Node, BoundNodes) <
66*0a6a1f1dSLionel Sambuc std::tie(Other.MatcherID, Other.Node, Other.BoundNodes);
67f4a2713aSLionel Sambuc }
68f4a2713aSLionel Sambuc };
69f4a2713aSLionel Sambuc
70f4a2713aSLionel Sambuc // Used to store the result of a match and possibly bound nodes.
71f4a2713aSLionel Sambuc struct MemoizedMatchResult {
72f4a2713aSLionel Sambuc bool ResultOfMatch;
73f4a2713aSLionel Sambuc BoundNodesTreeBuilder Nodes;
74f4a2713aSLionel Sambuc };
75f4a2713aSLionel Sambuc
76f4a2713aSLionel Sambuc // A RecursiveASTVisitor that traverses all children or all descendants of
77f4a2713aSLionel Sambuc // a node.
78f4a2713aSLionel Sambuc class MatchChildASTVisitor
79f4a2713aSLionel Sambuc : public RecursiveASTVisitor<MatchChildASTVisitor> {
80f4a2713aSLionel Sambuc public:
81f4a2713aSLionel Sambuc typedef RecursiveASTVisitor<MatchChildASTVisitor> VisitorBase;
82f4a2713aSLionel Sambuc
83f4a2713aSLionel Sambuc // Creates an AST visitor that matches 'matcher' on all children or
84f4a2713aSLionel Sambuc // descendants of a traversed node. max_depth is the maximum depth
85f4a2713aSLionel Sambuc // to traverse: use 1 for matching the children and INT_MAX for
86f4a2713aSLionel Sambuc // matching the descendants.
MatchChildASTVisitor(const DynTypedMatcher * Matcher,ASTMatchFinder * Finder,BoundNodesTreeBuilder * Builder,int MaxDepth,ASTMatchFinder::TraversalKind Traversal,ASTMatchFinder::BindKind Bind)87f4a2713aSLionel Sambuc MatchChildASTVisitor(const DynTypedMatcher *Matcher,
88f4a2713aSLionel Sambuc ASTMatchFinder *Finder,
89f4a2713aSLionel Sambuc BoundNodesTreeBuilder *Builder,
90f4a2713aSLionel Sambuc int MaxDepth,
91f4a2713aSLionel Sambuc ASTMatchFinder::TraversalKind Traversal,
92f4a2713aSLionel Sambuc ASTMatchFinder::BindKind Bind)
93f4a2713aSLionel Sambuc : Matcher(Matcher),
94f4a2713aSLionel Sambuc Finder(Finder),
95f4a2713aSLionel Sambuc Builder(Builder),
96f4a2713aSLionel Sambuc CurrentDepth(0),
97f4a2713aSLionel Sambuc MaxDepth(MaxDepth),
98f4a2713aSLionel Sambuc Traversal(Traversal),
99f4a2713aSLionel Sambuc Bind(Bind),
100f4a2713aSLionel Sambuc Matches(false) {}
101f4a2713aSLionel Sambuc
102f4a2713aSLionel Sambuc // Returns true if a match is found in the subtree rooted at the
103f4a2713aSLionel Sambuc // given AST node. This is done via a set of mutually recursive
104f4a2713aSLionel Sambuc // functions. Here's how the recursion is done (the *wildcard can
105f4a2713aSLionel Sambuc // actually be Decl, Stmt, or Type):
106f4a2713aSLionel Sambuc //
107f4a2713aSLionel Sambuc // - Traverse(node) calls BaseTraverse(node) when it needs
108f4a2713aSLionel Sambuc // to visit the descendants of node.
109f4a2713aSLionel Sambuc // - BaseTraverse(node) then calls (via VisitorBase::Traverse*(node))
110f4a2713aSLionel Sambuc // Traverse*(c) for each child c of 'node'.
111f4a2713aSLionel Sambuc // - Traverse*(c) in turn calls Traverse(c), completing the
112f4a2713aSLionel Sambuc // recursion.
findMatch(const ast_type_traits::DynTypedNode & DynNode)113f4a2713aSLionel Sambuc bool findMatch(const ast_type_traits::DynTypedNode &DynNode) {
114f4a2713aSLionel Sambuc reset();
115f4a2713aSLionel Sambuc if (const Decl *D = DynNode.get<Decl>())
116f4a2713aSLionel Sambuc traverse(*D);
117f4a2713aSLionel Sambuc else if (const Stmt *S = DynNode.get<Stmt>())
118f4a2713aSLionel Sambuc traverse(*S);
119f4a2713aSLionel Sambuc else if (const NestedNameSpecifier *NNS =
120f4a2713aSLionel Sambuc DynNode.get<NestedNameSpecifier>())
121f4a2713aSLionel Sambuc traverse(*NNS);
122f4a2713aSLionel Sambuc else if (const NestedNameSpecifierLoc *NNSLoc =
123f4a2713aSLionel Sambuc DynNode.get<NestedNameSpecifierLoc>())
124f4a2713aSLionel Sambuc traverse(*NNSLoc);
125f4a2713aSLionel Sambuc else if (const QualType *Q = DynNode.get<QualType>())
126f4a2713aSLionel Sambuc traverse(*Q);
127f4a2713aSLionel Sambuc else if (const TypeLoc *T = DynNode.get<TypeLoc>())
128f4a2713aSLionel Sambuc traverse(*T);
129f4a2713aSLionel Sambuc // FIXME: Add other base types after adding tests.
130f4a2713aSLionel Sambuc
131f4a2713aSLionel Sambuc // It's OK to always overwrite the bound nodes, as if there was
132f4a2713aSLionel Sambuc // no match in this recursive branch, the result set is empty
133f4a2713aSLionel Sambuc // anyway.
134f4a2713aSLionel Sambuc *Builder = ResultBindings;
135f4a2713aSLionel Sambuc
136f4a2713aSLionel Sambuc return Matches;
137f4a2713aSLionel Sambuc }
138f4a2713aSLionel Sambuc
139f4a2713aSLionel Sambuc // The following are overriding methods from the base visitor class.
140f4a2713aSLionel Sambuc // They are public only to allow CRTP to work. They are *not *part
141f4a2713aSLionel Sambuc // of the public API of this class.
TraverseDecl(Decl * DeclNode)142f4a2713aSLionel Sambuc bool TraverseDecl(Decl *DeclNode) {
143f4a2713aSLionel Sambuc ScopedIncrement ScopedDepth(&CurrentDepth);
144*0a6a1f1dSLionel Sambuc return (DeclNode == nullptr) || traverse(*DeclNode);
145f4a2713aSLionel Sambuc }
TraverseStmt(Stmt * StmtNode)146f4a2713aSLionel Sambuc bool TraverseStmt(Stmt *StmtNode) {
147f4a2713aSLionel Sambuc ScopedIncrement ScopedDepth(&CurrentDepth);
148f4a2713aSLionel Sambuc const Stmt *StmtToTraverse = StmtNode;
149f4a2713aSLionel Sambuc if (Traversal ==
150f4a2713aSLionel Sambuc ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses) {
151f4a2713aSLionel Sambuc const Expr *ExprNode = dyn_cast_or_null<Expr>(StmtNode);
152*0a6a1f1dSLionel Sambuc if (ExprNode) {
153f4a2713aSLionel Sambuc StmtToTraverse = ExprNode->IgnoreParenImpCasts();
154f4a2713aSLionel Sambuc }
155f4a2713aSLionel Sambuc }
156*0a6a1f1dSLionel Sambuc return (StmtToTraverse == nullptr) || traverse(*StmtToTraverse);
157f4a2713aSLionel Sambuc }
158f4a2713aSLionel Sambuc // We assume that the QualType and the contained type are on the same
159f4a2713aSLionel Sambuc // hierarchy level. Thus, we try to match either of them.
TraverseType(QualType TypeNode)160f4a2713aSLionel Sambuc bool TraverseType(QualType TypeNode) {
161f4a2713aSLionel Sambuc if (TypeNode.isNull())
162f4a2713aSLionel Sambuc return true;
163f4a2713aSLionel Sambuc ScopedIncrement ScopedDepth(&CurrentDepth);
164f4a2713aSLionel Sambuc // Match the Type.
165f4a2713aSLionel Sambuc if (!match(*TypeNode))
166f4a2713aSLionel Sambuc return false;
167f4a2713aSLionel Sambuc // The QualType is matched inside traverse.
168f4a2713aSLionel Sambuc return traverse(TypeNode);
169f4a2713aSLionel Sambuc }
170f4a2713aSLionel Sambuc // We assume that the TypeLoc, contained QualType and contained Type all are
171f4a2713aSLionel Sambuc // on the same hierarchy level. Thus, we try to match all of them.
TraverseTypeLoc(TypeLoc TypeLocNode)172f4a2713aSLionel Sambuc bool TraverseTypeLoc(TypeLoc TypeLocNode) {
173f4a2713aSLionel Sambuc if (TypeLocNode.isNull())
174f4a2713aSLionel Sambuc return true;
175f4a2713aSLionel Sambuc ScopedIncrement ScopedDepth(&CurrentDepth);
176f4a2713aSLionel Sambuc // Match the Type.
177f4a2713aSLionel Sambuc if (!match(*TypeLocNode.getType()))
178f4a2713aSLionel Sambuc return false;
179f4a2713aSLionel Sambuc // Match the QualType.
180f4a2713aSLionel Sambuc if (!match(TypeLocNode.getType()))
181f4a2713aSLionel Sambuc return false;
182f4a2713aSLionel Sambuc // The TypeLoc is matched inside traverse.
183f4a2713aSLionel Sambuc return traverse(TypeLocNode);
184f4a2713aSLionel Sambuc }
TraverseNestedNameSpecifier(NestedNameSpecifier * NNS)185f4a2713aSLionel Sambuc bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {
186f4a2713aSLionel Sambuc ScopedIncrement ScopedDepth(&CurrentDepth);
187*0a6a1f1dSLionel Sambuc return (NNS == nullptr) || traverse(*NNS);
188f4a2713aSLionel Sambuc }
TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS)189f4a2713aSLionel Sambuc bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
190f4a2713aSLionel Sambuc if (!NNS)
191f4a2713aSLionel Sambuc return true;
192f4a2713aSLionel Sambuc ScopedIncrement ScopedDepth(&CurrentDepth);
193f4a2713aSLionel Sambuc if (!match(*NNS.getNestedNameSpecifier()))
194f4a2713aSLionel Sambuc return false;
195f4a2713aSLionel Sambuc return traverse(NNS);
196f4a2713aSLionel Sambuc }
197f4a2713aSLionel Sambuc
shouldVisitTemplateInstantiations() const198f4a2713aSLionel Sambuc bool shouldVisitTemplateInstantiations() const { return true; }
shouldVisitImplicitCode() const199f4a2713aSLionel Sambuc bool shouldVisitImplicitCode() const { return true; }
200f4a2713aSLionel Sambuc // Disables data recursion. We intercept Traverse* methods in the RAV, which
201f4a2713aSLionel Sambuc // are not triggered during data recursion.
shouldUseDataRecursionFor(clang::Stmt * S) const202f4a2713aSLionel Sambuc bool shouldUseDataRecursionFor(clang::Stmt *S) const { return false; }
203f4a2713aSLionel Sambuc
204f4a2713aSLionel Sambuc private:
205f4a2713aSLionel Sambuc // Used for updating the depth during traversal.
206f4a2713aSLionel Sambuc struct ScopedIncrement {
ScopedIncrementclang::ast_matchers::internal::__anon0cad00880111::MatchChildASTVisitor::ScopedIncrement207f4a2713aSLionel Sambuc explicit ScopedIncrement(int *Depth) : Depth(Depth) { ++(*Depth); }
~ScopedIncrementclang::ast_matchers::internal::__anon0cad00880111::MatchChildASTVisitor::ScopedIncrement208f4a2713aSLionel Sambuc ~ScopedIncrement() { --(*Depth); }
209f4a2713aSLionel Sambuc
210f4a2713aSLionel Sambuc private:
211f4a2713aSLionel Sambuc int *Depth;
212f4a2713aSLionel Sambuc };
213f4a2713aSLionel Sambuc
214f4a2713aSLionel Sambuc // Resets the state of this object.
reset()215f4a2713aSLionel Sambuc void reset() {
216f4a2713aSLionel Sambuc Matches = false;
217f4a2713aSLionel Sambuc CurrentDepth = 0;
218f4a2713aSLionel Sambuc }
219f4a2713aSLionel Sambuc
220f4a2713aSLionel Sambuc // Forwards the call to the corresponding Traverse*() method in the
221f4a2713aSLionel Sambuc // base visitor class.
baseTraverse(const Decl & DeclNode)222f4a2713aSLionel Sambuc bool baseTraverse(const Decl &DeclNode) {
223f4a2713aSLionel Sambuc return VisitorBase::TraverseDecl(const_cast<Decl*>(&DeclNode));
224f4a2713aSLionel Sambuc }
baseTraverse(const Stmt & StmtNode)225f4a2713aSLionel Sambuc bool baseTraverse(const Stmt &StmtNode) {
226f4a2713aSLionel Sambuc return VisitorBase::TraverseStmt(const_cast<Stmt*>(&StmtNode));
227f4a2713aSLionel Sambuc }
baseTraverse(QualType TypeNode)228f4a2713aSLionel Sambuc bool baseTraverse(QualType TypeNode) {
229f4a2713aSLionel Sambuc return VisitorBase::TraverseType(TypeNode);
230f4a2713aSLionel Sambuc }
baseTraverse(TypeLoc TypeLocNode)231f4a2713aSLionel Sambuc bool baseTraverse(TypeLoc TypeLocNode) {
232f4a2713aSLionel Sambuc return VisitorBase::TraverseTypeLoc(TypeLocNode);
233f4a2713aSLionel Sambuc }
baseTraverse(const NestedNameSpecifier & NNS)234f4a2713aSLionel Sambuc bool baseTraverse(const NestedNameSpecifier &NNS) {
235f4a2713aSLionel Sambuc return VisitorBase::TraverseNestedNameSpecifier(
236f4a2713aSLionel Sambuc const_cast<NestedNameSpecifier*>(&NNS));
237f4a2713aSLionel Sambuc }
baseTraverse(NestedNameSpecifierLoc NNS)238f4a2713aSLionel Sambuc bool baseTraverse(NestedNameSpecifierLoc NNS) {
239f4a2713aSLionel Sambuc return VisitorBase::TraverseNestedNameSpecifierLoc(NNS);
240f4a2713aSLionel Sambuc }
241f4a2713aSLionel Sambuc
242f4a2713aSLionel Sambuc // Sets 'Matched' to true if 'Matcher' matches 'Node' and:
243f4a2713aSLionel Sambuc // 0 < CurrentDepth <= MaxDepth.
244f4a2713aSLionel Sambuc //
245f4a2713aSLionel Sambuc // Returns 'true' if traversal should continue after this function
246f4a2713aSLionel Sambuc // returns, i.e. if no match is found or 'Bind' is 'BK_All'.
247f4a2713aSLionel Sambuc template <typename T>
match(const T & Node)248f4a2713aSLionel Sambuc bool match(const T &Node) {
249f4a2713aSLionel Sambuc if (CurrentDepth == 0 || CurrentDepth > MaxDepth) {
250f4a2713aSLionel Sambuc return true;
251f4a2713aSLionel Sambuc }
252f4a2713aSLionel Sambuc if (Bind != ASTMatchFinder::BK_All) {
253f4a2713aSLionel Sambuc BoundNodesTreeBuilder RecursiveBuilder(*Builder);
254f4a2713aSLionel Sambuc if (Matcher->matches(ast_type_traits::DynTypedNode::create(Node), Finder,
255f4a2713aSLionel Sambuc &RecursiveBuilder)) {
256f4a2713aSLionel Sambuc Matches = true;
257f4a2713aSLionel Sambuc ResultBindings.addMatch(RecursiveBuilder);
258f4a2713aSLionel Sambuc return false; // Abort as soon as a match is found.
259f4a2713aSLionel Sambuc }
260f4a2713aSLionel Sambuc } else {
261f4a2713aSLionel Sambuc BoundNodesTreeBuilder RecursiveBuilder(*Builder);
262f4a2713aSLionel Sambuc if (Matcher->matches(ast_type_traits::DynTypedNode::create(Node), Finder,
263f4a2713aSLionel Sambuc &RecursiveBuilder)) {
264f4a2713aSLionel Sambuc // After the first match the matcher succeeds.
265f4a2713aSLionel Sambuc Matches = true;
266f4a2713aSLionel Sambuc ResultBindings.addMatch(RecursiveBuilder);
267f4a2713aSLionel Sambuc }
268f4a2713aSLionel Sambuc }
269f4a2713aSLionel Sambuc return true;
270f4a2713aSLionel Sambuc }
271f4a2713aSLionel Sambuc
272f4a2713aSLionel Sambuc // Traverses the subtree rooted at 'Node'; returns true if the
273f4a2713aSLionel Sambuc // traversal should continue after this function returns.
274f4a2713aSLionel Sambuc template <typename T>
traverse(const T & Node)275f4a2713aSLionel Sambuc bool traverse(const T &Node) {
276*0a6a1f1dSLionel Sambuc static_assert(IsBaseType<T>::value,
277*0a6a1f1dSLionel Sambuc "traverse can only be instantiated with base type");
278f4a2713aSLionel Sambuc if (!match(Node))
279f4a2713aSLionel Sambuc return false;
280f4a2713aSLionel Sambuc return baseTraverse(Node);
281f4a2713aSLionel Sambuc }
282f4a2713aSLionel Sambuc
283f4a2713aSLionel Sambuc const DynTypedMatcher *const Matcher;
284f4a2713aSLionel Sambuc ASTMatchFinder *const Finder;
285f4a2713aSLionel Sambuc BoundNodesTreeBuilder *const Builder;
286f4a2713aSLionel Sambuc BoundNodesTreeBuilder ResultBindings;
287f4a2713aSLionel Sambuc int CurrentDepth;
288f4a2713aSLionel Sambuc const int MaxDepth;
289f4a2713aSLionel Sambuc const ASTMatchFinder::TraversalKind Traversal;
290f4a2713aSLionel Sambuc const ASTMatchFinder::BindKind Bind;
291f4a2713aSLionel Sambuc bool Matches;
292f4a2713aSLionel Sambuc };
293f4a2713aSLionel Sambuc
294f4a2713aSLionel Sambuc // Controls the outermost traversal of the AST and allows to match multiple
295f4a2713aSLionel Sambuc // matchers.
296f4a2713aSLionel Sambuc class MatchASTVisitor : public RecursiveASTVisitor<MatchASTVisitor>,
297f4a2713aSLionel Sambuc public ASTMatchFinder {
298f4a2713aSLionel Sambuc public:
MatchASTVisitor(const MatchFinder::MatchersByType * Matchers,const MatchFinder::MatchFinderOptions & Options)299*0a6a1f1dSLionel Sambuc MatchASTVisitor(const MatchFinder::MatchersByType *Matchers,
300*0a6a1f1dSLionel Sambuc const MatchFinder::MatchFinderOptions &Options)
301*0a6a1f1dSLionel Sambuc : Matchers(Matchers), Options(Options), ActiveASTContext(nullptr) {}
302*0a6a1f1dSLionel Sambuc
~MatchASTVisitor()303*0a6a1f1dSLionel Sambuc ~MatchASTVisitor() {
304*0a6a1f1dSLionel Sambuc if (Options.CheckProfiling) {
305*0a6a1f1dSLionel Sambuc Options.CheckProfiling->Records = std::move(TimeByBucket);
306*0a6a1f1dSLionel Sambuc }
307*0a6a1f1dSLionel Sambuc }
308f4a2713aSLionel Sambuc
onStartOfTranslationUnit()309f4a2713aSLionel Sambuc void onStartOfTranslationUnit() {
310*0a6a1f1dSLionel Sambuc const bool EnableCheckProfiling = Options.CheckProfiling.hasValue();
311*0a6a1f1dSLionel Sambuc TimeBucketRegion Timer;
312*0a6a1f1dSLionel Sambuc for (MatchCallback *MC : Matchers->AllCallbacks) {
313*0a6a1f1dSLionel Sambuc if (EnableCheckProfiling)
314*0a6a1f1dSLionel Sambuc Timer.setBucket(&TimeByBucket[MC->getID()]);
315*0a6a1f1dSLionel Sambuc MC->onStartOfTranslationUnit();
316f4a2713aSLionel Sambuc }
317f4a2713aSLionel Sambuc }
318f4a2713aSLionel Sambuc
onEndOfTranslationUnit()319f4a2713aSLionel Sambuc void onEndOfTranslationUnit() {
320*0a6a1f1dSLionel Sambuc const bool EnableCheckProfiling = Options.CheckProfiling.hasValue();
321*0a6a1f1dSLionel Sambuc TimeBucketRegion Timer;
322*0a6a1f1dSLionel Sambuc for (MatchCallback *MC : Matchers->AllCallbacks) {
323*0a6a1f1dSLionel Sambuc if (EnableCheckProfiling)
324*0a6a1f1dSLionel Sambuc Timer.setBucket(&TimeByBucket[MC->getID()]);
325*0a6a1f1dSLionel Sambuc MC->onEndOfTranslationUnit();
326f4a2713aSLionel Sambuc }
327f4a2713aSLionel Sambuc }
328f4a2713aSLionel Sambuc
set_active_ast_context(ASTContext * NewActiveASTContext)329f4a2713aSLionel Sambuc void set_active_ast_context(ASTContext *NewActiveASTContext) {
330f4a2713aSLionel Sambuc ActiveASTContext = NewActiveASTContext;
331f4a2713aSLionel Sambuc }
332f4a2713aSLionel Sambuc
333f4a2713aSLionel Sambuc // The following Visit*() and Traverse*() functions "override"
334f4a2713aSLionel Sambuc // methods in RecursiveASTVisitor.
335f4a2713aSLionel Sambuc
VisitTypedefNameDecl(TypedefNameDecl * DeclNode)336f4a2713aSLionel Sambuc bool VisitTypedefNameDecl(TypedefNameDecl *DeclNode) {
337f4a2713aSLionel Sambuc // When we see 'typedef A B', we add name 'B' to the set of names
338f4a2713aSLionel Sambuc // A's canonical type maps to. This is necessary for implementing
339f4a2713aSLionel Sambuc // isDerivedFrom(x) properly, where x can be the name of the base
340f4a2713aSLionel Sambuc // class or any of its aliases.
341f4a2713aSLionel Sambuc //
342f4a2713aSLionel Sambuc // In general, the is-alias-of (as defined by typedefs) relation
343f4a2713aSLionel Sambuc // is tree-shaped, as you can typedef a type more than once. For
344f4a2713aSLionel Sambuc // example,
345f4a2713aSLionel Sambuc //
346f4a2713aSLionel Sambuc // typedef A B;
347f4a2713aSLionel Sambuc // typedef A C;
348f4a2713aSLionel Sambuc // typedef C D;
349f4a2713aSLionel Sambuc // typedef C E;
350f4a2713aSLionel Sambuc //
351f4a2713aSLionel Sambuc // gives you
352f4a2713aSLionel Sambuc //
353f4a2713aSLionel Sambuc // A
354f4a2713aSLionel Sambuc // |- B
355f4a2713aSLionel Sambuc // `- C
356f4a2713aSLionel Sambuc // |- D
357f4a2713aSLionel Sambuc // `- E
358f4a2713aSLionel Sambuc //
359f4a2713aSLionel Sambuc // It is wrong to assume that the relation is a chain. A correct
360f4a2713aSLionel Sambuc // implementation of isDerivedFrom() needs to recognize that B and
361f4a2713aSLionel Sambuc // E are aliases, even though neither is a typedef of the other.
362f4a2713aSLionel Sambuc // Therefore, we cannot simply walk through one typedef chain to
363f4a2713aSLionel Sambuc // find out whether the type name matches.
364f4a2713aSLionel Sambuc const Type *TypeNode = DeclNode->getUnderlyingType().getTypePtr();
365f4a2713aSLionel Sambuc const Type *CanonicalType = // root of the typedef tree
366f4a2713aSLionel Sambuc ActiveASTContext->getCanonicalType(TypeNode);
367f4a2713aSLionel Sambuc TypeAliases[CanonicalType].insert(DeclNode);
368f4a2713aSLionel Sambuc return true;
369f4a2713aSLionel Sambuc }
370f4a2713aSLionel Sambuc
371f4a2713aSLionel Sambuc bool TraverseDecl(Decl *DeclNode);
372f4a2713aSLionel Sambuc bool TraverseStmt(Stmt *StmtNode);
373f4a2713aSLionel Sambuc bool TraverseType(QualType TypeNode);
374f4a2713aSLionel Sambuc bool TraverseTypeLoc(TypeLoc TypeNode);
375f4a2713aSLionel Sambuc bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS);
376f4a2713aSLionel Sambuc bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);
377f4a2713aSLionel Sambuc
378f4a2713aSLionel Sambuc // Matches children or descendants of 'Node' with 'BaseMatcher'.
memoizedMatchesRecursively(const ast_type_traits::DynTypedNode & Node,const DynTypedMatcher & Matcher,BoundNodesTreeBuilder * Builder,int MaxDepth,TraversalKind Traversal,BindKind Bind)379f4a2713aSLionel Sambuc bool memoizedMatchesRecursively(const ast_type_traits::DynTypedNode &Node,
380f4a2713aSLionel Sambuc const DynTypedMatcher &Matcher,
381f4a2713aSLionel Sambuc BoundNodesTreeBuilder *Builder, int MaxDepth,
382f4a2713aSLionel Sambuc TraversalKind Traversal, BindKind Bind) {
383f4a2713aSLionel Sambuc // For AST-nodes that don't have an identity, we can't memoize.
384*0a6a1f1dSLionel Sambuc if (!Node.getMemoizationData() || !Builder->isComparable())
385f4a2713aSLionel Sambuc return matchesRecursively(Node, Matcher, Builder, MaxDepth, Traversal,
386f4a2713aSLionel Sambuc Bind);
387f4a2713aSLionel Sambuc
388f4a2713aSLionel Sambuc MatchKey Key;
389f4a2713aSLionel Sambuc Key.MatcherID = Matcher.getID();
390f4a2713aSLionel Sambuc Key.Node = Node;
391f4a2713aSLionel Sambuc // Note that we key on the bindings *before* the match.
392f4a2713aSLionel Sambuc Key.BoundNodes = *Builder;
393f4a2713aSLionel Sambuc
394f4a2713aSLionel Sambuc MemoizationMap::iterator I = ResultCache.find(Key);
395f4a2713aSLionel Sambuc if (I != ResultCache.end()) {
396f4a2713aSLionel Sambuc *Builder = I->second.Nodes;
397f4a2713aSLionel Sambuc return I->second.ResultOfMatch;
398f4a2713aSLionel Sambuc }
399f4a2713aSLionel Sambuc
400f4a2713aSLionel Sambuc MemoizedMatchResult Result;
401f4a2713aSLionel Sambuc Result.Nodes = *Builder;
402f4a2713aSLionel Sambuc Result.ResultOfMatch = matchesRecursively(Node, Matcher, &Result.Nodes,
403f4a2713aSLionel Sambuc MaxDepth, Traversal, Bind);
404*0a6a1f1dSLionel Sambuc
405*0a6a1f1dSLionel Sambuc MemoizedMatchResult &CachedResult = ResultCache[Key];
406*0a6a1f1dSLionel Sambuc CachedResult = std::move(Result);
407*0a6a1f1dSLionel Sambuc
408*0a6a1f1dSLionel Sambuc *Builder = CachedResult.Nodes;
409*0a6a1f1dSLionel Sambuc return CachedResult.ResultOfMatch;
410f4a2713aSLionel Sambuc }
411f4a2713aSLionel Sambuc
412f4a2713aSLionel Sambuc // Matches children or descendants of 'Node' with 'BaseMatcher'.
matchesRecursively(const ast_type_traits::DynTypedNode & Node,const DynTypedMatcher & Matcher,BoundNodesTreeBuilder * Builder,int MaxDepth,TraversalKind Traversal,BindKind Bind)413f4a2713aSLionel Sambuc bool matchesRecursively(const ast_type_traits::DynTypedNode &Node,
414f4a2713aSLionel Sambuc const DynTypedMatcher &Matcher,
415f4a2713aSLionel Sambuc BoundNodesTreeBuilder *Builder, int MaxDepth,
416f4a2713aSLionel Sambuc TraversalKind Traversal, BindKind Bind) {
417f4a2713aSLionel Sambuc MatchChildASTVisitor Visitor(
418f4a2713aSLionel Sambuc &Matcher, this, Builder, MaxDepth, Traversal, Bind);
419f4a2713aSLionel Sambuc return Visitor.findMatch(Node);
420f4a2713aSLionel Sambuc }
421f4a2713aSLionel Sambuc
422*0a6a1f1dSLionel Sambuc bool classIsDerivedFrom(const CXXRecordDecl *Declaration,
423f4a2713aSLionel Sambuc const Matcher<NamedDecl> &Base,
424*0a6a1f1dSLionel Sambuc BoundNodesTreeBuilder *Builder) override;
425f4a2713aSLionel Sambuc
426f4a2713aSLionel Sambuc // Implements ASTMatchFinder::matchesChildOf.
matchesChildOf(const ast_type_traits::DynTypedNode & Node,const DynTypedMatcher & Matcher,BoundNodesTreeBuilder * Builder,TraversalKind Traversal,BindKind Bind)427*0a6a1f1dSLionel Sambuc bool matchesChildOf(const ast_type_traits::DynTypedNode &Node,
428f4a2713aSLionel Sambuc const DynTypedMatcher &Matcher,
429f4a2713aSLionel Sambuc BoundNodesTreeBuilder *Builder,
430f4a2713aSLionel Sambuc TraversalKind Traversal,
431*0a6a1f1dSLionel Sambuc BindKind Bind) override {
432f4a2713aSLionel Sambuc if (ResultCache.size() > MaxMemoizationEntries)
433f4a2713aSLionel Sambuc ResultCache.clear();
434f4a2713aSLionel Sambuc return memoizedMatchesRecursively(Node, Matcher, Builder, 1, Traversal,
435f4a2713aSLionel Sambuc Bind);
436f4a2713aSLionel Sambuc }
437f4a2713aSLionel Sambuc // Implements ASTMatchFinder::matchesDescendantOf.
matchesDescendantOf(const ast_type_traits::DynTypedNode & Node,const DynTypedMatcher & Matcher,BoundNodesTreeBuilder * Builder,BindKind Bind)438*0a6a1f1dSLionel Sambuc bool matchesDescendantOf(const ast_type_traits::DynTypedNode &Node,
439f4a2713aSLionel Sambuc const DynTypedMatcher &Matcher,
440f4a2713aSLionel Sambuc BoundNodesTreeBuilder *Builder,
441*0a6a1f1dSLionel Sambuc BindKind Bind) override {
442f4a2713aSLionel Sambuc if (ResultCache.size() > MaxMemoizationEntries)
443f4a2713aSLionel Sambuc ResultCache.clear();
444f4a2713aSLionel Sambuc return memoizedMatchesRecursively(Node, Matcher, Builder, INT_MAX,
445f4a2713aSLionel Sambuc TK_AsIs, Bind);
446f4a2713aSLionel Sambuc }
447f4a2713aSLionel Sambuc // Implements ASTMatchFinder::matchesAncestorOf.
matchesAncestorOf(const ast_type_traits::DynTypedNode & Node,const DynTypedMatcher & Matcher,BoundNodesTreeBuilder * Builder,AncestorMatchMode MatchMode)448*0a6a1f1dSLionel Sambuc bool matchesAncestorOf(const ast_type_traits::DynTypedNode &Node,
449f4a2713aSLionel Sambuc const DynTypedMatcher &Matcher,
450f4a2713aSLionel Sambuc BoundNodesTreeBuilder *Builder,
451*0a6a1f1dSLionel Sambuc AncestorMatchMode MatchMode) override {
452f4a2713aSLionel Sambuc // Reset the cache outside of the recursive call to make sure we
453f4a2713aSLionel Sambuc // don't invalidate any iterators.
454f4a2713aSLionel Sambuc if (ResultCache.size() > MaxMemoizationEntries)
455f4a2713aSLionel Sambuc ResultCache.clear();
456f4a2713aSLionel Sambuc return memoizedMatchesAncestorOfRecursively(Node, Matcher, Builder,
457f4a2713aSLionel Sambuc MatchMode);
458f4a2713aSLionel Sambuc }
459f4a2713aSLionel Sambuc
460f4a2713aSLionel Sambuc // Matches all registered matchers on the given node and calls the
461f4a2713aSLionel Sambuc // result callback for every node that matches.
match(const ast_type_traits::DynTypedNode & Node)462f4a2713aSLionel Sambuc void match(const ast_type_traits::DynTypedNode &Node) {
463*0a6a1f1dSLionel Sambuc // FIXME: Improve this with a switch or a visitor pattern.
464*0a6a1f1dSLionel Sambuc if (auto *N = Node.get<Decl>()) {
465*0a6a1f1dSLionel Sambuc match(*N);
466*0a6a1f1dSLionel Sambuc } else if (auto *N = Node.get<Stmt>()) {
467*0a6a1f1dSLionel Sambuc match(*N);
468*0a6a1f1dSLionel Sambuc } else if (auto *N = Node.get<Type>()) {
469*0a6a1f1dSLionel Sambuc match(*N);
470*0a6a1f1dSLionel Sambuc } else if (auto *N = Node.get<QualType>()) {
471*0a6a1f1dSLionel Sambuc match(*N);
472*0a6a1f1dSLionel Sambuc } else if (auto *N = Node.get<NestedNameSpecifier>()) {
473*0a6a1f1dSLionel Sambuc match(*N);
474*0a6a1f1dSLionel Sambuc } else if (auto *N = Node.get<NestedNameSpecifierLoc>()) {
475*0a6a1f1dSLionel Sambuc match(*N);
476*0a6a1f1dSLionel Sambuc } else if (auto *N = Node.get<TypeLoc>()) {
477*0a6a1f1dSLionel Sambuc match(*N);
478f4a2713aSLionel Sambuc }
479f4a2713aSLionel Sambuc }
480f4a2713aSLionel Sambuc
match(const T & Node)481f4a2713aSLionel Sambuc template <typename T> void match(const T &Node) {
482*0a6a1f1dSLionel Sambuc matchDispatch(&Node);
483f4a2713aSLionel Sambuc }
484f4a2713aSLionel Sambuc
485f4a2713aSLionel Sambuc // Implements ASTMatchFinder::getASTContext.
getASTContext() const486*0a6a1f1dSLionel Sambuc ASTContext &getASTContext() const override { return *ActiveASTContext; }
487f4a2713aSLionel Sambuc
shouldVisitTemplateInstantiations() const488f4a2713aSLionel Sambuc bool shouldVisitTemplateInstantiations() const { return true; }
shouldVisitImplicitCode() const489f4a2713aSLionel Sambuc bool shouldVisitImplicitCode() const { return true; }
490f4a2713aSLionel Sambuc // Disables data recursion. We intercept Traverse* methods in the RAV, which
491f4a2713aSLionel Sambuc // are not triggered during data recursion.
shouldUseDataRecursionFor(clang::Stmt * S) const492f4a2713aSLionel Sambuc bool shouldUseDataRecursionFor(clang::Stmt *S) const { return false; }
493f4a2713aSLionel Sambuc
494f4a2713aSLionel Sambuc private:
495*0a6a1f1dSLionel Sambuc class TimeBucketRegion {
496*0a6a1f1dSLionel Sambuc public:
TimeBucketRegion()497*0a6a1f1dSLionel Sambuc TimeBucketRegion() : Bucket(nullptr) {}
~TimeBucketRegion()498*0a6a1f1dSLionel Sambuc ~TimeBucketRegion() { setBucket(nullptr); }
499*0a6a1f1dSLionel Sambuc
500*0a6a1f1dSLionel Sambuc /// \brief Start timing for \p NewBucket.
501*0a6a1f1dSLionel Sambuc ///
502*0a6a1f1dSLionel Sambuc /// If there was a bucket already set, it will finish the timing for that
503*0a6a1f1dSLionel Sambuc /// other bucket.
504*0a6a1f1dSLionel Sambuc /// \p NewBucket will be timed until the next call to \c setBucket() or
505*0a6a1f1dSLionel Sambuc /// until the \c TimeBucketRegion is destroyed.
506*0a6a1f1dSLionel Sambuc /// If \p NewBucket is the same as the currently timed bucket, this call
507*0a6a1f1dSLionel Sambuc /// does nothing.
setBucket(llvm::TimeRecord * NewBucket)508*0a6a1f1dSLionel Sambuc void setBucket(llvm::TimeRecord *NewBucket) {
509*0a6a1f1dSLionel Sambuc if (Bucket != NewBucket) {
510*0a6a1f1dSLionel Sambuc auto Now = llvm::TimeRecord::getCurrentTime(true);
511*0a6a1f1dSLionel Sambuc if (Bucket)
512*0a6a1f1dSLionel Sambuc *Bucket += Now;
513*0a6a1f1dSLionel Sambuc if (NewBucket)
514*0a6a1f1dSLionel Sambuc *NewBucket -= Now;
515*0a6a1f1dSLionel Sambuc Bucket = NewBucket;
516*0a6a1f1dSLionel Sambuc }
517*0a6a1f1dSLionel Sambuc }
518*0a6a1f1dSLionel Sambuc
519*0a6a1f1dSLionel Sambuc private:
520*0a6a1f1dSLionel Sambuc llvm::TimeRecord *Bucket;
521*0a6a1f1dSLionel Sambuc };
522*0a6a1f1dSLionel Sambuc
523*0a6a1f1dSLionel Sambuc /// \brief Runs all the \p Matchers on \p Node.
524*0a6a1f1dSLionel Sambuc ///
525*0a6a1f1dSLionel Sambuc /// Used by \c matchDispatch() below.
526*0a6a1f1dSLionel Sambuc template <typename T, typename MC>
matchWithoutFilter(const T & Node,const MC & Matchers)527*0a6a1f1dSLionel Sambuc void matchWithoutFilter(const T &Node, const MC &Matchers) {
528*0a6a1f1dSLionel Sambuc const bool EnableCheckProfiling = Options.CheckProfiling.hasValue();
529*0a6a1f1dSLionel Sambuc TimeBucketRegion Timer;
530*0a6a1f1dSLionel Sambuc for (const auto &MP : Matchers) {
531*0a6a1f1dSLionel Sambuc if (EnableCheckProfiling)
532*0a6a1f1dSLionel Sambuc Timer.setBucket(&TimeByBucket[MP.second->getID()]);
533*0a6a1f1dSLionel Sambuc BoundNodesTreeBuilder Builder;
534*0a6a1f1dSLionel Sambuc if (MP.first.matches(Node, this, &Builder)) {
535*0a6a1f1dSLionel Sambuc MatchVisitor Visitor(ActiveASTContext, MP.second);
536*0a6a1f1dSLionel Sambuc Builder.visitMatches(&Visitor);
537*0a6a1f1dSLionel Sambuc }
538*0a6a1f1dSLionel Sambuc }
539*0a6a1f1dSLionel Sambuc }
540*0a6a1f1dSLionel Sambuc
matchWithFilter(const ast_type_traits::DynTypedNode & DynNode)541*0a6a1f1dSLionel Sambuc void matchWithFilter(const ast_type_traits::DynTypedNode &DynNode) {
542*0a6a1f1dSLionel Sambuc auto Kind = DynNode.getNodeKind();
543*0a6a1f1dSLionel Sambuc auto it = MatcherFiltersMap.find(Kind);
544*0a6a1f1dSLionel Sambuc const auto &Filter =
545*0a6a1f1dSLionel Sambuc it != MatcherFiltersMap.end() ? it->second : getFilterForKind(Kind);
546*0a6a1f1dSLionel Sambuc
547*0a6a1f1dSLionel Sambuc if (Filter.empty())
548*0a6a1f1dSLionel Sambuc return;
549*0a6a1f1dSLionel Sambuc
550*0a6a1f1dSLionel Sambuc const bool EnableCheckProfiling = Options.CheckProfiling.hasValue();
551*0a6a1f1dSLionel Sambuc TimeBucketRegion Timer;
552*0a6a1f1dSLionel Sambuc auto &Matchers = this->Matchers->DeclOrStmt;
553*0a6a1f1dSLionel Sambuc for (unsigned short I : Filter) {
554*0a6a1f1dSLionel Sambuc auto &MP = Matchers[I];
555*0a6a1f1dSLionel Sambuc if (EnableCheckProfiling)
556*0a6a1f1dSLionel Sambuc Timer.setBucket(&TimeByBucket[MP.second->getID()]);
557*0a6a1f1dSLionel Sambuc BoundNodesTreeBuilder Builder;
558*0a6a1f1dSLionel Sambuc if (MP.first.matchesNoKindCheck(DynNode, this, &Builder)) {
559*0a6a1f1dSLionel Sambuc MatchVisitor Visitor(ActiveASTContext, MP.second);
560*0a6a1f1dSLionel Sambuc Builder.visitMatches(&Visitor);
561*0a6a1f1dSLionel Sambuc }
562*0a6a1f1dSLionel Sambuc }
563*0a6a1f1dSLionel Sambuc }
564*0a6a1f1dSLionel Sambuc
565*0a6a1f1dSLionel Sambuc const std::vector<unsigned short> &
getFilterForKind(ast_type_traits::ASTNodeKind Kind)566*0a6a1f1dSLionel Sambuc getFilterForKind(ast_type_traits::ASTNodeKind Kind) {
567*0a6a1f1dSLionel Sambuc auto &Filter = MatcherFiltersMap[Kind];
568*0a6a1f1dSLionel Sambuc auto &Matchers = this->Matchers->DeclOrStmt;
569*0a6a1f1dSLionel Sambuc assert((Matchers.size() < USHRT_MAX) && "Too many matchers.");
570*0a6a1f1dSLionel Sambuc for (unsigned I = 0, E = Matchers.size(); I != E; ++I) {
571*0a6a1f1dSLionel Sambuc if (Matchers[I].first.canMatchNodesOfKind(Kind)) {
572*0a6a1f1dSLionel Sambuc Filter.push_back(I);
573*0a6a1f1dSLionel Sambuc }
574*0a6a1f1dSLionel Sambuc }
575*0a6a1f1dSLionel Sambuc return Filter;
576*0a6a1f1dSLionel Sambuc }
577*0a6a1f1dSLionel Sambuc
578*0a6a1f1dSLionel Sambuc /// @{
579*0a6a1f1dSLionel Sambuc /// \brief Overloads to pair the different node types to their matchers.
matchDispatch(const Decl * Node)580*0a6a1f1dSLionel Sambuc void matchDispatch(const Decl *Node) {
581*0a6a1f1dSLionel Sambuc return matchWithFilter(ast_type_traits::DynTypedNode::create(*Node));
582*0a6a1f1dSLionel Sambuc }
matchDispatch(const Stmt * Node)583*0a6a1f1dSLionel Sambuc void matchDispatch(const Stmt *Node) {
584*0a6a1f1dSLionel Sambuc return matchWithFilter(ast_type_traits::DynTypedNode::create(*Node));
585*0a6a1f1dSLionel Sambuc }
586*0a6a1f1dSLionel Sambuc
matchDispatch(const Type * Node)587*0a6a1f1dSLionel Sambuc void matchDispatch(const Type *Node) {
588*0a6a1f1dSLionel Sambuc matchWithoutFilter(QualType(Node, 0), Matchers->Type);
589*0a6a1f1dSLionel Sambuc }
matchDispatch(const TypeLoc * Node)590*0a6a1f1dSLionel Sambuc void matchDispatch(const TypeLoc *Node) {
591*0a6a1f1dSLionel Sambuc matchWithoutFilter(*Node, Matchers->TypeLoc);
592*0a6a1f1dSLionel Sambuc }
matchDispatch(const QualType * Node)593*0a6a1f1dSLionel Sambuc void matchDispatch(const QualType *Node) {
594*0a6a1f1dSLionel Sambuc matchWithoutFilter(*Node, Matchers->Type);
595*0a6a1f1dSLionel Sambuc }
matchDispatch(const NestedNameSpecifier * Node)596*0a6a1f1dSLionel Sambuc void matchDispatch(const NestedNameSpecifier *Node) {
597*0a6a1f1dSLionel Sambuc matchWithoutFilter(*Node, Matchers->NestedNameSpecifier);
598*0a6a1f1dSLionel Sambuc }
matchDispatch(const NestedNameSpecifierLoc * Node)599*0a6a1f1dSLionel Sambuc void matchDispatch(const NestedNameSpecifierLoc *Node) {
600*0a6a1f1dSLionel Sambuc matchWithoutFilter(*Node, Matchers->NestedNameSpecifierLoc);
601*0a6a1f1dSLionel Sambuc }
matchDispatch(const void *)602*0a6a1f1dSLionel Sambuc void matchDispatch(const void *) { /* Do nothing. */ }
603*0a6a1f1dSLionel Sambuc /// @}
604*0a6a1f1dSLionel Sambuc
605f4a2713aSLionel Sambuc // Returns whether an ancestor of \p Node matches \p Matcher.
606f4a2713aSLionel Sambuc //
607f4a2713aSLionel Sambuc // The order of matching ((which can lead to different nodes being bound in
608f4a2713aSLionel Sambuc // case there are multiple matches) is breadth first search.
609f4a2713aSLionel Sambuc //
610f4a2713aSLionel Sambuc // To allow memoization in the very common case of having deeply nested
611f4a2713aSLionel Sambuc // expressions inside a template function, we first walk up the AST, memoizing
612f4a2713aSLionel Sambuc // the result of the match along the way, as long as there is only a single
613f4a2713aSLionel Sambuc // parent.
614f4a2713aSLionel Sambuc //
615f4a2713aSLionel Sambuc // Once there are multiple parents, the breadth first search order does not
616f4a2713aSLionel Sambuc // allow simple memoization on the ancestors. Thus, we only memoize as long
617f4a2713aSLionel Sambuc // as there is a single parent.
memoizedMatchesAncestorOfRecursively(const ast_type_traits::DynTypedNode & Node,const DynTypedMatcher & Matcher,BoundNodesTreeBuilder * Builder,AncestorMatchMode MatchMode)618f4a2713aSLionel Sambuc bool memoizedMatchesAncestorOfRecursively(
619f4a2713aSLionel Sambuc const ast_type_traits::DynTypedNode &Node, const DynTypedMatcher &Matcher,
620f4a2713aSLionel Sambuc BoundNodesTreeBuilder *Builder, AncestorMatchMode MatchMode) {
621f4a2713aSLionel Sambuc if (Node.get<TranslationUnitDecl>() ==
622f4a2713aSLionel Sambuc ActiveASTContext->getTranslationUnitDecl())
623f4a2713aSLionel Sambuc return false;
624f4a2713aSLionel Sambuc assert(Node.getMemoizationData() &&
625f4a2713aSLionel Sambuc "Invariant broken: only nodes that support memoization may be "
626f4a2713aSLionel Sambuc "used in the parent map.");
627*0a6a1f1dSLionel Sambuc
628f4a2713aSLionel Sambuc MatchKey Key;
629f4a2713aSLionel Sambuc Key.MatcherID = Matcher.getID();
630f4a2713aSLionel Sambuc Key.Node = Node;
631f4a2713aSLionel Sambuc Key.BoundNodes = *Builder;
632f4a2713aSLionel Sambuc
633f4a2713aSLionel Sambuc // Note that we cannot use insert and reuse the iterator, as recursive
634f4a2713aSLionel Sambuc // calls to match might invalidate the result cache iterators.
635f4a2713aSLionel Sambuc MemoizationMap::iterator I = ResultCache.find(Key);
636f4a2713aSLionel Sambuc if (I != ResultCache.end()) {
637f4a2713aSLionel Sambuc *Builder = I->second.Nodes;
638f4a2713aSLionel Sambuc return I->second.ResultOfMatch;
639f4a2713aSLionel Sambuc }
640*0a6a1f1dSLionel Sambuc
641f4a2713aSLionel Sambuc MemoizedMatchResult Result;
642f4a2713aSLionel Sambuc Result.ResultOfMatch = false;
643f4a2713aSLionel Sambuc Result.Nodes = *Builder;
644*0a6a1f1dSLionel Sambuc
645*0a6a1f1dSLionel Sambuc const auto &Parents = ActiveASTContext->getParents(Node);
646*0a6a1f1dSLionel Sambuc assert(!Parents.empty() && "Found node that is not in the parent map.");
647f4a2713aSLionel Sambuc if (Parents.size() == 1) {
648f4a2713aSLionel Sambuc // Only one parent - do recursive memoization.
649f4a2713aSLionel Sambuc const ast_type_traits::DynTypedNode Parent = Parents[0];
650f4a2713aSLionel Sambuc if (Matcher.matches(Parent, this, &Result.Nodes)) {
651f4a2713aSLionel Sambuc Result.ResultOfMatch = true;
652f4a2713aSLionel Sambuc } else if (MatchMode != ASTMatchFinder::AMM_ParentOnly) {
653f4a2713aSLionel Sambuc // Reset the results to not include the bound nodes from the failed
654f4a2713aSLionel Sambuc // match above.
655f4a2713aSLionel Sambuc Result.Nodes = *Builder;
656f4a2713aSLionel Sambuc Result.ResultOfMatch = memoizedMatchesAncestorOfRecursively(
657f4a2713aSLionel Sambuc Parent, Matcher, &Result.Nodes, MatchMode);
658f4a2713aSLionel Sambuc // Once we get back from the recursive call, the result will be the
659f4a2713aSLionel Sambuc // same as the parent's result.
660f4a2713aSLionel Sambuc }
661f4a2713aSLionel Sambuc } else {
662f4a2713aSLionel Sambuc // Multiple parents - BFS over the rest of the nodes.
663f4a2713aSLionel Sambuc llvm::DenseSet<const void *> Visited;
664f4a2713aSLionel Sambuc std::deque<ast_type_traits::DynTypedNode> Queue(Parents.begin(),
665f4a2713aSLionel Sambuc Parents.end());
666f4a2713aSLionel Sambuc while (!Queue.empty()) {
667f4a2713aSLionel Sambuc Result.Nodes = *Builder;
668f4a2713aSLionel Sambuc if (Matcher.matches(Queue.front(), this, &Result.Nodes)) {
669f4a2713aSLionel Sambuc Result.ResultOfMatch = true;
670f4a2713aSLionel Sambuc break;
671f4a2713aSLionel Sambuc }
672f4a2713aSLionel Sambuc if (MatchMode != ASTMatchFinder::AMM_ParentOnly) {
673*0a6a1f1dSLionel Sambuc for (const auto &Parent :
674*0a6a1f1dSLionel Sambuc ActiveASTContext->getParents(Queue.front())) {
675f4a2713aSLionel Sambuc // Make sure we do not visit the same node twice.
676f4a2713aSLionel Sambuc // Otherwise, we'll visit the common ancestors as often as there
677f4a2713aSLionel Sambuc // are splits on the way down.
678*0a6a1f1dSLionel Sambuc if (Visited.insert(Parent.getMemoizationData()).second)
679*0a6a1f1dSLionel Sambuc Queue.push_back(Parent);
680f4a2713aSLionel Sambuc }
681f4a2713aSLionel Sambuc }
682f4a2713aSLionel Sambuc Queue.pop_front();
683f4a2713aSLionel Sambuc }
684f4a2713aSLionel Sambuc }
685f4a2713aSLionel Sambuc
686*0a6a1f1dSLionel Sambuc MemoizedMatchResult &CachedResult = ResultCache[Key];
687*0a6a1f1dSLionel Sambuc CachedResult = std::move(Result);
688*0a6a1f1dSLionel Sambuc
689*0a6a1f1dSLionel Sambuc *Builder = CachedResult.Nodes;
690*0a6a1f1dSLionel Sambuc return CachedResult.ResultOfMatch;
691f4a2713aSLionel Sambuc }
692f4a2713aSLionel Sambuc
693f4a2713aSLionel Sambuc // Implements a BoundNodesTree::Visitor that calls a MatchCallback with
694f4a2713aSLionel Sambuc // the aggregated bound nodes for each match.
695f4a2713aSLionel Sambuc class MatchVisitor : public BoundNodesTreeBuilder::Visitor {
696f4a2713aSLionel Sambuc public:
MatchVisitor(ASTContext * Context,MatchFinder::MatchCallback * Callback)697f4a2713aSLionel Sambuc MatchVisitor(ASTContext* Context,
698f4a2713aSLionel Sambuc MatchFinder::MatchCallback* Callback)
699f4a2713aSLionel Sambuc : Context(Context),
700f4a2713aSLionel Sambuc Callback(Callback) {}
701f4a2713aSLionel Sambuc
visitMatch(const BoundNodes & BoundNodesView)702*0a6a1f1dSLionel Sambuc void visitMatch(const BoundNodes& BoundNodesView) override {
703f4a2713aSLionel Sambuc Callback->run(MatchFinder::MatchResult(BoundNodesView, Context));
704f4a2713aSLionel Sambuc }
705f4a2713aSLionel Sambuc
706f4a2713aSLionel Sambuc private:
707f4a2713aSLionel Sambuc ASTContext* Context;
708f4a2713aSLionel Sambuc MatchFinder::MatchCallback* Callback;
709f4a2713aSLionel Sambuc };
710f4a2713aSLionel Sambuc
711f4a2713aSLionel Sambuc // Returns true if 'TypeNode' has an alias that matches the given matcher.
typeHasMatchingAlias(const Type * TypeNode,const Matcher<NamedDecl> Matcher,BoundNodesTreeBuilder * Builder)712f4a2713aSLionel Sambuc bool typeHasMatchingAlias(const Type *TypeNode,
713f4a2713aSLionel Sambuc const Matcher<NamedDecl> Matcher,
714f4a2713aSLionel Sambuc BoundNodesTreeBuilder *Builder) {
715f4a2713aSLionel Sambuc const Type *const CanonicalType =
716f4a2713aSLionel Sambuc ActiveASTContext->getCanonicalType(TypeNode);
717*0a6a1f1dSLionel Sambuc for (const TypedefNameDecl *Alias : TypeAliases.lookup(CanonicalType)) {
718f4a2713aSLionel Sambuc BoundNodesTreeBuilder Result(*Builder);
719*0a6a1f1dSLionel Sambuc if (Matcher.matches(*Alias, this, &Result)) {
720*0a6a1f1dSLionel Sambuc *Builder = std::move(Result);
721f4a2713aSLionel Sambuc return true;
722f4a2713aSLionel Sambuc }
723f4a2713aSLionel Sambuc }
724f4a2713aSLionel Sambuc return false;
725f4a2713aSLionel Sambuc }
726f4a2713aSLionel Sambuc
727*0a6a1f1dSLionel Sambuc /// \brief Bucket to record map.
728*0a6a1f1dSLionel Sambuc ///
729*0a6a1f1dSLionel Sambuc /// Used to get the appropriate bucket for each matcher.
730*0a6a1f1dSLionel Sambuc llvm::StringMap<llvm::TimeRecord> TimeByBucket;
731*0a6a1f1dSLionel Sambuc
732*0a6a1f1dSLionel Sambuc const MatchFinder::MatchersByType *Matchers;
733*0a6a1f1dSLionel Sambuc
734*0a6a1f1dSLionel Sambuc /// \brief Filtered list of matcher indices for each matcher kind.
735*0a6a1f1dSLionel Sambuc ///
736*0a6a1f1dSLionel Sambuc /// \c Decl and \c Stmt toplevel matchers usually apply to a specific node
737*0a6a1f1dSLionel Sambuc /// kind (and derived kinds) so it is a waste to try every matcher on every
738*0a6a1f1dSLionel Sambuc /// node.
739*0a6a1f1dSLionel Sambuc /// We precalculate a list of matchers that pass the toplevel restrict check.
740*0a6a1f1dSLionel Sambuc /// This also allows us to skip the restrict check at matching time. See
741*0a6a1f1dSLionel Sambuc /// use \c matchesNoKindCheck() above.
742*0a6a1f1dSLionel Sambuc llvm::DenseMap<ast_type_traits::ASTNodeKind, std::vector<unsigned short>>
743*0a6a1f1dSLionel Sambuc MatcherFiltersMap;
744*0a6a1f1dSLionel Sambuc
745*0a6a1f1dSLionel Sambuc const MatchFinder::MatchFinderOptions &Options;
746f4a2713aSLionel Sambuc ASTContext *ActiveASTContext;
747f4a2713aSLionel Sambuc
748f4a2713aSLionel Sambuc // Maps a canonical type to its TypedefDecls.
749f4a2713aSLionel Sambuc llvm::DenseMap<const Type*, std::set<const TypedefNameDecl*> > TypeAliases;
750f4a2713aSLionel Sambuc
751f4a2713aSLionel Sambuc // Maps (matcher, node) -> the match result for memoization.
752f4a2713aSLionel Sambuc typedef std::map<MatchKey, MemoizedMatchResult> MemoizationMap;
753f4a2713aSLionel Sambuc MemoizationMap ResultCache;
754f4a2713aSLionel Sambuc };
755f4a2713aSLionel Sambuc
getAsCXXRecordDecl(const Type * TypeNode)756f4a2713aSLionel Sambuc static CXXRecordDecl *getAsCXXRecordDecl(const Type *TypeNode) {
757f4a2713aSLionel Sambuc // Type::getAs<...>() drills through typedefs.
758*0a6a1f1dSLionel Sambuc if (TypeNode->getAs<DependentNameType>() != nullptr ||
759*0a6a1f1dSLionel Sambuc TypeNode->getAs<DependentTemplateSpecializationType>() != nullptr ||
760*0a6a1f1dSLionel Sambuc TypeNode->getAs<TemplateTypeParmType>() != nullptr)
761f4a2713aSLionel Sambuc // Dependent names and template TypeNode parameters will be matched when
762f4a2713aSLionel Sambuc // the template is instantiated.
763*0a6a1f1dSLionel Sambuc return nullptr;
764f4a2713aSLionel Sambuc TemplateSpecializationType const *TemplateType =
765f4a2713aSLionel Sambuc TypeNode->getAs<TemplateSpecializationType>();
766*0a6a1f1dSLionel Sambuc if (!TemplateType) {
767f4a2713aSLionel Sambuc return TypeNode->getAsCXXRecordDecl();
768f4a2713aSLionel Sambuc }
769f4a2713aSLionel Sambuc if (TemplateType->getTemplateName().isDependent())
770f4a2713aSLionel Sambuc // Dependent template specializations will be matched when the
771f4a2713aSLionel Sambuc // template is instantiated.
772*0a6a1f1dSLionel Sambuc return nullptr;
773f4a2713aSLionel Sambuc
774f4a2713aSLionel Sambuc // For template specialization types which are specializing a template
775f4a2713aSLionel Sambuc // declaration which is an explicit or partial specialization of another
776f4a2713aSLionel Sambuc // template declaration, getAsCXXRecordDecl() returns the corresponding
777f4a2713aSLionel Sambuc // ClassTemplateSpecializationDecl.
778f4a2713aSLionel Sambuc //
779f4a2713aSLionel Sambuc // For template specialization types which are specializing a template
780f4a2713aSLionel Sambuc // declaration which is neither an explicit nor partial specialization of
781f4a2713aSLionel Sambuc // another template declaration, getAsCXXRecordDecl() returns NULL and
782f4a2713aSLionel Sambuc // we get the CXXRecordDecl of the templated declaration.
783f4a2713aSLionel Sambuc CXXRecordDecl *SpecializationDecl = TemplateType->getAsCXXRecordDecl();
784*0a6a1f1dSLionel Sambuc if (SpecializationDecl) {
785f4a2713aSLionel Sambuc return SpecializationDecl;
786f4a2713aSLionel Sambuc }
787f4a2713aSLionel Sambuc NamedDecl *Templated =
788f4a2713aSLionel Sambuc TemplateType->getTemplateName().getAsTemplateDecl()->getTemplatedDecl();
789f4a2713aSLionel Sambuc if (CXXRecordDecl *TemplatedRecord = dyn_cast<CXXRecordDecl>(Templated)) {
790f4a2713aSLionel Sambuc return TemplatedRecord;
791f4a2713aSLionel Sambuc }
792f4a2713aSLionel Sambuc // Now it can still be that we have an alias template.
793f4a2713aSLionel Sambuc TypeAliasDecl *AliasDecl = dyn_cast<TypeAliasDecl>(Templated);
794f4a2713aSLionel Sambuc assert(AliasDecl);
795f4a2713aSLionel Sambuc return getAsCXXRecordDecl(AliasDecl->getUnderlyingType().getTypePtr());
796f4a2713aSLionel Sambuc }
797f4a2713aSLionel Sambuc
798f4a2713aSLionel Sambuc // Returns true if the given class is directly or indirectly derived
799f4a2713aSLionel Sambuc // from a base type with the given name. A class is not considered to be
800f4a2713aSLionel Sambuc // derived from itself.
classIsDerivedFrom(const CXXRecordDecl * Declaration,const Matcher<NamedDecl> & Base,BoundNodesTreeBuilder * Builder)801f4a2713aSLionel Sambuc bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
802f4a2713aSLionel Sambuc const Matcher<NamedDecl> &Base,
803f4a2713aSLionel Sambuc BoundNodesTreeBuilder *Builder) {
804f4a2713aSLionel Sambuc if (!Declaration->hasDefinition())
805f4a2713aSLionel Sambuc return false;
806*0a6a1f1dSLionel Sambuc for (const auto &It : Declaration->bases()) {
807*0a6a1f1dSLionel Sambuc const Type *TypeNode = It.getType().getTypePtr();
808f4a2713aSLionel Sambuc
809f4a2713aSLionel Sambuc if (typeHasMatchingAlias(TypeNode, Base, Builder))
810f4a2713aSLionel Sambuc return true;
811f4a2713aSLionel Sambuc
812f4a2713aSLionel Sambuc CXXRecordDecl *ClassDecl = getAsCXXRecordDecl(TypeNode);
813*0a6a1f1dSLionel Sambuc if (!ClassDecl)
814f4a2713aSLionel Sambuc continue;
815f4a2713aSLionel Sambuc if (ClassDecl == Declaration) {
816f4a2713aSLionel Sambuc // This can happen for recursive template definitions; if the
817f4a2713aSLionel Sambuc // current declaration did not match, we can safely return false.
818f4a2713aSLionel Sambuc return false;
819f4a2713aSLionel Sambuc }
820f4a2713aSLionel Sambuc BoundNodesTreeBuilder Result(*Builder);
821f4a2713aSLionel Sambuc if (Base.matches(*ClassDecl, this, &Result)) {
822*0a6a1f1dSLionel Sambuc *Builder = std::move(Result);
823f4a2713aSLionel Sambuc return true;
824f4a2713aSLionel Sambuc }
825f4a2713aSLionel Sambuc if (classIsDerivedFrom(ClassDecl, Base, Builder))
826f4a2713aSLionel Sambuc return true;
827f4a2713aSLionel Sambuc }
828f4a2713aSLionel Sambuc return false;
829f4a2713aSLionel Sambuc }
830f4a2713aSLionel Sambuc
TraverseDecl(Decl * DeclNode)831f4a2713aSLionel Sambuc bool MatchASTVisitor::TraverseDecl(Decl *DeclNode) {
832*0a6a1f1dSLionel Sambuc if (!DeclNode) {
833f4a2713aSLionel Sambuc return true;
834f4a2713aSLionel Sambuc }
835f4a2713aSLionel Sambuc match(*DeclNode);
836f4a2713aSLionel Sambuc return RecursiveASTVisitor<MatchASTVisitor>::TraverseDecl(DeclNode);
837f4a2713aSLionel Sambuc }
838f4a2713aSLionel Sambuc
TraverseStmt(Stmt * StmtNode)839f4a2713aSLionel Sambuc bool MatchASTVisitor::TraverseStmt(Stmt *StmtNode) {
840*0a6a1f1dSLionel Sambuc if (!StmtNode) {
841f4a2713aSLionel Sambuc return true;
842f4a2713aSLionel Sambuc }
843f4a2713aSLionel Sambuc match(*StmtNode);
844f4a2713aSLionel Sambuc return RecursiveASTVisitor<MatchASTVisitor>::TraverseStmt(StmtNode);
845f4a2713aSLionel Sambuc }
846f4a2713aSLionel Sambuc
TraverseType(QualType TypeNode)847f4a2713aSLionel Sambuc bool MatchASTVisitor::TraverseType(QualType TypeNode) {
848f4a2713aSLionel Sambuc match(TypeNode);
849f4a2713aSLionel Sambuc return RecursiveASTVisitor<MatchASTVisitor>::TraverseType(TypeNode);
850f4a2713aSLionel Sambuc }
851f4a2713aSLionel Sambuc
TraverseTypeLoc(TypeLoc TypeLocNode)852f4a2713aSLionel Sambuc bool MatchASTVisitor::TraverseTypeLoc(TypeLoc TypeLocNode) {
853f4a2713aSLionel Sambuc // The RecursiveASTVisitor only visits types if they're not within TypeLocs.
854f4a2713aSLionel Sambuc // We still want to find those types via matchers, so we match them here. Note
855f4a2713aSLionel Sambuc // that the TypeLocs are structurally a shadow-hierarchy to the expressed
856f4a2713aSLionel Sambuc // type, so we visit all involved parts of a compound type when matching on
857f4a2713aSLionel Sambuc // each TypeLoc.
858f4a2713aSLionel Sambuc match(TypeLocNode);
859f4a2713aSLionel Sambuc match(TypeLocNode.getType());
860f4a2713aSLionel Sambuc return RecursiveASTVisitor<MatchASTVisitor>::TraverseTypeLoc(TypeLocNode);
861f4a2713aSLionel Sambuc }
862f4a2713aSLionel Sambuc
TraverseNestedNameSpecifier(NestedNameSpecifier * NNS)863f4a2713aSLionel Sambuc bool MatchASTVisitor::TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {
864f4a2713aSLionel Sambuc match(*NNS);
865f4a2713aSLionel Sambuc return RecursiveASTVisitor<MatchASTVisitor>::TraverseNestedNameSpecifier(NNS);
866f4a2713aSLionel Sambuc }
867f4a2713aSLionel Sambuc
TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS)868f4a2713aSLionel Sambuc bool MatchASTVisitor::TraverseNestedNameSpecifierLoc(
869f4a2713aSLionel Sambuc NestedNameSpecifierLoc NNS) {
870f4a2713aSLionel Sambuc match(NNS);
871f4a2713aSLionel Sambuc // We only match the nested name specifier here (as opposed to traversing it)
872f4a2713aSLionel Sambuc // because the traversal is already done in the parallel "Loc"-hierarchy.
873*0a6a1f1dSLionel Sambuc if (NNS.hasQualifier())
874f4a2713aSLionel Sambuc match(*NNS.getNestedNameSpecifier());
875f4a2713aSLionel Sambuc return
876f4a2713aSLionel Sambuc RecursiveASTVisitor<MatchASTVisitor>::TraverseNestedNameSpecifierLoc(NNS);
877f4a2713aSLionel Sambuc }
878f4a2713aSLionel Sambuc
879f4a2713aSLionel Sambuc class MatchASTConsumer : public ASTConsumer {
880f4a2713aSLionel Sambuc public:
MatchASTConsumer(MatchFinder * Finder,MatchFinder::ParsingDoneTestCallback * ParsingDone)881f4a2713aSLionel Sambuc MatchASTConsumer(MatchFinder *Finder,
882f4a2713aSLionel Sambuc MatchFinder::ParsingDoneTestCallback *ParsingDone)
883f4a2713aSLionel Sambuc : Finder(Finder), ParsingDone(ParsingDone) {}
884f4a2713aSLionel Sambuc
885f4a2713aSLionel Sambuc private:
HandleTranslationUnit(ASTContext & Context)886*0a6a1f1dSLionel Sambuc void HandleTranslationUnit(ASTContext &Context) override {
887*0a6a1f1dSLionel Sambuc if (ParsingDone != nullptr) {
888f4a2713aSLionel Sambuc ParsingDone->run();
889f4a2713aSLionel Sambuc }
890f4a2713aSLionel Sambuc Finder->matchAST(Context);
891f4a2713aSLionel Sambuc }
892f4a2713aSLionel Sambuc
893f4a2713aSLionel Sambuc MatchFinder *Finder;
894f4a2713aSLionel Sambuc MatchFinder::ParsingDoneTestCallback *ParsingDone;
895f4a2713aSLionel Sambuc };
896f4a2713aSLionel Sambuc
897f4a2713aSLionel Sambuc } // end namespace
898f4a2713aSLionel Sambuc } // end namespace internal
899f4a2713aSLionel Sambuc
MatchResult(const BoundNodes & Nodes,ASTContext * Context)900f4a2713aSLionel Sambuc MatchFinder::MatchResult::MatchResult(const BoundNodes &Nodes,
901f4a2713aSLionel Sambuc ASTContext *Context)
902f4a2713aSLionel Sambuc : Nodes(Nodes), Context(Context),
903f4a2713aSLionel Sambuc SourceManager(&Context->getSourceManager()) {}
904f4a2713aSLionel Sambuc
~MatchCallback()905f4a2713aSLionel Sambuc MatchFinder::MatchCallback::~MatchCallback() {}
~ParsingDoneTestCallback()906f4a2713aSLionel Sambuc MatchFinder::ParsingDoneTestCallback::~ParsingDoneTestCallback() {}
907f4a2713aSLionel Sambuc
MatchFinder(MatchFinderOptions Options)908*0a6a1f1dSLionel Sambuc MatchFinder::MatchFinder(MatchFinderOptions Options)
909*0a6a1f1dSLionel Sambuc : Options(std::move(Options)), ParsingDone(nullptr) {}
910f4a2713aSLionel Sambuc
~MatchFinder()911f4a2713aSLionel Sambuc MatchFinder::~MatchFinder() {}
912f4a2713aSLionel Sambuc
addMatcher(const DeclarationMatcher & NodeMatch,MatchCallback * Action)913f4a2713aSLionel Sambuc void MatchFinder::addMatcher(const DeclarationMatcher &NodeMatch,
914f4a2713aSLionel Sambuc MatchCallback *Action) {
915*0a6a1f1dSLionel Sambuc Matchers.DeclOrStmt.push_back(std::make_pair(NodeMatch, Action));
916*0a6a1f1dSLionel Sambuc Matchers.AllCallbacks.push_back(Action);
917f4a2713aSLionel Sambuc }
918f4a2713aSLionel Sambuc
addMatcher(const TypeMatcher & NodeMatch,MatchCallback * Action)919f4a2713aSLionel Sambuc void MatchFinder::addMatcher(const TypeMatcher &NodeMatch,
920f4a2713aSLionel Sambuc MatchCallback *Action) {
921*0a6a1f1dSLionel Sambuc Matchers.Type.push_back(std::make_pair(NodeMatch, Action));
922*0a6a1f1dSLionel Sambuc Matchers.AllCallbacks.push_back(Action);
923f4a2713aSLionel Sambuc }
924f4a2713aSLionel Sambuc
addMatcher(const StatementMatcher & NodeMatch,MatchCallback * Action)925f4a2713aSLionel Sambuc void MatchFinder::addMatcher(const StatementMatcher &NodeMatch,
926f4a2713aSLionel Sambuc MatchCallback *Action) {
927*0a6a1f1dSLionel Sambuc Matchers.DeclOrStmt.push_back(std::make_pair(NodeMatch, Action));
928*0a6a1f1dSLionel Sambuc Matchers.AllCallbacks.push_back(Action);
929f4a2713aSLionel Sambuc }
930f4a2713aSLionel Sambuc
addMatcher(const NestedNameSpecifierMatcher & NodeMatch,MatchCallback * Action)931f4a2713aSLionel Sambuc void MatchFinder::addMatcher(const NestedNameSpecifierMatcher &NodeMatch,
932f4a2713aSLionel Sambuc MatchCallback *Action) {
933*0a6a1f1dSLionel Sambuc Matchers.NestedNameSpecifier.push_back(std::make_pair(NodeMatch, Action));
934*0a6a1f1dSLionel Sambuc Matchers.AllCallbacks.push_back(Action);
935f4a2713aSLionel Sambuc }
936f4a2713aSLionel Sambuc
addMatcher(const NestedNameSpecifierLocMatcher & NodeMatch,MatchCallback * Action)937f4a2713aSLionel Sambuc void MatchFinder::addMatcher(const NestedNameSpecifierLocMatcher &NodeMatch,
938f4a2713aSLionel Sambuc MatchCallback *Action) {
939*0a6a1f1dSLionel Sambuc Matchers.NestedNameSpecifierLoc.push_back(std::make_pair(NodeMatch, Action));
940*0a6a1f1dSLionel Sambuc Matchers.AllCallbacks.push_back(Action);
941f4a2713aSLionel Sambuc }
942f4a2713aSLionel Sambuc
addMatcher(const TypeLocMatcher & NodeMatch,MatchCallback * Action)943f4a2713aSLionel Sambuc void MatchFinder::addMatcher(const TypeLocMatcher &NodeMatch,
944f4a2713aSLionel Sambuc MatchCallback *Action) {
945*0a6a1f1dSLionel Sambuc Matchers.TypeLoc.push_back(std::make_pair(NodeMatch, Action));
946*0a6a1f1dSLionel Sambuc Matchers.AllCallbacks.push_back(Action);
947f4a2713aSLionel Sambuc }
948f4a2713aSLionel Sambuc
addDynamicMatcher(const internal::DynTypedMatcher & NodeMatch,MatchCallback * Action)949f4a2713aSLionel Sambuc bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
950f4a2713aSLionel Sambuc MatchCallback *Action) {
951f4a2713aSLionel Sambuc if (NodeMatch.canConvertTo<Decl>()) {
952f4a2713aSLionel Sambuc addMatcher(NodeMatch.convertTo<Decl>(), Action);
953f4a2713aSLionel Sambuc return true;
954f4a2713aSLionel Sambuc } else if (NodeMatch.canConvertTo<QualType>()) {
955f4a2713aSLionel Sambuc addMatcher(NodeMatch.convertTo<QualType>(), Action);
956f4a2713aSLionel Sambuc return true;
957f4a2713aSLionel Sambuc } else if (NodeMatch.canConvertTo<Stmt>()) {
958f4a2713aSLionel Sambuc addMatcher(NodeMatch.convertTo<Stmt>(), Action);
959f4a2713aSLionel Sambuc return true;
960f4a2713aSLionel Sambuc } else if (NodeMatch.canConvertTo<NestedNameSpecifier>()) {
961f4a2713aSLionel Sambuc addMatcher(NodeMatch.convertTo<NestedNameSpecifier>(), Action);
962f4a2713aSLionel Sambuc return true;
963f4a2713aSLionel Sambuc } else if (NodeMatch.canConvertTo<NestedNameSpecifierLoc>()) {
964f4a2713aSLionel Sambuc addMatcher(NodeMatch.convertTo<NestedNameSpecifierLoc>(), Action);
965f4a2713aSLionel Sambuc return true;
966f4a2713aSLionel Sambuc } else if (NodeMatch.canConvertTo<TypeLoc>()) {
967f4a2713aSLionel Sambuc addMatcher(NodeMatch.convertTo<TypeLoc>(), Action);
968f4a2713aSLionel Sambuc return true;
969f4a2713aSLionel Sambuc }
970f4a2713aSLionel Sambuc return false;
971f4a2713aSLionel Sambuc }
972f4a2713aSLionel Sambuc
newASTConsumer()973*0a6a1f1dSLionel Sambuc std::unique_ptr<ASTConsumer> MatchFinder::newASTConsumer() {
974*0a6a1f1dSLionel Sambuc return llvm::make_unique<internal::MatchASTConsumer>(this, ParsingDone);
975f4a2713aSLionel Sambuc }
976f4a2713aSLionel Sambuc
match(const clang::ast_type_traits::DynTypedNode & Node,ASTContext & Context)977f4a2713aSLionel Sambuc void MatchFinder::match(const clang::ast_type_traits::DynTypedNode &Node,
978f4a2713aSLionel Sambuc ASTContext &Context) {
979*0a6a1f1dSLionel Sambuc internal::MatchASTVisitor Visitor(&Matchers, Options);
980f4a2713aSLionel Sambuc Visitor.set_active_ast_context(&Context);
981f4a2713aSLionel Sambuc Visitor.match(Node);
982f4a2713aSLionel Sambuc }
983f4a2713aSLionel Sambuc
matchAST(ASTContext & Context)984f4a2713aSLionel Sambuc void MatchFinder::matchAST(ASTContext &Context) {
985*0a6a1f1dSLionel Sambuc internal::MatchASTVisitor Visitor(&Matchers, Options);
986f4a2713aSLionel Sambuc Visitor.set_active_ast_context(&Context);
987f4a2713aSLionel Sambuc Visitor.onStartOfTranslationUnit();
988f4a2713aSLionel Sambuc Visitor.TraverseDecl(Context.getTranslationUnitDecl());
989f4a2713aSLionel Sambuc Visitor.onEndOfTranslationUnit();
990f4a2713aSLionel Sambuc }
991f4a2713aSLionel Sambuc
registerTestCallbackAfterParsing(MatchFinder::ParsingDoneTestCallback * NewParsingDone)992f4a2713aSLionel Sambuc void MatchFinder::registerTestCallbackAfterParsing(
993f4a2713aSLionel Sambuc MatchFinder::ParsingDoneTestCallback *NewParsingDone) {
994f4a2713aSLionel Sambuc ParsingDone = NewParsingDone;
995f4a2713aSLionel Sambuc }
996f4a2713aSLionel Sambuc
getID() const997*0a6a1f1dSLionel Sambuc StringRef MatchFinder::MatchCallback::getID() const { return "<unknown>"; }
998*0a6a1f1dSLionel Sambuc
999f4a2713aSLionel Sambuc } // end namespace ast_matchers
1000f4a2713aSLionel Sambuc } // end namespace clang
1001