1e5dd7070Spatrick //===--- ASTMatchFinder.cpp - Structural query framework ------------------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // Implements an algorithm to efficiently search for matches on AST nodes.
10e5dd7070Spatrick // Uses memoization to support recursive matches like HasDescendant.
11e5dd7070Spatrick //
12e5dd7070Spatrick // The general idea is to visit all AST nodes with a RecursiveASTVisitor,
13e5dd7070Spatrick // calling the Matches(...) method of each matcher we are running on each
14e5dd7070Spatrick // AST node. The matcher can recurse via the ASTMatchFinder interface.
15e5dd7070Spatrick //
16e5dd7070Spatrick //===----------------------------------------------------------------------===//
17e5dd7070Spatrick
18e5dd7070Spatrick #include "clang/ASTMatchers/ASTMatchFinder.h"
19e5dd7070Spatrick #include "clang/AST/ASTConsumer.h"
20e5dd7070Spatrick #include "clang/AST/ASTContext.h"
21e5dd7070Spatrick #include "clang/AST/RecursiveASTVisitor.h"
22e5dd7070Spatrick #include "llvm/ADT/DenseMap.h"
23e5dd7070Spatrick #include "llvm/ADT/StringMap.h"
24*12c85518Srobert #include "llvm/Support/PrettyStackTrace.h"
25e5dd7070Spatrick #include "llvm/Support/Timer.h"
26e5dd7070Spatrick #include <deque>
27e5dd7070Spatrick #include <memory>
28e5dd7070Spatrick #include <set>
29e5dd7070Spatrick
30e5dd7070Spatrick namespace clang {
31e5dd7070Spatrick namespace ast_matchers {
32e5dd7070Spatrick namespace internal {
33e5dd7070Spatrick namespace {
34e5dd7070Spatrick
35e5dd7070Spatrick typedef MatchFinder::MatchCallback MatchCallback;
36e5dd7070Spatrick
37e5dd7070Spatrick // The maximum number of memoization entries to store.
38e5dd7070Spatrick // 10k has been experimentally found to give a good trade-off
39e5dd7070Spatrick // of performance vs. memory consumption by running matcher
40e5dd7070Spatrick // that match on every statement over a very large codebase.
41e5dd7070Spatrick //
42e5dd7070Spatrick // FIXME: Do some performance optimization in general and
43e5dd7070Spatrick // revisit this number; also, put up micro-benchmarks that we can
44e5dd7070Spatrick // optimize this on.
45e5dd7070Spatrick static const unsigned MaxMemoizationEntries = 10000;
46e5dd7070Spatrick
47ec727ea7Spatrick enum class MatchType {
48ec727ea7Spatrick Ancestors,
49ec727ea7Spatrick
50ec727ea7Spatrick Descendants,
51ec727ea7Spatrick Child,
52ec727ea7Spatrick };
53ec727ea7Spatrick
54e5dd7070Spatrick // We use memoization to avoid running the same matcher on the same
55e5dd7070Spatrick // AST node twice. This struct is the key for looking up match
56e5dd7070Spatrick // result. It consists of an ID of the MatcherInterface (for
57e5dd7070Spatrick // identifying the matcher), a pointer to the AST node and the
58e5dd7070Spatrick // bound nodes before the matcher was executed.
59e5dd7070Spatrick //
60e5dd7070Spatrick // We currently only memoize on nodes whose pointers identify the
61e5dd7070Spatrick // nodes (\c Stmt and \c Decl, but not \c QualType or \c TypeLoc).
62e5dd7070Spatrick // For \c QualType and \c TypeLoc it is possible to implement
63e5dd7070Spatrick // generation of keys for each type.
64e5dd7070Spatrick // FIXME: Benchmark whether memoization of non-pointer typed nodes
65e5dd7070Spatrick // provides enough benefit for the additional amount of code.
66e5dd7070Spatrick struct MatchKey {
67e5dd7070Spatrick DynTypedMatcher::MatcherIDType MatcherID;
68ec727ea7Spatrick DynTypedNode Node;
69e5dd7070Spatrick BoundNodesTreeBuilder BoundNodes;
70ec727ea7Spatrick TraversalKind Traversal = TK_AsIs;
71ec727ea7Spatrick MatchType Type;
72e5dd7070Spatrick
operator <clang::ast_matchers::internal::__anonab4d286c0111::MatchKey73e5dd7070Spatrick bool operator<(const MatchKey &Other) const {
74ec727ea7Spatrick return std::tie(Traversal, Type, MatcherID, Node, BoundNodes) <
75ec727ea7Spatrick std::tie(Other.Traversal, Other.Type, Other.MatcherID, Other.Node,
76ec727ea7Spatrick Other.BoundNodes);
77e5dd7070Spatrick }
78e5dd7070Spatrick };
79e5dd7070Spatrick
80e5dd7070Spatrick // Used to store the result of a match and possibly bound nodes.
81e5dd7070Spatrick struct MemoizedMatchResult {
82e5dd7070Spatrick bool ResultOfMatch;
83e5dd7070Spatrick BoundNodesTreeBuilder Nodes;
84e5dd7070Spatrick };
85e5dd7070Spatrick
86e5dd7070Spatrick // A RecursiveASTVisitor that traverses all children or all descendants of
87e5dd7070Spatrick // a node.
88e5dd7070Spatrick class MatchChildASTVisitor
89e5dd7070Spatrick : public RecursiveASTVisitor<MatchChildASTVisitor> {
90e5dd7070Spatrick public:
91e5dd7070Spatrick typedef RecursiveASTVisitor<MatchChildASTVisitor> VisitorBase;
92e5dd7070Spatrick
93e5dd7070Spatrick // Creates an AST visitor that matches 'matcher' on all children or
94e5dd7070Spatrick // descendants of a traversed node. max_depth is the maximum depth
95e5dd7070Spatrick // to traverse: use 1 for matching the children and INT_MAX for
96e5dd7070Spatrick // matching the descendants.
MatchChildASTVisitor(const DynTypedMatcher * Matcher,ASTMatchFinder * Finder,BoundNodesTreeBuilder * Builder,int MaxDepth,bool IgnoreImplicitChildren,ASTMatchFinder::BindKind Bind)97e5dd7070Spatrick MatchChildASTVisitor(const DynTypedMatcher *Matcher, ASTMatchFinder *Finder,
98e5dd7070Spatrick BoundNodesTreeBuilder *Builder, int MaxDepth,
99a9ac8606Spatrick bool IgnoreImplicitChildren,
100a9ac8606Spatrick ASTMatchFinder::BindKind Bind)
101e5dd7070Spatrick : Matcher(Matcher), Finder(Finder), Builder(Builder), CurrentDepth(0),
102a9ac8606Spatrick MaxDepth(MaxDepth), IgnoreImplicitChildren(IgnoreImplicitChildren),
103a9ac8606Spatrick Bind(Bind), Matches(false) {}
104e5dd7070Spatrick
105e5dd7070Spatrick // Returns true if a match is found in the subtree rooted at the
106e5dd7070Spatrick // given AST node. This is done via a set of mutually recursive
107e5dd7070Spatrick // functions. Here's how the recursion is done (the *wildcard can
108e5dd7070Spatrick // actually be Decl, Stmt, or Type):
109e5dd7070Spatrick //
110e5dd7070Spatrick // - Traverse(node) calls BaseTraverse(node) when it needs
111e5dd7070Spatrick // to visit the descendants of node.
112e5dd7070Spatrick // - BaseTraverse(node) then calls (via VisitorBase::Traverse*(node))
113e5dd7070Spatrick // Traverse*(c) for each child c of 'node'.
114e5dd7070Spatrick // - Traverse*(c) in turn calls Traverse(c), completing the
115e5dd7070Spatrick // recursion.
findMatch(const DynTypedNode & DynNode)116ec727ea7Spatrick bool findMatch(const DynTypedNode &DynNode) {
117e5dd7070Spatrick reset();
118e5dd7070Spatrick if (const Decl *D = DynNode.get<Decl>())
119e5dd7070Spatrick traverse(*D);
120e5dd7070Spatrick else if (const Stmt *S = DynNode.get<Stmt>())
121e5dd7070Spatrick traverse(*S);
122e5dd7070Spatrick else if (const NestedNameSpecifier *NNS =
123e5dd7070Spatrick DynNode.get<NestedNameSpecifier>())
124e5dd7070Spatrick traverse(*NNS);
125e5dd7070Spatrick else if (const NestedNameSpecifierLoc *NNSLoc =
126e5dd7070Spatrick DynNode.get<NestedNameSpecifierLoc>())
127e5dd7070Spatrick traverse(*NNSLoc);
128e5dd7070Spatrick else if (const QualType *Q = DynNode.get<QualType>())
129e5dd7070Spatrick traverse(*Q);
130e5dd7070Spatrick else if (const TypeLoc *T = DynNode.get<TypeLoc>())
131e5dd7070Spatrick traverse(*T);
132e5dd7070Spatrick else if (const auto *C = DynNode.get<CXXCtorInitializer>())
133e5dd7070Spatrick traverse(*C);
134a9ac8606Spatrick else if (const TemplateArgumentLoc *TALoc =
135a9ac8606Spatrick DynNode.get<TemplateArgumentLoc>())
136a9ac8606Spatrick traverse(*TALoc);
137*12c85518Srobert else if (const Attr *A = DynNode.get<Attr>())
138*12c85518Srobert traverse(*A);
139e5dd7070Spatrick // FIXME: Add other base types after adding tests.
140e5dd7070Spatrick
141e5dd7070Spatrick // It's OK to always overwrite the bound nodes, as if there was
142e5dd7070Spatrick // no match in this recursive branch, the result set is empty
143e5dd7070Spatrick // anyway.
144e5dd7070Spatrick *Builder = ResultBindings;
145e5dd7070Spatrick
146e5dd7070Spatrick return Matches;
147e5dd7070Spatrick }
148e5dd7070Spatrick
149e5dd7070Spatrick // The following are overriding methods from the base visitor class.
150e5dd7070Spatrick // They are public only to allow CRTP to work. They are *not *part
151e5dd7070Spatrick // of the public API of this class.
TraverseDecl(Decl * DeclNode)152e5dd7070Spatrick bool TraverseDecl(Decl *DeclNode) {
153a9ac8606Spatrick
154a9ac8606Spatrick if (DeclNode && DeclNode->isImplicit() &&
155a9ac8606Spatrick Finder->isTraversalIgnoringImplicitNodes())
156a9ac8606Spatrick return baseTraverse(*DeclNode);
157a9ac8606Spatrick
158e5dd7070Spatrick ScopedIncrement ScopedDepth(&CurrentDepth);
159e5dd7070Spatrick return (DeclNode == nullptr) || traverse(*DeclNode);
160e5dd7070Spatrick }
161e5dd7070Spatrick
getStmtToTraverse(Stmt * StmtNode)162e5dd7070Spatrick Stmt *getStmtToTraverse(Stmt *StmtNode) {
163e5dd7070Spatrick Stmt *StmtToTraverse = StmtNode;
164e5dd7070Spatrick if (auto *ExprNode = dyn_cast_or_null<Expr>(StmtNode)) {
165e5dd7070Spatrick auto *LambdaNode = dyn_cast_or_null<LambdaExpr>(StmtNode);
166a9ac8606Spatrick if (LambdaNode && Finder->isTraversalIgnoringImplicitNodes())
167e5dd7070Spatrick StmtToTraverse = LambdaNode;
168e5dd7070Spatrick else
169ec727ea7Spatrick StmtToTraverse =
170ec727ea7Spatrick Finder->getASTContext().getParentMapContext().traverseIgnored(
171ec727ea7Spatrick ExprNode);
172e5dd7070Spatrick }
173e5dd7070Spatrick return StmtToTraverse;
174e5dd7070Spatrick }
175e5dd7070Spatrick
TraverseStmt(Stmt * StmtNode,DataRecursionQueue * Queue=nullptr)176e5dd7070Spatrick bool TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue = nullptr) {
177e5dd7070Spatrick // If we need to keep track of the depth, we can't perform data recursion.
178e5dd7070Spatrick if (CurrentDepth == 0 || (CurrentDepth <= MaxDepth && MaxDepth < INT_MAX))
179e5dd7070Spatrick Queue = nullptr;
180e5dd7070Spatrick
181e5dd7070Spatrick ScopedIncrement ScopedDepth(&CurrentDepth);
182e5dd7070Spatrick Stmt *StmtToTraverse = getStmtToTraverse(StmtNode);
183e5dd7070Spatrick if (!StmtToTraverse)
184e5dd7070Spatrick return true;
185a9ac8606Spatrick
186a9ac8606Spatrick if (IgnoreImplicitChildren && isa<CXXDefaultArgExpr>(StmtNode))
187a9ac8606Spatrick return true;
188a9ac8606Spatrick
189e5dd7070Spatrick if (!match(*StmtToTraverse))
190e5dd7070Spatrick return false;
191e5dd7070Spatrick return VisitorBase::TraverseStmt(StmtToTraverse, Queue);
192e5dd7070Spatrick }
193e5dd7070Spatrick // We assume that the QualType and the contained type are on the same
194e5dd7070Spatrick // hierarchy level. Thus, we try to match either of them.
TraverseType(QualType TypeNode)195e5dd7070Spatrick bool TraverseType(QualType TypeNode) {
196e5dd7070Spatrick if (TypeNode.isNull())
197e5dd7070Spatrick return true;
198e5dd7070Spatrick ScopedIncrement ScopedDepth(&CurrentDepth);
199e5dd7070Spatrick // Match the Type.
200e5dd7070Spatrick if (!match(*TypeNode))
201e5dd7070Spatrick return false;
202e5dd7070Spatrick // The QualType is matched inside traverse.
203e5dd7070Spatrick return traverse(TypeNode);
204e5dd7070Spatrick }
205e5dd7070Spatrick // We assume that the TypeLoc, contained QualType and contained Type all are
206e5dd7070Spatrick // on the same hierarchy level. Thus, we try to match all of them.
TraverseTypeLoc(TypeLoc TypeLocNode)207e5dd7070Spatrick bool TraverseTypeLoc(TypeLoc TypeLocNode) {
208e5dd7070Spatrick if (TypeLocNode.isNull())
209e5dd7070Spatrick return true;
210e5dd7070Spatrick ScopedIncrement ScopedDepth(&CurrentDepth);
211e5dd7070Spatrick // Match the Type.
212e5dd7070Spatrick if (!match(*TypeLocNode.getType()))
213e5dd7070Spatrick return false;
214e5dd7070Spatrick // Match the QualType.
215e5dd7070Spatrick if (!match(TypeLocNode.getType()))
216e5dd7070Spatrick return false;
217e5dd7070Spatrick // The TypeLoc is matched inside traverse.
218e5dd7070Spatrick return traverse(TypeLocNode);
219e5dd7070Spatrick }
TraverseNestedNameSpecifier(NestedNameSpecifier * NNS)220e5dd7070Spatrick bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {
221e5dd7070Spatrick ScopedIncrement ScopedDepth(&CurrentDepth);
222e5dd7070Spatrick return (NNS == nullptr) || traverse(*NNS);
223e5dd7070Spatrick }
TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS)224e5dd7070Spatrick bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
225e5dd7070Spatrick if (!NNS)
226e5dd7070Spatrick return true;
227e5dd7070Spatrick ScopedIncrement ScopedDepth(&CurrentDepth);
228e5dd7070Spatrick if (!match(*NNS.getNestedNameSpecifier()))
229e5dd7070Spatrick return false;
230e5dd7070Spatrick return traverse(NNS);
231e5dd7070Spatrick }
TraverseConstructorInitializer(CXXCtorInitializer * CtorInit)232e5dd7070Spatrick bool TraverseConstructorInitializer(CXXCtorInitializer *CtorInit) {
233e5dd7070Spatrick if (!CtorInit)
234e5dd7070Spatrick return true;
235e5dd7070Spatrick ScopedIncrement ScopedDepth(&CurrentDepth);
236e5dd7070Spatrick return traverse(*CtorInit);
237e5dd7070Spatrick }
TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL)238a9ac8606Spatrick bool TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL) {
239a9ac8606Spatrick ScopedIncrement ScopedDepth(&CurrentDepth);
240a9ac8606Spatrick return traverse(TAL);
241a9ac8606Spatrick }
TraverseCXXForRangeStmt(CXXForRangeStmt * Node)242a9ac8606Spatrick bool TraverseCXXForRangeStmt(CXXForRangeStmt *Node) {
243a9ac8606Spatrick if (!Finder->isTraversalIgnoringImplicitNodes())
244a9ac8606Spatrick return VisitorBase::TraverseCXXForRangeStmt(Node);
245a9ac8606Spatrick if (!Node)
246a9ac8606Spatrick return true;
247a9ac8606Spatrick ScopedIncrement ScopedDepth(&CurrentDepth);
248a9ac8606Spatrick if (auto *Init = Node->getInit())
249a9ac8606Spatrick if (!traverse(*Init))
250a9ac8606Spatrick return false;
251a9ac8606Spatrick if (!match(*Node->getLoopVariable()))
252a9ac8606Spatrick return false;
253a9ac8606Spatrick if (match(*Node->getRangeInit()))
254a9ac8606Spatrick if (!VisitorBase::TraverseStmt(Node->getRangeInit()))
255a9ac8606Spatrick return false;
256a9ac8606Spatrick if (!match(*Node->getBody()))
257a9ac8606Spatrick return false;
258a9ac8606Spatrick return VisitorBase::TraverseStmt(Node->getBody());
259a9ac8606Spatrick }
TraverseCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator * Node)260a9ac8606Spatrick bool TraverseCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *Node) {
261a9ac8606Spatrick if (!Finder->isTraversalIgnoringImplicitNodes())
262a9ac8606Spatrick return VisitorBase::TraverseCXXRewrittenBinaryOperator(Node);
263a9ac8606Spatrick if (!Node)
264a9ac8606Spatrick return true;
265a9ac8606Spatrick ScopedIncrement ScopedDepth(&CurrentDepth);
266a9ac8606Spatrick
267a9ac8606Spatrick return match(*Node->getLHS()) && match(*Node->getRHS());
268a9ac8606Spatrick }
TraverseAttr(Attr * A)269*12c85518Srobert bool TraverseAttr(Attr *A) {
270*12c85518Srobert if (A == nullptr ||
271*12c85518Srobert (A->isImplicit() &&
272*12c85518Srobert Finder->getASTContext().getParentMapContext().getTraversalKind() ==
273*12c85518Srobert TK_IgnoreUnlessSpelledInSource))
274*12c85518Srobert return true;
275*12c85518Srobert ScopedIncrement ScopedDepth(&CurrentDepth);
276*12c85518Srobert return traverse(*A);
277*12c85518Srobert }
TraverseLambdaExpr(LambdaExpr * Node)278e5dd7070Spatrick bool TraverseLambdaExpr(LambdaExpr *Node) {
279a9ac8606Spatrick if (!Finder->isTraversalIgnoringImplicitNodes())
280e5dd7070Spatrick return VisitorBase::TraverseLambdaExpr(Node);
281e5dd7070Spatrick if (!Node)
282e5dd7070Spatrick return true;
283e5dd7070Spatrick ScopedIncrement ScopedDepth(&CurrentDepth);
284e5dd7070Spatrick
285e5dd7070Spatrick for (unsigned I = 0, N = Node->capture_size(); I != N; ++I) {
286e5dd7070Spatrick const auto *C = Node->capture_begin() + I;
287e5dd7070Spatrick if (!C->isExplicit())
288e5dd7070Spatrick continue;
289e5dd7070Spatrick if (Node->isInitCapture(C) && !match(*C->getCapturedVar()))
290e5dd7070Spatrick return false;
291e5dd7070Spatrick if (!match(*Node->capture_init_begin()[I]))
292e5dd7070Spatrick return false;
293e5dd7070Spatrick }
294e5dd7070Spatrick
295e5dd7070Spatrick if (const auto *TPL = Node->getTemplateParameterList()) {
296e5dd7070Spatrick for (const auto *TP : *TPL) {
297e5dd7070Spatrick if (!match(*TP))
298e5dd7070Spatrick return false;
299e5dd7070Spatrick }
300e5dd7070Spatrick }
301e5dd7070Spatrick
302e5dd7070Spatrick for (const auto *P : Node->getCallOperator()->parameters()) {
303e5dd7070Spatrick if (!match(*P))
304e5dd7070Spatrick return false;
305e5dd7070Spatrick }
306e5dd7070Spatrick
307e5dd7070Spatrick if (!match(*Node->getBody()))
308e5dd7070Spatrick return false;
309e5dd7070Spatrick
310a9ac8606Spatrick return VisitorBase::TraverseStmt(Node->getBody());
311e5dd7070Spatrick }
312e5dd7070Spatrick
shouldVisitTemplateInstantiations() const313e5dd7070Spatrick bool shouldVisitTemplateInstantiations() const { return true; }
shouldVisitImplicitCode() const314a9ac8606Spatrick bool shouldVisitImplicitCode() const { return !IgnoreImplicitChildren; }
315e5dd7070Spatrick
316e5dd7070Spatrick private:
317e5dd7070Spatrick // Used for updating the depth during traversal.
318e5dd7070Spatrick struct ScopedIncrement {
ScopedIncrementclang::ast_matchers::internal::__anonab4d286c0111::MatchChildASTVisitor::ScopedIncrement319e5dd7070Spatrick explicit ScopedIncrement(int *Depth) : Depth(Depth) { ++(*Depth); }
~ScopedIncrementclang::ast_matchers::internal::__anonab4d286c0111::MatchChildASTVisitor::ScopedIncrement320e5dd7070Spatrick ~ScopedIncrement() { --(*Depth); }
321e5dd7070Spatrick
322e5dd7070Spatrick private:
323e5dd7070Spatrick int *Depth;
324e5dd7070Spatrick };
325e5dd7070Spatrick
326e5dd7070Spatrick // Resets the state of this object.
reset()327e5dd7070Spatrick void reset() {
328e5dd7070Spatrick Matches = false;
329e5dd7070Spatrick CurrentDepth = 0;
330e5dd7070Spatrick }
331e5dd7070Spatrick
332e5dd7070Spatrick // Forwards the call to the corresponding Traverse*() method in the
333e5dd7070Spatrick // base visitor class.
baseTraverse(const Decl & DeclNode)334e5dd7070Spatrick bool baseTraverse(const Decl &DeclNode) {
335e5dd7070Spatrick return VisitorBase::TraverseDecl(const_cast<Decl*>(&DeclNode));
336e5dd7070Spatrick }
baseTraverse(const Stmt & StmtNode)337e5dd7070Spatrick bool baseTraverse(const Stmt &StmtNode) {
338e5dd7070Spatrick return VisitorBase::TraverseStmt(const_cast<Stmt*>(&StmtNode));
339e5dd7070Spatrick }
baseTraverse(QualType TypeNode)340e5dd7070Spatrick bool baseTraverse(QualType TypeNode) {
341e5dd7070Spatrick return VisitorBase::TraverseType(TypeNode);
342e5dd7070Spatrick }
baseTraverse(TypeLoc TypeLocNode)343e5dd7070Spatrick bool baseTraverse(TypeLoc TypeLocNode) {
344e5dd7070Spatrick return VisitorBase::TraverseTypeLoc(TypeLocNode);
345e5dd7070Spatrick }
baseTraverse(const NestedNameSpecifier & NNS)346e5dd7070Spatrick bool baseTraverse(const NestedNameSpecifier &NNS) {
347e5dd7070Spatrick return VisitorBase::TraverseNestedNameSpecifier(
348e5dd7070Spatrick const_cast<NestedNameSpecifier*>(&NNS));
349e5dd7070Spatrick }
baseTraverse(NestedNameSpecifierLoc NNS)350e5dd7070Spatrick bool baseTraverse(NestedNameSpecifierLoc NNS) {
351e5dd7070Spatrick return VisitorBase::TraverseNestedNameSpecifierLoc(NNS);
352e5dd7070Spatrick }
baseTraverse(const CXXCtorInitializer & CtorInit)353e5dd7070Spatrick bool baseTraverse(const CXXCtorInitializer &CtorInit) {
354e5dd7070Spatrick return VisitorBase::TraverseConstructorInitializer(
355e5dd7070Spatrick const_cast<CXXCtorInitializer *>(&CtorInit));
356e5dd7070Spatrick }
baseTraverse(TemplateArgumentLoc TAL)357a9ac8606Spatrick bool baseTraverse(TemplateArgumentLoc TAL) {
358a9ac8606Spatrick return VisitorBase::TraverseTemplateArgumentLoc(TAL);
359a9ac8606Spatrick }
baseTraverse(const Attr & AttrNode)360*12c85518Srobert bool baseTraverse(const Attr &AttrNode) {
361*12c85518Srobert return VisitorBase::TraverseAttr(const_cast<Attr *>(&AttrNode));
362*12c85518Srobert }
363e5dd7070Spatrick
364e5dd7070Spatrick // Sets 'Matched' to true if 'Matcher' matches 'Node' and:
365e5dd7070Spatrick // 0 < CurrentDepth <= MaxDepth.
366e5dd7070Spatrick //
367e5dd7070Spatrick // Returns 'true' if traversal should continue after this function
368e5dd7070Spatrick // returns, i.e. if no match is found or 'Bind' is 'BK_All'.
369e5dd7070Spatrick template <typename T>
match(const T & Node)370e5dd7070Spatrick bool match(const T &Node) {
371e5dd7070Spatrick if (CurrentDepth == 0 || CurrentDepth > MaxDepth) {
372e5dd7070Spatrick return true;
373e5dd7070Spatrick }
374e5dd7070Spatrick if (Bind != ASTMatchFinder::BK_All) {
375e5dd7070Spatrick BoundNodesTreeBuilder RecursiveBuilder(*Builder);
376ec727ea7Spatrick if (Matcher->matches(DynTypedNode::create(Node), Finder,
377e5dd7070Spatrick &RecursiveBuilder)) {
378e5dd7070Spatrick Matches = true;
379e5dd7070Spatrick ResultBindings.addMatch(RecursiveBuilder);
380e5dd7070Spatrick return false; // Abort as soon as a match is found.
381e5dd7070Spatrick }
382e5dd7070Spatrick } else {
383e5dd7070Spatrick BoundNodesTreeBuilder RecursiveBuilder(*Builder);
384ec727ea7Spatrick if (Matcher->matches(DynTypedNode::create(Node), Finder,
385e5dd7070Spatrick &RecursiveBuilder)) {
386e5dd7070Spatrick // After the first match the matcher succeeds.
387e5dd7070Spatrick Matches = true;
388e5dd7070Spatrick ResultBindings.addMatch(RecursiveBuilder);
389e5dd7070Spatrick }
390e5dd7070Spatrick }
391e5dd7070Spatrick return true;
392e5dd7070Spatrick }
393e5dd7070Spatrick
394e5dd7070Spatrick // Traverses the subtree rooted at 'Node'; returns true if the
395e5dd7070Spatrick // traversal should continue after this function returns.
396e5dd7070Spatrick template <typename T>
traverse(const T & Node)397e5dd7070Spatrick bool traverse(const T &Node) {
398e5dd7070Spatrick static_assert(IsBaseType<T>::value,
399e5dd7070Spatrick "traverse can only be instantiated with base type");
400e5dd7070Spatrick if (!match(Node))
401e5dd7070Spatrick return false;
402e5dd7070Spatrick return baseTraverse(Node);
403e5dd7070Spatrick }
404e5dd7070Spatrick
405e5dd7070Spatrick const DynTypedMatcher *const Matcher;
406e5dd7070Spatrick ASTMatchFinder *const Finder;
407e5dd7070Spatrick BoundNodesTreeBuilder *const Builder;
408e5dd7070Spatrick BoundNodesTreeBuilder ResultBindings;
409e5dd7070Spatrick int CurrentDepth;
410e5dd7070Spatrick const int MaxDepth;
411a9ac8606Spatrick const bool IgnoreImplicitChildren;
412e5dd7070Spatrick const ASTMatchFinder::BindKind Bind;
413e5dd7070Spatrick bool Matches;
414e5dd7070Spatrick };
415e5dd7070Spatrick
416e5dd7070Spatrick // Controls the outermost traversal of the AST and allows to match multiple
417e5dd7070Spatrick // matchers.
418e5dd7070Spatrick class MatchASTVisitor : public RecursiveASTVisitor<MatchASTVisitor>,
419e5dd7070Spatrick public ASTMatchFinder {
420e5dd7070Spatrick public:
MatchASTVisitor(const MatchFinder::MatchersByType * Matchers,const MatchFinder::MatchFinderOptions & Options)421e5dd7070Spatrick MatchASTVisitor(const MatchFinder::MatchersByType *Matchers,
422e5dd7070Spatrick const MatchFinder::MatchFinderOptions &Options)
423e5dd7070Spatrick : Matchers(Matchers), Options(Options), ActiveASTContext(nullptr) {}
424e5dd7070Spatrick
~MatchASTVisitor()425e5dd7070Spatrick ~MatchASTVisitor() override {
426e5dd7070Spatrick if (Options.CheckProfiling) {
427e5dd7070Spatrick Options.CheckProfiling->Records = std::move(TimeByBucket);
428e5dd7070Spatrick }
429e5dd7070Spatrick }
430e5dd7070Spatrick
onStartOfTranslationUnit()431e5dd7070Spatrick void onStartOfTranslationUnit() {
432*12c85518Srobert const bool EnableCheckProfiling = Options.CheckProfiling.has_value();
433e5dd7070Spatrick TimeBucketRegion Timer;
434e5dd7070Spatrick for (MatchCallback *MC : Matchers->AllCallbacks) {
435e5dd7070Spatrick if (EnableCheckProfiling)
436e5dd7070Spatrick Timer.setBucket(&TimeByBucket[MC->getID()]);
437e5dd7070Spatrick MC->onStartOfTranslationUnit();
438e5dd7070Spatrick }
439e5dd7070Spatrick }
440e5dd7070Spatrick
onEndOfTranslationUnit()441e5dd7070Spatrick void onEndOfTranslationUnit() {
442*12c85518Srobert const bool EnableCheckProfiling = Options.CheckProfiling.has_value();
443e5dd7070Spatrick TimeBucketRegion Timer;
444e5dd7070Spatrick for (MatchCallback *MC : Matchers->AllCallbacks) {
445e5dd7070Spatrick if (EnableCheckProfiling)
446e5dd7070Spatrick Timer.setBucket(&TimeByBucket[MC->getID()]);
447e5dd7070Spatrick MC->onEndOfTranslationUnit();
448e5dd7070Spatrick }
449e5dd7070Spatrick }
450e5dd7070Spatrick
set_active_ast_context(ASTContext * NewActiveASTContext)451e5dd7070Spatrick void set_active_ast_context(ASTContext *NewActiveASTContext) {
452e5dd7070Spatrick ActiveASTContext = NewActiveASTContext;
453e5dd7070Spatrick }
454e5dd7070Spatrick
455e5dd7070Spatrick // The following Visit*() and Traverse*() functions "override"
456e5dd7070Spatrick // methods in RecursiveASTVisitor.
457e5dd7070Spatrick
VisitTypedefNameDecl(TypedefNameDecl * DeclNode)458e5dd7070Spatrick bool VisitTypedefNameDecl(TypedefNameDecl *DeclNode) {
459e5dd7070Spatrick // When we see 'typedef A B', we add name 'B' to the set of names
460e5dd7070Spatrick // A's canonical type maps to. This is necessary for implementing
461e5dd7070Spatrick // isDerivedFrom(x) properly, where x can be the name of the base
462e5dd7070Spatrick // class or any of its aliases.
463e5dd7070Spatrick //
464e5dd7070Spatrick // In general, the is-alias-of (as defined by typedefs) relation
465e5dd7070Spatrick // is tree-shaped, as you can typedef a type more than once. For
466e5dd7070Spatrick // example,
467e5dd7070Spatrick //
468e5dd7070Spatrick // typedef A B;
469e5dd7070Spatrick // typedef A C;
470e5dd7070Spatrick // typedef C D;
471e5dd7070Spatrick // typedef C E;
472e5dd7070Spatrick //
473e5dd7070Spatrick // gives you
474e5dd7070Spatrick //
475e5dd7070Spatrick // A
476e5dd7070Spatrick // |- B
477e5dd7070Spatrick // `- C
478e5dd7070Spatrick // |- D
479e5dd7070Spatrick // `- E
480e5dd7070Spatrick //
481e5dd7070Spatrick // It is wrong to assume that the relation is a chain. A correct
482e5dd7070Spatrick // implementation of isDerivedFrom() needs to recognize that B and
483e5dd7070Spatrick // E are aliases, even though neither is a typedef of the other.
484e5dd7070Spatrick // Therefore, we cannot simply walk through one typedef chain to
485e5dd7070Spatrick // find out whether the type name matches.
486e5dd7070Spatrick const Type *TypeNode = DeclNode->getUnderlyingType().getTypePtr();
487e5dd7070Spatrick const Type *CanonicalType = // root of the typedef tree
488e5dd7070Spatrick ActiveASTContext->getCanonicalType(TypeNode);
489e5dd7070Spatrick TypeAliases[CanonicalType].insert(DeclNode);
490e5dd7070Spatrick return true;
491e5dd7070Spatrick }
492e5dd7070Spatrick
VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl * CAD)493e5dd7070Spatrick bool VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) {
494e5dd7070Spatrick const ObjCInterfaceDecl *InterfaceDecl = CAD->getClassInterface();
495e5dd7070Spatrick CompatibleAliases[InterfaceDecl].insert(CAD);
496e5dd7070Spatrick return true;
497e5dd7070Spatrick }
498e5dd7070Spatrick
499e5dd7070Spatrick bool TraverseDecl(Decl *DeclNode);
500e5dd7070Spatrick bool TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue = nullptr);
501e5dd7070Spatrick bool TraverseType(QualType TypeNode);
502e5dd7070Spatrick bool TraverseTypeLoc(TypeLoc TypeNode);
503e5dd7070Spatrick bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS);
504e5dd7070Spatrick bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);
505e5dd7070Spatrick bool TraverseConstructorInitializer(CXXCtorInitializer *CtorInit);
506a9ac8606Spatrick bool TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL);
507*12c85518Srobert bool TraverseAttr(Attr *AttrNode);
508a9ac8606Spatrick
dataTraverseNode(Stmt * S,DataRecursionQueue * Queue)509a9ac8606Spatrick bool dataTraverseNode(Stmt *S, DataRecursionQueue *Queue) {
510a9ac8606Spatrick if (auto *RF = dyn_cast<CXXForRangeStmt>(S)) {
511a9ac8606Spatrick {
512a9ac8606Spatrick ASTNodeNotAsIsSourceScope RAII(this, true);
513a9ac8606Spatrick TraverseStmt(RF->getInit());
514a9ac8606Spatrick // Don't traverse under the loop variable
515a9ac8606Spatrick match(*RF->getLoopVariable());
516a9ac8606Spatrick TraverseStmt(RF->getRangeInit());
517a9ac8606Spatrick }
518a9ac8606Spatrick {
519a9ac8606Spatrick ASTNodeNotSpelledInSourceScope RAII(this, true);
520a9ac8606Spatrick for (auto *SubStmt : RF->children()) {
521a9ac8606Spatrick if (SubStmt != RF->getBody())
522a9ac8606Spatrick TraverseStmt(SubStmt);
523a9ac8606Spatrick }
524a9ac8606Spatrick }
525a9ac8606Spatrick TraverseStmt(RF->getBody());
526a9ac8606Spatrick return true;
527a9ac8606Spatrick } else if (auto *RBO = dyn_cast<CXXRewrittenBinaryOperator>(S)) {
528a9ac8606Spatrick {
529a9ac8606Spatrick ASTNodeNotAsIsSourceScope RAII(this, true);
530a9ac8606Spatrick TraverseStmt(const_cast<Expr *>(RBO->getLHS()));
531a9ac8606Spatrick TraverseStmt(const_cast<Expr *>(RBO->getRHS()));
532a9ac8606Spatrick }
533a9ac8606Spatrick {
534a9ac8606Spatrick ASTNodeNotSpelledInSourceScope RAII(this, true);
535a9ac8606Spatrick for (auto *SubStmt : RBO->children()) {
536a9ac8606Spatrick TraverseStmt(SubStmt);
537a9ac8606Spatrick }
538a9ac8606Spatrick }
539a9ac8606Spatrick return true;
540a9ac8606Spatrick } else if (auto *LE = dyn_cast<LambdaExpr>(S)) {
541a9ac8606Spatrick for (auto I : llvm::zip(LE->captures(), LE->capture_inits())) {
542a9ac8606Spatrick auto C = std::get<0>(I);
543a9ac8606Spatrick ASTNodeNotSpelledInSourceScope RAII(
544a9ac8606Spatrick this, TraversingASTNodeNotSpelledInSource || !C.isExplicit());
545a9ac8606Spatrick TraverseLambdaCapture(LE, &C, std::get<1>(I));
546a9ac8606Spatrick }
547a9ac8606Spatrick
548a9ac8606Spatrick {
549a9ac8606Spatrick ASTNodeNotSpelledInSourceScope RAII(this, true);
550a9ac8606Spatrick TraverseDecl(LE->getLambdaClass());
551a9ac8606Spatrick }
552a9ac8606Spatrick {
553a9ac8606Spatrick ASTNodeNotAsIsSourceScope RAII(this, true);
554a9ac8606Spatrick
555a9ac8606Spatrick // We need to poke around to find the bits that might be explicitly
556a9ac8606Spatrick // written.
557a9ac8606Spatrick TypeLoc TL = LE->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
558a9ac8606Spatrick FunctionProtoTypeLoc Proto = TL.getAsAdjusted<FunctionProtoTypeLoc>();
559a9ac8606Spatrick
560a9ac8606Spatrick if (auto *TPL = LE->getTemplateParameterList()) {
561a9ac8606Spatrick for (NamedDecl *D : *TPL) {
562a9ac8606Spatrick TraverseDecl(D);
563a9ac8606Spatrick }
564a9ac8606Spatrick if (Expr *RequiresClause = TPL->getRequiresClause()) {
565a9ac8606Spatrick TraverseStmt(RequiresClause);
566a9ac8606Spatrick }
567a9ac8606Spatrick }
568a9ac8606Spatrick
569a9ac8606Spatrick if (LE->hasExplicitParameters()) {
570a9ac8606Spatrick // Visit parameters.
571a9ac8606Spatrick for (ParmVarDecl *Param : Proto.getParams())
572a9ac8606Spatrick TraverseDecl(Param);
573a9ac8606Spatrick }
574a9ac8606Spatrick
575a9ac8606Spatrick const auto *T = Proto.getTypePtr();
576a9ac8606Spatrick for (const auto &E : T->exceptions())
577a9ac8606Spatrick TraverseType(E);
578a9ac8606Spatrick
579a9ac8606Spatrick if (Expr *NE = T->getNoexceptExpr())
580a9ac8606Spatrick TraverseStmt(NE, Queue);
581a9ac8606Spatrick
582a9ac8606Spatrick if (LE->hasExplicitResultType())
583a9ac8606Spatrick TraverseTypeLoc(Proto.getReturnLoc());
584a9ac8606Spatrick TraverseStmt(LE->getTrailingRequiresClause());
585a9ac8606Spatrick }
586a9ac8606Spatrick
587a9ac8606Spatrick TraverseStmt(LE->getBody());
588a9ac8606Spatrick return true;
589a9ac8606Spatrick }
590a9ac8606Spatrick return RecursiveASTVisitor<MatchASTVisitor>::dataTraverseNode(S, Queue);
591a9ac8606Spatrick }
592e5dd7070Spatrick
593e5dd7070Spatrick // Matches children or descendants of 'Node' with 'BaseMatcher'.
memoizedMatchesRecursively(const DynTypedNode & Node,ASTContext & Ctx,const DynTypedMatcher & Matcher,BoundNodesTreeBuilder * Builder,int MaxDepth,BindKind Bind)594ec727ea7Spatrick bool memoizedMatchesRecursively(const DynTypedNode &Node, ASTContext &Ctx,
595e5dd7070Spatrick const DynTypedMatcher &Matcher,
596e5dd7070Spatrick BoundNodesTreeBuilder *Builder, int MaxDepth,
597a9ac8606Spatrick BindKind Bind) {
598e5dd7070Spatrick // For AST-nodes that don't have an identity, we can't memoize.
599e5dd7070Spatrick if (!Node.getMemoizationData() || !Builder->isComparable())
600a9ac8606Spatrick return matchesRecursively(Node, Matcher, Builder, MaxDepth, Bind);
601e5dd7070Spatrick
602e5dd7070Spatrick MatchKey Key;
603e5dd7070Spatrick Key.MatcherID = Matcher.getID();
604e5dd7070Spatrick Key.Node = Node;
605e5dd7070Spatrick // Note that we key on the bindings *before* the match.
606e5dd7070Spatrick Key.BoundNodes = *Builder;
607ec727ea7Spatrick Key.Traversal = Ctx.getParentMapContext().getTraversalKind();
608ec727ea7Spatrick // Memoize result even doing a single-level match, it might be expensive.
609ec727ea7Spatrick Key.Type = MaxDepth == 1 ? MatchType::Child : MatchType::Descendants;
610e5dd7070Spatrick MemoizationMap::iterator I = ResultCache.find(Key);
611e5dd7070Spatrick if (I != ResultCache.end()) {
612e5dd7070Spatrick *Builder = I->second.Nodes;
613e5dd7070Spatrick return I->second.ResultOfMatch;
614e5dd7070Spatrick }
615e5dd7070Spatrick
616e5dd7070Spatrick MemoizedMatchResult Result;
617e5dd7070Spatrick Result.Nodes = *Builder;
618a9ac8606Spatrick Result.ResultOfMatch =
619a9ac8606Spatrick matchesRecursively(Node, Matcher, &Result.Nodes, MaxDepth, Bind);
620e5dd7070Spatrick
621e5dd7070Spatrick MemoizedMatchResult &CachedResult = ResultCache[Key];
622e5dd7070Spatrick CachedResult = std::move(Result);
623e5dd7070Spatrick
624e5dd7070Spatrick *Builder = CachedResult.Nodes;
625e5dd7070Spatrick return CachedResult.ResultOfMatch;
626e5dd7070Spatrick }
627e5dd7070Spatrick
628e5dd7070Spatrick // Matches children or descendants of 'Node' with 'BaseMatcher'.
matchesRecursively(const DynTypedNode & Node,const DynTypedMatcher & Matcher,BoundNodesTreeBuilder * Builder,int MaxDepth,BindKind Bind)629ec727ea7Spatrick bool matchesRecursively(const DynTypedNode &Node,
630e5dd7070Spatrick const DynTypedMatcher &Matcher,
631e5dd7070Spatrick BoundNodesTreeBuilder *Builder, int MaxDepth,
632a9ac8606Spatrick BindKind Bind) {
633a9ac8606Spatrick bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
634a9ac8606Spatrick TraversingASTChildrenNotSpelledInSource;
635a9ac8606Spatrick
636a9ac8606Spatrick bool IgnoreImplicitChildren = false;
637a9ac8606Spatrick
638a9ac8606Spatrick if (isTraversalIgnoringImplicitNodes()) {
639a9ac8606Spatrick IgnoreImplicitChildren = true;
640a9ac8606Spatrick }
641a9ac8606Spatrick
642a9ac8606Spatrick ASTNodeNotSpelledInSourceScope RAII(this, ScopedTraversal);
643a9ac8606Spatrick
644a9ac8606Spatrick MatchChildASTVisitor Visitor(&Matcher, this, Builder, MaxDepth,
645a9ac8606Spatrick IgnoreImplicitChildren, Bind);
646e5dd7070Spatrick return Visitor.findMatch(Node);
647e5dd7070Spatrick }
648e5dd7070Spatrick
649e5dd7070Spatrick bool classIsDerivedFrom(const CXXRecordDecl *Declaration,
650e5dd7070Spatrick const Matcher<NamedDecl> &Base,
651e5dd7070Spatrick BoundNodesTreeBuilder *Builder,
652e5dd7070Spatrick bool Directly) override;
653e5dd7070Spatrick
654e5dd7070Spatrick bool objcClassIsDerivedFrom(const ObjCInterfaceDecl *Declaration,
655e5dd7070Spatrick const Matcher<NamedDecl> &Base,
656e5dd7070Spatrick BoundNodesTreeBuilder *Builder,
657e5dd7070Spatrick bool Directly) override;
658e5dd7070Spatrick
659e5dd7070Spatrick // Implements ASTMatchFinder::matchesChildOf.
matchesChildOf(const DynTypedNode & Node,ASTContext & Ctx,const DynTypedMatcher & Matcher,BoundNodesTreeBuilder * Builder,BindKind Bind)660ec727ea7Spatrick bool matchesChildOf(const DynTypedNode &Node, ASTContext &Ctx,
661ec727ea7Spatrick const DynTypedMatcher &Matcher,
662a9ac8606Spatrick BoundNodesTreeBuilder *Builder, BindKind Bind) override {
663e5dd7070Spatrick if (ResultCache.size() > MaxMemoizationEntries)
664e5dd7070Spatrick ResultCache.clear();
665a9ac8606Spatrick return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder, 1, Bind);
666e5dd7070Spatrick }
667e5dd7070Spatrick // Implements ASTMatchFinder::matchesDescendantOf.
matchesDescendantOf(const DynTypedNode & Node,ASTContext & Ctx,const DynTypedMatcher & Matcher,BoundNodesTreeBuilder * Builder,BindKind Bind)668ec727ea7Spatrick bool matchesDescendantOf(const DynTypedNode &Node, ASTContext &Ctx,
669ec727ea7Spatrick const DynTypedMatcher &Matcher,
670e5dd7070Spatrick BoundNodesTreeBuilder *Builder,
671e5dd7070Spatrick BindKind Bind) override {
672e5dd7070Spatrick if (ResultCache.size() > MaxMemoizationEntries)
673e5dd7070Spatrick ResultCache.clear();
674e5dd7070Spatrick return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder, INT_MAX,
675a9ac8606Spatrick Bind);
676e5dd7070Spatrick }
677e5dd7070Spatrick // Implements ASTMatchFinder::matchesAncestorOf.
matchesAncestorOf(const DynTypedNode & Node,ASTContext & Ctx,const DynTypedMatcher & Matcher,BoundNodesTreeBuilder * Builder,AncestorMatchMode MatchMode)678ec727ea7Spatrick bool matchesAncestorOf(const DynTypedNode &Node, ASTContext &Ctx,
679ec727ea7Spatrick const DynTypedMatcher &Matcher,
680e5dd7070Spatrick BoundNodesTreeBuilder *Builder,
681e5dd7070Spatrick AncestorMatchMode MatchMode) override {
682e5dd7070Spatrick // Reset the cache outside of the recursive call to make sure we
683e5dd7070Spatrick // don't invalidate any iterators.
684e5dd7070Spatrick if (ResultCache.size() > MaxMemoizationEntries)
685e5dd7070Spatrick ResultCache.clear();
686a9ac8606Spatrick if (MatchMode == AncestorMatchMode::AMM_ParentOnly)
687a9ac8606Spatrick return matchesParentOf(Node, Matcher, Builder);
688a9ac8606Spatrick return matchesAnyAncestorOf(Node, Ctx, Matcher, Builder);
689e5dd7070Spatrick }
690e5dd7070Spatrick
691e5dd7070Spatrick // Matches all registered matchers on the given node and calls the
692e5dd7070Spatrick // result callback for every node that matches.
match(const DynTypedNode & Node)693ec727ea7Spatrick void match(const DynTypedNode &Node) {
694e5dd7070Spatrick // FIXME: Improve this with a switch or a visitor pattern.
695e5dd7070Spatrick if (auto *N = Node.get<Decl>()) {
696e5dd7070Spatrick match(*N);
697e5dd7070Spatrick } else if (auto *N = Node.get<Stmt>()) {
698e5dd7070Spatrick match(*N);
699e5dd7070Spatrick } else if (auto *N = Node.get<Type>()) {
700e5dd7070Spatrick match(*N);
701e5dd7070Spatrick } else if (auto *N = Node.get<QualType>()) {
702e5dd7070Spatrick match(*N);
703e5dd7070Spatrick } else if (auto *N = Node.get<NestedNameSpecifier>()) {
704e5dd7070Spatrick match(*N);
705e5dd7070Spatrick } else if (auto *N = Node.get<NestedNameSpecifierLoc>()) {
706e5dd7070Spatrick match(*N);
707e5dd7070Spatrick } else if (auto *N = Node.get<TypeLoc>()) {
708e5dd7070Spatrick match(*N);
709e5dd7070Spatrick } else if (auto *N = Node.get<CXXCtorInitializer>()) {
710e5dd7070Spatrick match(*N);
711a9ac8606Spatrick } else if (auto *N = Node.get<TemplateArgumentLoc>()) {
712a9ac8606Spatrick match(*N);
713*12c85518Srobert } else if (auto *N = Node.get<Attr>()) {
714*12c85518Srobert match(*N);
715e5dd7070Spatrick }
716e5dd7070Spatrick }
717e5dd7070Spatrick
match(const T & Node)718e5dd7070Spatrick template <typename T> void match(const T &Node) {
719e5dd7070Spatrick matchDispatch(&Node);
720e5dd7070Spatrick }
721e5dd7070Spatrick
722e5dd7070Spatrick // Implements ASTMatchFinder::getASTContext.
getASTContext() const723e5dd7070Spatrick ASTContext &getASTContext() const override { return *ActiveASTContext; }
724e5dd7070Spatrick
shouldVisitTemplateInstantiations() const725e5dd7070Spatrick bool shouldVisitTemplateInstantiations() const { return true; }
shouldVisitImplicitCode() const726e5dd7070Spatrick bool shouldVisitImplicitCode() const { return true; }
727e5dd7070Spatrick
728a9ac8606Spatrick // We visit the lambda body explicitly, so instruct the RAV
729a9ac8606Spatrick // to not visit it on our behalf too.
shouldVisitLambdaBody() const730a9ac8606Spatrick bool shouldVisitLambdaBody() const { return false; }
731a9ac8606Spatrick
IsMatchingInASTNodeNotSpelledInSource() const732a9ac8606Spatrick bool IsMatchingInASTNodeNotSpelledInSource() const override {
733a9ac8606Spatrick return TraversingASTNodeNotSpelledInSource;
734a9ac8606Spatrick }
isMatchingChildrenNotSpelledInSource() const735a9ac8606Spatrick bool isMatchingChildrenNotSpelledInSource() const override {
736a9ac8606Spatrick return TraversingASTChildrenNotSpelledInSource;
737a9ac8606Spatrick }
setMatchingChildrenNotSpelledInSource(bool Set)738a9ac8606Spatrick void setMatchingChildrenNotSpelledInSource(bool Set) override {
739a9ac8606Spatrick TraversingASTChildrenNotSpelledInSource = Set;
740a9ac8606Spatrick }
741a9ac8606Spatrick
IsMatchingInASTNodeNotAsIs() const742a9ac8606Spatrick bool IsMatchingInASTNodeNotAsIs() const override {
743a9ac8606Spatrick return TraversingASTNodeNotAsIs;
744a9ac8606Spatrick }
745a9ac8606Spatrick
TraverseTemplateInstantiations(ClassTemplateDecl * D)746a9ac8606Spatrick bool TraverseTemplateInstantiations(ClassTemplateDecl *D) {
747a9ac8606Spatrick ASTNodeNotSpelledInSourceScope RAII(this, true);
748a9ac8606Spatrick return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
749a9ac8606Spatrick D);
750a9ac8606Spatrick }
751a9ac8606Spatrick
TraverseTemplateInstantiations(VarTemplateDecl * D)752a9ac8606Spatrick bool TraverseTemplateInstantiations(VarTemplateDecl *D) {
753a9ac8606Spatrick ASTNodeNotSpelledInSourceScope RAII(this, true);
754a9ac8606Spatrick return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
755a9ac8606Spatrick D);
756a9ac8606Spatrick }
757a9ac8606Spatrick
TraverseTemplateInstantiations(FunctionTemplateDecl * D)758a9ac8606Spatrick bool TraverseTemplateInstantiations(FunctionTemplateDecl *D) {
759a9ac8606Spatrick ASTNodeNotSpelledInSourceScope RAII(this, true);
760a9ac8606Spatrick return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
761a9ac8606Spatrick D);
762a9ac8606Spatrick }
763a9ac8606Spatrick
764e5dd7070Spatrick private:
765a9ac8606Spatrick bool TraversingASTNodeNotSpelledInSource = false;
766a9ac8606Spatrick bool TraversingASTNodeNotAsIs = false;
767a9ac8606Spatrick bool TraversingASTChildrenNotSpelledInSource = false;
768a9ac8606Spatrick
769*12c85518Srobert class CurMatchData {
770*12c85518Srobert // We don't have enough free low bits in 32bit builds to discriminate 8 pointer
771*12c85518Srobert // types in PointerUnion. so split the union in 2 using a free bit from the
772*12c85518Srobert // callback pointer.
773*12c85518Srobert #define CMD_TYPES_0 \
774*12c85518Srobert const QualType *, const TypeLoc *, const NestedNameSpecifier *, \
775*12c85518Srobert const NestedNameSpecifierLoc *
776*12c85518Srobert #define CMD_TYPES_1 \
777*12c85518Srobert const CXXCtorInitializer *, const TemplateArgumentLoc *, const Attr *, \
778*12c85518Srobert const DynTypedNode *
779*12c85518Srobert
780*12c85518Srobert #define IMPL(Index) \
781*12c85518Srobert template <typename NodeType> \
782*12c85518Srobert std::enable_if_t< \
783*12c85518Srobert llvm::is_one_of<const NodeType *, CMD_TYPES_##Index>::value> \
784*12c85518Srobert SetCallbackAndRawNode(const MatchCallback *CB, const NodeType &N) { \
785*12c85518Srobert assertEmpty(); \
786*12c85518Srobert Callback.setPointerAndInt(CB, Index); \
787*12c85518Srobert Node##Index = &N; \
788*12c85518Srobert } \
789*12c85518Srobert \
790*12c85518Srobert template <typename T> \
791*12c85518Srobert std::enable_if_t<llvm::is_one_of<const T *, CMD_TYPES_##Index>::value, \
792*12c85518Srobert const T *> \
793*12c85518Srobert getNode() const { \
794*12c85518Srobert assertHoldsState(); \
795*12c85518Srobert return Callback.getInt() == (Index) ? Node##Index.dyn_cast<const T *>() \
796*12c85518Srobert : nullptr; \
797*12c85518Srobert }
798*12c85518Srobert
799*12c85518Srobert public:
CurMatchData()800*12c85518Srobert CurMatchData() : Node0(nullptr) {}
801*12c85518Srobert
802*12c85518Srobert IMPL(0)
803*12c85518Srobert IMPL(1)
804*12c85518Srobert
getCallback() const805*12c85518Srobert const MatchCallback *getCallback() const { return Callback.getPointer(); }
806*12c85518Srobert
SetBoundNodes(const BoundNodes & BN)807*12c85518Srobert void SetBoundNodes(const BoundNodes &BN) {
808*12c85518Srobert assertHoldsState();
809*12c85518Srobert BNodes = &BN;
810*12c85518Srobert }
811*12c85518Srobert
clearBoundNodes()812*12c85518Srobert void clearBoundNodes() {
813*12c85518Srobert assertHoldsState();
814*12c85518Srobert BNodes = nullptr;
815*12c85518Srobert }
816*12c85518Srobert
getBoundNodes() const817*12c85518Srobert const BoundNodes *getBoundNodes() const {
818*12c85518Srobert assertHoldsState();
819*12c85518Srobert return BNodes;
820*12c85518Srobert }
821*12c85518Srobert
reset()822*12c85518Srobert void reset() {
823*12c85518Srobert assertHoldsState();
824*12c85518Srobert Callback.setPointerAndInt(nullptr, 0);
825*12c85518Srobert Node0 = nullptr;
826*12c85518Srobert }
827*12c85518Srobert
828*12c85518Srobert private:
assertHoldsState() const829*12c85518Srobert void assertHoldsState() const {
830*12c85518Srobert assert(Callback.getPointer() != nullptr && !Node0.isNull());
831*12c85518Srobert }
832*12c85518Srobert
assertEmpty() const833*12c85518Srobert void assertEmpty() const {
834*12c85518Srobert assert(Callback.getPointer() == nullptr && Node0.isNull() &&
835*12c85518Srobert BNodes == nullptr);
836*12c85518Srobert }
837*12c85518Srobert
838*12c85518Srobert llvm::PointerIntPair<const MatchCallback *, 1> Callback;
839*12c85518Srobert union {
840*12c85518Srobert llvm::PointerUnion<CMD_TYPES_0> Node0;
841*12c85518Srobert llvm::PointerUnion<CMD_TYPES_1> Node1;
842*12c85518Srobert };
843*12c85518Srobert const BoundNodes *BNodes = nullptr;
844*12c85518Srobert
845*12c85518Srobert #undef CMD_TYPES_0
846*12c85518Srobert #undef CMD_TYPES_1
847*12c85518Srobert #undef IMPL
848*12c85518Srobert } CurMatchState;
849*12c85518Srobert
850*12c85518Srobert struct CurMatchRAII {
851*12c85518Srobert template <typename NodeType>
CurMatchRAIIclang::ast_matchers::internal::__anonab4d286c0111::MatchASTVisitor::CurMatchRAII852*12c85518Srobert CurMatchRAII(MatchASTVisitor &MV, const MatchCallback *CB,
853*12c85518Srobert const NodeType &NT)
854*12c85518Srobert : MV(MV) {
855*12c85518Srobert MV.CurMatchState.SetCallbackAndRawNode(CB, NT);
856*12c85518Srobert }
857*12c85518Srobert
~CurMatchRAIIclang::ast_matchers::internal::__anonab4d286c0111::MatchASTVisitor::CurMatchRAII858*12c85518Srobert ~CurMatchRAII() { MV.CurMatchState.reset(); }
859*12c85518Srobert
860*12c85518Srobert private:
861*12c85518Srobert MatchASTVisitor &MV;
862*12c85518Srobert };
863*12c85518Srobert
864*12c85518Srobert public:
865*12c85518Srobert class TraceReporter : llvm::PrettyStackTraceEntry {
dumpNode(const ASTContext & Ctx,const DynTypedNode & Node,raw_ostream & OS)866*12c85518Srobert static void dumpNode(const ASTContext &Ctx, const DynTypedNode &Node,
867*12c85518Srobert raw_ostream &OS) {
868*12c85518Srobert if (const auto *D = Node.get<Decl>()) {
869*12c85518Srobert OS << D->getDeclKindName() << "Decl ";
870*12c85518Srobert if (const auto *ND = dyn_cast<NamedDecl>(D)) {
871*12c85518Srobert ND->printQualifiedName(OS);
872*12c85518Srobert OS << " : ";
873*12c85518Srobert } else
874*12c85518Srobert OS << ": ";
875*12c85518Srobert D->getSourceRange().print(OS, Ctx.getSourceManager());
876*12c85518Srobert } else if (const auto *S = Node.get<Stmt>()) {
877*12c85518Srobert OS << S->getStmtClassName() << " : ";
878*12c85518Srobert S->getSourceRange().print(OS, Ctx.getSourceManager());
879*12c85518Srobert } else if (const auto *T = Node.get<Type>()) {
880*12c85518Srobert OS << T->getTypeClassName() << "Type : ";
881*12c85518Srobert QualType(T, 0).print(OS, Ctx.getPrintingPolicy());
882*12c85518Srobert } else if (const auto *QT = Node.get<QualType>()) {
883*12c85518Srobert OS << "QualType : ";
884*12c85518Srobert QT->print(OS, Ctx.getPrintingPolicy());
885*12c85518Srobert } else {
886*12c85518Srobert OS << Node.getNodeKind().asStringRef() << " : ";
887*12c85518Srobert Node.getSourceRange().print(OS, Ctx.getSourceManager());
888*12c85518Srobert }
889*12c85518Srobert }
890*12c85518Srobert
dumpNodeFromState(const ASTContext & Ctx,const CurMatchData & State,raw_ostream & OS)891*12c85518Srobert static void dumpNodeFromState(const ASTContext &Ctx,
892*12c85518Srobert const CurMatchData &State, raw_ostream &OS) {
893*12c85518Srobert if (const DynTypedNode *MatchNode = State.getNode<DynTypedNode>()) {
894*12c85518Srobert dumpNode(Ctx, *MatchNode, OS);
895*12c85518Srobert } else if (const auto *QT = State.getNode<QualType>()) {
896*12c85518Srobert dumpNode(Ctx, DynTypedNode::create(*QT), OS);
897*12c85518Srobert } else if (const auto *TL = State.getNode<TypeLoc>()) {
898*12c85518Srobert dumpNode(Ctx, DynTypedNode::create(*TL), OS);
899*12c85518Srobert } else if (const auto *NNS = State.getNode<NestedNameSpecifier>()) {
900*12c85518Srobert dumpNode(Ctx, DynTypedNode::create(*NNS), OS);
901*12c85518Srobert } else if (const auto *NNSL = State.getNode<NestedNameSpecifierLoc>()) {
902*12c85518Srobert dumpNode(Ctx, DynTypedNode::create(*NNSL), OS);
903*12c85518Srobert } else if (const auto *CtorInit = State.getNode<CXXCtorInitializer>()) {
904*12c85518Srobert dumpNode(Ctx, DynTypedNode::create(*CtorInit), OS);
905*12c85518Srobert } else if (const auto *TAL = State.getNode<TemplateArgumentLoc>()) {
906*12c85518Srobert dumpNode(Ctx, DynTypedNode::create(*TAL), OS);
907*12c85518Srobert } else if (const auto *At = State.getNode<Attr>()) {
908*12c85518Srobert dumpNode(Ctx, DynTypedNode::create(*At), OS);
909*12c85518Srobert }
910*12c85518Srobert }
911*12c85518Srobert
912*12c85518Srobert public:
TraceReporter(const MatchASTVisitor & MV)913*12c85518Srobert TraceReporter(const MatchASTVisitor &MV) : MV(MV) {}
print(raw_ostream & OS) const914*12c85518Srobert void print(raw_ostream &OS) const override {
915*12c85518Srobert const CurMatchData &State = MV.CurMatchState;
916*12c85518Srobert const MatchCallback *CB = State.getCallback();
917*12c85518Srobert if (!CB) {
918*12c85518Srobert OS << "ASTMatcher: Not currently matching\n";
919*12c85518Srobert return;
920*12c85518Srobert }
921*12c85518Srobert
922*12c85518Srobert assert(MV.ActiveASTContext &&
923*12c85518Srobert "ActiveASTContext should be set if there is a matched callback");
924*12c85518Srobert
925*12c85518Srobert ASTContext &Ctx = MV.getASTContext();
926*12c85518Srobert
927*12c85518Srobert if (const BoundNodes *Nodes = State.getBoundNodes()) {
928*12c85518Srobert OS << "ASTMatcher: Processing '" << CB->getID() << "' against:\n\t";
929*12c85518Srobert dumpNodeFromState(Ctx, State, OS);
930*12c85518Srobert const BoundNodes::IDToNodeMap &Map = Nodes->getMap();
931*12c85518Srobert if (Map.empty()) {
932*12c85518Srobert OS << "\nNo bound nodes\n";
933*12c85518Srobert return;
934*12c85518Srobert }
935*12c85518Srobert OS << "\n--- Bound Nodes Begin ---\n";
936*12c85518Srobert for (const auto &Item : Map) {
937*12c85518Srobert OS << " " << Item.first << " - { ";
938*12c85518Srobert dumpNode(Ctx, Item.second, OS);
939*12c85518Srobert OS << " }\n";
940*12c85518Srobert }
941*12c85518Srobert OS << "--- Bound Nodes End ---\n";
942*12c85518Srobert } else {
943*12c85518Srobert OS << "ASTMatcher: Matching '" << CB->getID() << "' against:\n\t";
944*12c85518Srobert dumpNodeFromState(Ctx, State, OS);
945*12c85518Srobert OS << '\n';
946*12c85518Srobert }
947*12c85518Srobert }
948*12c85518Srobert
949*12c85518Srobert private:
950*12c85518Srobert const MatchASTVisitor &MV;
951*12c85518Srobert };
952*12c85518Srobert
953*12c85518Srobert private:
954a9ac8606Spatrick struct ASTNodeNotSpelledInSourceScope {
ASTNodeNotSpelledInSourceScopeclang::ast_matchers::internal::__anonab4d286c0111::MatchASTVisitor::ASTNodeNotSpelledInSourceScope955a9ac8606Spatrick ASTNodeNotSpelledInSourceScope(MatchASTVisitor *V, bool B)
956a9ac8606Spatrick : MV(V), MB(V->TraversingASTNodeNotSpelledInSource) {
957a9ac8606Spatrick V->TraversingASTNodeNotSpelledInSource = B;
958a9ac8606Spatrick }
~ASTNodeNotSpelledInSourceScopeclang::ast_matchers::internal::__anonab4d286c0111::MatchASTVisitor::ASTNodeNotSpelledInSourceScope959a9ac8606Spatrick ~ASTNodeNotSpelledInSourceScope() {
960a9ac8606Spatrick MV->TraversingASTNodeNotSpelledInSource = MB;
961a9ac8606Spatrick }
962a9ac8606Spatrick
963a9ac8606Spatrick private:
964a9ac8606Spatrick MatchASTVisitor *MV;
965a9ac8606Spatrick bool MB;
966a9ac8606Spatrick };
967a9ac8606Spatrick
968a9ac8606Spatrick struct ASTNodeNotAsIsSourceScope {
ASTNodeNotAsIsSourceScopeclang::ast_matchers::internal::__anonab4d286c0111::MatchASTVisitor::ASTNodeNotAsIsSourceScope969a9ac8606Spatrick ASTNodeNotAsIsSourceScope(MatchASTVisitor *V, bool B)
970a9ac8606Spatrick : MV(V), MB(V->TraversingASTNodeNotAsIs) {
971a9ac8606Spatrick V->TraversingASTNodeNotAsIs = B;
972a9ac8606Spatrick }
~ASTNodeNotAsIsSourceScopeclang::ast_matchers::internal::__anonab4d286c0111::MatchASTVisitor::ASTNodeNotAsIsSourceScope973a9ac8606Spatrick ~ASTNodeNotAsIsSourceScope() { MV->TraversingASTNodeNotAsIs = MB; }
974a9ac8606Spatrick
975a9ac8606Spatrick private:
976a9ac8606Spatrick MatchASTVisitor *MV;
977a9ac8606Spatrick bool MB;
978a9ac8606Spatrick };
979a9ac8606Spatrick
980e5dd7070Spatrick class TimeBucketRegion {
981e5dd7070Spatrick public:
TimeBucketRegion()982e5dd7070Spatrick TimeBucketRegion() : Bucket(nullptr) {}
~TimeBucketRegion()983e5dd7070Spatrick ~TimeBucketRegion() { setBucket(nullptr); }
984e5dd7070Spatrick
985e5dd7070Spatrick /// Start timing for \p NewBucket.
986e5dd7070Spatrick ///
987e5dd7070Spatrick /// If there was a bucket already set, it will finish the timing for that
988e5dd7070Spatrick /// other bucket.
989e5dd7070Spatrick /// \p NewBucket will be timed until the next call to \c setBucket() or
990e5dd7070Spatrick /// until the \c TimeBucketRegion is destroyed.
991e5dd7070Spatrick /// If \p NewBucket is the same as the currently timed bucket, this call
992e5dd7070Spatrick /// does nothing.
setBucket(llvm::TimeRecord * NewBucket)993e5dd7070Spatrick void setBucket(llvm::TimeRecord *NewBucket) {
994e5dd7070Spatrick if (Bucket != NewBucket) {
995e5dd7070Spatrick auto Now = llvm::TimeRecord::getCurrentTime(true);
996e5dd7070Spatrick if (Bucket)
997e5dd7070Spatrick *Bucket += Now;
998e5dd7070Spatrick if (NewBucket)
999e5dd7070Spatrick *NewBucket -= Now;
1000e5dd7070Spatrick Bucket = NewBucket;
1001e5dd7070Spatrick }
1002e5dd7070Spatrick }
1003e5dd7070Spatrick
1004e5dd7070Spatrick private:
1005e5dd7070Spatrick llvm::TimeRecord *Bucket;
1006e5dd7070Spatrick };
1007e5dd7070Spatrick
1008e5dd7070Spatrick /// Runs all the \p Matchers on \p Node.
1009e5dd7070Spatrick ///
1010e5dd7070Spatrick /// Used by \c matchDispatch() below.
1011e5dd7070Spatrick template <typename T, typename MC>
matchWithoutFilter(const T & Node,const MC & Matchers)1012e5dd7070Spatrick void matchWithoutFilter(const T &Node, const MC &Matchers) {
1013*12c85518Srobert const bool EnableCheckProfiling = Options.CheckProfiling.has_value();
1014e5dd7070Spatrick TimeBucketRegion Timer;
1015e5dd7070Spatrick for (const auto &MP : Matchers) {
1016e5dd7070Spatrick if (EnableCheckProfiling)
1017e5dd7070Spatrick Timer.setBucket(&TimeByBucket[MP.second->getID()]);
1018e5dd7070Spatrick BoundNodesTreeBuilder Builder;
1019*12c85518Srobert CurMatchRAII RAII(*this, MP.second, Node);
1020e5dd7070Spatrick if (MP.first.matches(Node, this, &Builder)) {
1021*12c85518Srobert MatchVisitor Visitor(*this, ActiveASTContext, MP.second);
1022e5dd7070Spatrick Builder.visitMatches(&Visitor);
1023e5dd7070Spatrick }
1024e5dd7070Spatrick }
1025e5dd7070Spatrick }
1026e5dd7070Spatrick
matchWithFilter(const DynTypedNode & DynNode)1027ec727ea7Spatrick void matchWithFilter(const DynTypedNode &DynNode) {
1028e5dd7070Spatrick auto Kind = DynNode.getNodeKind();
1029e5dd7070Spatrick auto it = MatcherFiltersMap.find(Kind);
1030e5dd7070Spatrick const auto &Filter =
1031e5dd7070Spatrick it != MatcherFiltersMap.end() ? it->second : getFilterForKind(Kind);
1032e5dd7070Spatrick
1033e5dd7070Spatrick if (Filter.empty())
1034e5dd7070Spatrick return;
1035e5dd7070Spatrick
1036*12c85518Srobert const bool EnableCheckProfiling = Options.CheckProfiling.has_value();
1037e5dd7070Spatrick TimeBucketRegion Timer;
1038e5dd7070Spatrick auto &Matchers = this->Matchers->DeclOrStmt;
1039e5dd7070Spatrick for (unsigned short I : Filter) {
1040e5dd7070Spatrick auto &MP = Matchers[I];
1041e5dd7070Spatrick if (EnableCheckProfiling)
1042e5dd7070Spatrick Timer.setBucket(&TimeByBucket[MP.second->getID()]);
1043e5dd7070Spatrick BoundNodesTreeBuilder Builder;
1044a9ac8606Spatrick
1045a9ac8606Spatrick {
1046a9ac8606Spatrick TraversalKindScope RAII(getASTContext(), MP.first.getTraversalKind());
1047a9ac8606Spatrick if (getASTContext().getParentMapContext().traverseIgnored(DynNode) !=
1048a9ac8606Spatrick DynNode)
1049a9ac8606Spatrick continue;
1050a9ac8606Spatrick }
1051a9ac8606Spatrick
1052*12c85518Srobert CurMatchRAII RAII(*this, MP.second, DynNode);
1053e5dd7070Spatrick if (MP.first.matches(DynNode, this, &Builder)) {
1054*12c85518Srobert MatchVisitor Visitor(*this, ActiveASTContext, MP.second);
1055e5dd7070Spatrick Builder.visitMatches(&Visitor);
1056e5dd7070Spatrick }
1057e5dd7070Spatrick }
1058e5dd7070Spatrick }
1059e5dd7070Spatrick
getFilterForKind(ASTNodeKind Kind)1060ec727ea7Spatrick const std::vector<unsigned short> &getFilterForKind(ASTNodeKind Kind) {
1061e5dd7070Spatrick auto &Filter = MatcherFiltersMap[Kind];
1062e5dd7070Spatrick auto &Matchers = this->Matchers->DeclOrStmt;
1063e5dd7070Spatrick assert((Matchers.size() < USHRT_MAX) && "Too many matchers.");
1064e5dd7070Spatrick for (unsigned I = 0, E = Matchers.size(); I != E; ++I) {
1065e5dd7070Spatrick if (Matchers[I].first.canMatchNodesOfKind(Kind)) {
1066e5dd7070Spatrick Filter.push_back(I);
1067e5dd7070Spatrick }
1068e5dd7070Spatrick }
1069e5dd7070Spatrick return Filter;
1070e5dd7070Spatrick }
1071e5dd7070Spatrick
1072e5dd7070Spatrick /// @{
1073e5dd7070Spatrick /// Overloads to pair the different node types to their matchers.
matchDispatch(const Decl * Node)1074e5dd7070Spatrick void matchDispatch(const Decl *Node) {
1075ec727ea7Spatrick return matchWithFilter(DynTypedNode::create(*Node));
1076e5dd7070Spatrick }
matchDispatch(const Stmt * Node)1077e5dd7070Spatrick void matchDispatch(const Stmt *Node) {
1078ec727ea7Spatrick return matchWithFilter(DynTypedNode::create(*Node));
1079e5dd7070Spatrick }
1080e5dd7070Spatrick
matchDispatch(const Type * Node)1081e5dd7070Spatrick void matchDispatch(const Type *Node) {
1082e5dd7070Spatrick matchWithoutFilter(QualType(Node, 0), Matchers->Type);
1083e5dd7070Spatrick }
matchDispatch(const TypeLoc * Node)1084e5dd7070Spatrick void matchDispatch(const TypeLoc *Node) {
1085e5dd7070Spatrick matchWithoutFilter(*Node, Matchers->TypeLoc);
1086e5dd7070Spatrick }
matchDispatch(const QualType * Node)1087e5dd7070Spatrick void matchDispatch(const QualType *Node) {
1088e5dd7070Spatrick matchWithoutFilter(*Node, Matchers->Type);
1089e5dd7070Spatrick }
matchDispatch(const NestedNameSpecifier * Node)1090e5dd7070Spatrick void matchDispatch(const NestedNameSpecifier *Node) {
1091e5dd7070Spatrick matchWithoutFilter(*Node, Matchers->NestedNameSpecifier);
1092e5dd7070Spatrick }
matchDispatch(const NestedNameSpecifierLoc * Node)1093e5dd7070Spatrick void matchDispatch(const NestedNameSpecifierLoc *Node) {
1094e5dd7070Spatrick matchWithoutFilter(*Node, Matchers->NestedNameSpecifierLoc);
1095e5dd7070Spatrick }
matchDispatch(const CXXCtorInitializer * Node)1096e5dd7070Spatrick void matchDispatch(const CXXCtorInitializer *Node) {
1097e5dd7070Spatrick matchWithoutFilter(*Node, Matchers->CtorInit);
1098e5dd7070Spatrick }
matchDispatch(const TemplateArgumentLoc * Node)1099a9ac8606Spatrick void matchDispatch(const TemplateArgumentLoc *Node) {
1100a9ac8606Spatrick matchWithoutFilter(*Node, Matchers->TemplateArgumentLoc);
1101a9ac8606Spatrick }
matchDispatch(const Attr * Node)1102*12c85518Srobert void matchDispatch(const Attr *Node) {
1103*12c85518Srobert matchWithoutFilter(*Node, Matchers->Attr);
1104*12c85518Srobert }
matchDispatch(const void *)1105e5dd7070Spatrick void matchDispatch(const void *) { /* Do nothing. */ }
1106e5dd7070Spatrick /// @}
1107e5dd7070Spatrick
1108a9ac8606Spatrick // Returns whether a direct parent of \p Node matches \p Matcher.
1109a9ac8606Spatrick // Unlike matchesAnyAncestorOf there's no memoization: it doesn't save much.
matchesParentOf(const DynTypedNode & Node,const DynTypedMatcher & Matcher,BoundNodesTreeBuilder * Builder)1110a9ac8606Spatrick bool matchesParentOf(const DynTypedNode &Node, const DynTypedMatcher &Matcher,
1111a9ac8606Spatrick BoundNodesTreeBuilder *Builder) {
1112a9ac8606Spatrick for (const auto &Parent : ActiveASTContext->getParents(Node)) {
1113a9ac8606Spatrick BoundNodesTreeBuilder BuilderCopy = *Builder;
1114a9ac8606Spatrick if (Matcher.matches(Parent, this, &BuilderCopy)) {
1115a9ac8606Spatrick *Builder = std::move(BuilderCopy);
1116a9ac8606Spatrick return true;
1117a9ac8606Spatrick }
1118a9ac8606Spatrick }
1119a9ac8606Spatrick return false;
1120a9ac8606Spatrick }
1121a9ac8606Spatrick
1122e5dd7070Spatrick // Returns whether an ancestor of \p Node matches \p Matcher.
1123e5dd7070Spatrick //
1124a9ac8606Spatrick // The order of matching (which can lead to different nodes being bound in
1125e5dd7070Spatrick // case there are multiple matches) is breadth first search.
1126e5dd7070Spatrick //
1127e5dd7070Spatrick // To allow memoization in the very common case of having deeply nested
1128e5dd7070Spatrick // expressions inside a template function, we first walk up the AST, memoizing
1129e5dd7070Spatrick // the result of the match along the way, as long as there is only a single
1130e5dd7070Spatrick // parent.
1131e5dd7070Spatrick //
1132e5dd7070Spatrick // Once there are multiple parents, the breadth first search order does not
1133e5dd7070Spatrick // allow simple memoization on the ancestors. Thus, we only memoize as long
1134e5dd7070Spatrick // as there is a single parent.
1135a9ac8606Spatrick //
1136a9ac8606Spatrick // We avoid a recursive implementation to prevent excessive stack use on
1137a9ac8606Spatrick // very deep ASTs (similarly to RecursiveASTVisitor's data recursion).
matchesAnyAncestorOf(DynTypedNode Node,ASTContext & Ctx,const DynTypedMatcher & Matcher,BoundNodesTreeBuilder * Builder)1138a9ac8606Spatrick bool matchesAnyAncestorOf(DynTypedNode Node, ASTContext &Ctx,
1139ec727ea7Spatrick const DynTypedMatcher &Matcher,
1140a9ac8606Spatrick BoundNodesTreeBuilder *Builder) {
1141e5dd7070Spatrick
1142a9ac8606Spatrick // Memoization keys that can be updated with the result.
1143a9ac8606Spatrick // These are the memoizable nodes in the chain of unique parents, which
1144a9ac8606Spatrick // terminates when a node has multiple parents, or matches, or is the root.
1145a9ac8606Spatrick std::vector<MatchKey> Keys;
1146a9ac8606Spatrick // When returning, update the memoization cache.
1147a9ac8606Spatrick auto Finish = [&](bool Matched) {
1148a9ac8606Spatrick for (const auto &Key : Keys) {
1149e5dd7070Spatrick MemoizedMatchResult &CachedResult = ResultCache[Key];
1150a9ac8606Spatrick CachedResult.ResultOfMatch = Matched;
1151a9ac8606Spatrick CachedResult.Nodes = *Builder;
1152a9ac8606Spatrick }
1153a9ac8606Spatrick return Matched;
1154a9ac8606Spatrick };
1155e5dd7070Spatrick
1156a9ac8606Spatrick // Loop while there's a single parent and we want to attempt memoization.
1157a9ac8606Spatrick DynTypedNodeList Parents{ArrayRef<DynTypedNode>()}; // after loop: size != 1
1158a9ac8606Spatrick for (;;) {
1159a9ac8606Spatrick // A cache key only makes sense if memoization is possible.
1160a9ac8606Spatrick if (Builder->isComparable()) {
1161a9ac8606Spatrick Keys.emplace_back();
1162a9ac8606Spatrick Keys.back().MatcherID = Matcher.getID();
1163a9ac8606Spatrick Keys.back().Node = Node;
1164a9ac8606Spatrick Keys.back().BoundNodes = *Builder;
1165a9ac8606Spatrick Keys.back().Traversal = Ctx.getParentMapContext().getTraversalKind();
1166a9ac8606Spatrick Keys.back().Type = MatchType::Ancestors;
1167a9ac8606Spatrick
1168a9ac8606Spatrick // Check the cache.
1169a9ac8606Spatrick MemoizationMap::iterator I = ResultCache.find(Keys.back());
1170a9ac8606Spatrick if (I != ResultCache.end()) {
1171a9ac8606Spatrick Keys.pop_back(); // Don't populate the cache for the matching node!
1172a9ac8606Spatrick *Builder = I->second.Nodes;
1173a9ac8606Spatrick return Finish(I->second.ResultOfMatch);
1174a9ac8606Spatrick }
1175e5dd7070Spatrick }
1176e5dd7070Spatrick
1177a9ac8606Spatrick Parents = ActiveASTContext->getParents(Node);
1178a9ac8606Spatrick // Either no parents or multiple parents: leave chain+memoize mode and
1179a9ac8606Spatrick // enter bfs+forgetful mode.
1180a9ac8606Spatrick if (Parents.size() != 1)
1181a9ac8606Spatrick break;
1182a9ac8606Spatrick
1183a9ac8606Spatrick // Check the next parent.
1184a9ac8606Spatrick Node = *Parents.begin();
1185a9ac8606Spatrick BoundNodesTreeBuilder BuilderCopy = *Builder;
1186a9ac8606Spatrick if (Matcher.matches(Node, this, &BuilderCopy)) {
1187a9ac8606Spatrick *Builder = std::move(BuilderCopy);
1188a9ac8606Spatrick return Finish(true);
1189a9ac8606Spatrick }
1190a9ac8606Spatrick }
1191a9ac8606Spatrick // We reached the end of the chain.
1192a9ac8606Spatrick
1193e5dd7070Spatrick if (Parents.empty()) {
1194e5dd7070Spatrick // Nodes may have no parents if:
1195e5dd7070Spatrick // a) the node is the TranslationUnitDecl
1196e5dd7070Spatrick // b) we have a limited traversal scope that excludes the parent edges
1197e5dd7070Spatrick // c) there is a bug in the AST, and the node is not reachable
1198e5dd7070Spatrick // Usually the traversal scope is the whole AST, which precludes b.
1199e5dd7070Spatrick // Bugs are common enough that it's worthwhile asserting when we can.
1200e5dd7070Spatrick #ifndef NDEBUG
1201e5dd7070Spatrick if (!Node.get<TranslationUnitDecl>() &&
1202e5dd7070Spatrick /* Traversal scope is full AST if any of the bounds are the TU */
1203e5dd7070Spatrick llvm::any_of(ActiveASTContext->getTraversalScope(), [](Decl *D) {
1204e5dd7070Spatrick return D->getKind() == Decl::TranslationUnit;
1205e5dd7070Spatrick })) {
1206e5dd7070Spatrick llvm::errs() << "Tried to match orphan node:\n";
1207ec727ea7Spatrick Node.dump(llvm::errs(), *ActiveASTContext);
1208e5dd7070Spatrick llvm_unreachable("Parent map should be complete!");
1209e5dd7070Spatrick }
1210e5dd7070Spatrick #endif
1211e5dd7070Spatrick } else {
1212a9ac8606Spatrick assert(Parents.size() > 1);
1213a9ac8606Spatrick // BFS starting from the parents not yet considered.
1214a9ac8606Spatrick // Memoization of newly visited nodes is not possible (but we still update
1215a9ac8606Spatrick // results for the elements in the chain we found above).
1216ec727ea7Spatrick std::deque<DynTypedNode> Queue(Parents.begin(), Parents.end());
1217a9ac8606Spatrick llvm::DenseSet<const void *> Visited;
1218e5dd7070Spatrick while (!Queue.empty()) {
1219e5dd7070Spatrick BoundNodesTreeBuilder BuilderCopy = *Builder;
1220e5dd7070Spatrick if (Matcher.matches(Queue.front(), this, &BuilderCopy)) {
1221e5dd7070Spatrick *Builder = std::move(BuilderCopy);
1222a9ac8606Spatrick return Finish(true);
1223e5dd7070Spatrick }
1224a9ac8606Spatrick for (const auto &Parent : ActiveASTContext->getParents(Queue.front())) {
1225e5dd7070Spatrick // Make sure we do not visit the same node twice.
1226e5dd7070Spatrick // Otherwise, we'll visit the common ancestors as often as there
1227e5dd7070Spatrick // are splits on the way down.
1228e5dd7070Spatrick if (Visited.insert(Parent.getMemoizationData()).second)
1229e5dd7070Spatrick Queue.push_back(Parent);
1230e5dd7070Spatrick }
1231e5dd7070Spatrick Queue.pop_front();
1232e5dd7070Spatrick }
1233e5dd7070Spatrick }
1234a9ac8606Spatrick return Finish(false);
1235e5dd7070Spatrick }
1236e5dd7070Spatrick
1237e5dd7070Spatrick // Implements a BoundNodesTree::Visitor that calls a MatchCallback with
1238e5dd7070Spatrick // the aggregated bound nodes for each match.
1239e5dd7070Spatrick class MatchVisitor : public BoundNodesTreeBuilder::Visitor {
1240*12c85518Srobert struct CurBoundScope {
CurBoundScopeclang::ast_matchers::internal::__anonab4d286c0111::MatchASTVisitor::MatchVisitor::CurBoundScope1241*12c85518Srobert CurBoundScope(MatchASTVisitor::CurMatchData &State, const BoundNodes &BN)
1242*12c85518Srobert : State(State) {
1243*12c85518Srobert State.SetBoundNodes(BN);
1244*12c85518Srobert }
1245*12c85518Srobert
~CurBoundScopeclang::ast_matchers::internal::__anonab4d286c0111::MatchASTVisitor::MatchVisitor::CurBoundScope1246*12c85518Srobert ~CurBoundScope() { State.clearBoundNodes(); }
1247*12c85518Srobert
1248*12c85518Srobert private:
1249*12c85518Srobert MatchASTVisitor::CurMatchData &State;
1250*12c85518Srobert };
1251*12c85518Srobert
1252e5dd7070Spatrick public:
MatchVisitor(MatchASTVisitor & MV,ASTContext * Context,MatchFinder::MatchCallback * Callback)1253*12c85518Srobert MatchVisitor(MatchASTVisitor &MV, ASTContext *Context,
1254e5dd7070Spatrick MatchFinder::MatchCallback *Callback)
1255*12c85518Srobert : State(MV.CurMatchState), Context(Context), Callback(Callback) {}
1256e5dd7070Spatrick
visitMatch(const BoundNodes & BoundNodesView)1257e5dd7070Spatrick void visitMatch(const BoundNodes& BoundNodesView) override {
1258a9ac8606Spatrick TraversalKindScope RAII(*Context, Callback->getCheckTraversalKind());
1259*12c85518Srobert CurBoundScope RAII2(State, BoundNodesView);
1260e5dd7070Spatrick Callback->run(MatchFinder::MatchResult(BoundNodesView, Context));
1261e5dd7070Spatrick }
1262e5dd7070Spatrick
1263e5dd7070Spatrick private:
1264*12c85518Srobert MatchASTVisitor::CurMatchData &State;
1265e5dd7070Spatrick ASTContext* Context;
1266e5dd7070Spatrick MatchFinder::MatchCallback* Callback;
1267e5dd7070Spatrick };
1268e5dd7070Spatrick
1269e5dd7070Spatrick // Returns true if 'TypeNode' has an alias that matches the given matcher.
typeHasMatchingAlias(const Type * TypeNode,const Matcher<NamedDecl> & Matcher,BoundNodesTreeBuilder * Builder)1270e5dd7070Spatrick bool typeHasMatchingAlias(const Type *TypeNode,
1271e5dd7070Spatrick const Matcher<NamedDecl> &Matcher,
1272e5dd7070Spatrick BoundNodesTreeBuilder *Builder) {
1273e5dd7070Spatrick const Type *const CanonicalType =
1274e5dd7070Spatrick ActiveASTContext->getCanonicalType(TypeNode);
1275e5dd7070Spatrick auto Aliases = TypeAliases.find(CanonicalType);
1276e5dd7070Spatrick if (Aliases == TypeAliases.end())
1277e5dd7070Spatrick return false;
1278e5dd7070Spatrick for (const TypedefNameDecl *Alias : Aliases->second) {
1279e5dd7070Spatrick BoundNodesTreeBuilder Result(*Builder);
1280e5dd7070Spatrick if (Matcher.matches(*Alias, this, &Result)) {
1281e5dd7070Spatrick *Builder = std::move(Result);
1282e5dd7070Spatrick return true;
1283e5dd7070Spatrick }
1284e5dd7070Spatrick }
1285e5dd7070Spatrick return false;
1286e5dd7070Spatrick }
1287e5dd7070Spatrick
1288e5dd7070Spatrick bool
objcClassHasMatchingCompatibilityAlias(const ObjCInterfaceDecl * InterfaceDecl,const Matcher<NamedDecl> & Matcher,BoundNodesTreeBuilder * Builder)1289e5dd7070Spatrick objcClassHasMatchingCompatibilityAlias(const ObjCInterfaceDecl *InterfaceDecl,
1290e5dd7070Spatrick const Matcher<NamedDecl> &Matcher,
1291e5dd7070Spatrick BoundNodesTreeBuilder *Builder) {
1292e5dd7070Spatrick auto Aliases = CompatibleAliases.find(InterfaceDecl);
1293e5dd7070Spatrick if (Aliases == CompatibleAliases.end())
1294e5dd7070Spatrick return false;
1295e5dd7070Spatrick for (const ObjCCompatibleAliasDecl *Alias : Aliases->second) {
1296e5dd7070Spatrick BoundNodesTreeBuilder Result(*Builder);
1297e5dd7070Spatrick if (Matcher.matches(*Alias, this, &Result)) {
1298e5dd7070Spatrick *Builder = std::move(Result);
1299e5dd7070Spatrick return true;
1300e5dd7070Spatrick }
1301e5dd7070Spatrick }
1302e5dd7070Spatrick return false;
1303e5dd7070Spatrick }
1304e5dd7070Spatrick
1305e5dd7070Spatrick /// Bucket to record map.
1306e5dd7070Spatrick ///
1307e5dd7070Spatrick /// Used to get the appropriate bucket for each matcher.
1308e5dd7070Spatrick llvm::StringMap<llvm::TimeRecord> TimeByBucket;
1309e5dd7070Spatrick
1310e5dd7070Spatrick const MatchFinder::MatchersByType *Matchers;
1311e5dd7070Spatrick
1312e5dd7070Spatrick /// Filtered list of matcher indices for each matcher kind.
1313e5dd7070Spatrick ///
1314e5dd7070Spatrick /// \c Decl and \c Stmt toplevel matchers usually apply to a specific node
1315e5dd7070Spatrick /// kind (and derived kinds) so it is a waste to try every matcher on every
1316e5dd7070Spatrick /// node.
1317e5dd7070Spatrick /// We precalculate a list of matchers that pass the toplevel restrict check.
1318ec727ea7Spatrick llvm::DenseMap<ASTNodeKind, std::vector<unsigned short>> MatcherFiltersMap;
1319e5dd7070Spatrick
1320e5dd7070Spatrick const MatchFinder::MatchFinderOptions &Options;
1321e5dd7070Spatrick ASTContext *ActiveASTContext;
1322e5dd7070Spatrick
1323e5dd7070Spatrick // Maps a canonical type to its TypedefDecls.
1324e5dd7070Spatrick llvm::DenseMap<const Type*, std::set<const TypedefNameDecl*> > TypeAliases;
1325e5dd7070Spatrick
1326e5dd7070Spatrick // Maps an Objective-C interface to its ObjCCompatibleAliasDecls.
1327e5dd7070Spatrick llvm::DenseMap<const ObjCInterfaceDecl *,
1328e5dd7070Spatrick llvm::SmallPtrSet<const ObjCCompatibleAliasDecl *, 2>>
1329e5dd7070Spatrick CompatibleAliases;
1330e5dd7070Spatrick
1331e5dd7070Spatrick // Maps (matcher, node) -> the match result for memoization.
1332e5dd7070Spatrick typedef std::map<MatchKey, MemoizedMatchResult> MemoizationMap;
1333e5dd7070Spatrick MemoizationMap ResultCache;
1334e5dd7070Spatrick };
1335e5dd7070Spatrick
1336e5dd7070Spatrick static CXXRecordDecl *
getAsCXXRecordDeclOrPrimaryTemplate(const Type * TypeNode)1337e5dd7070Spatrick getAsCXXRecordDeclOrPrimaryTemplate(const Type *TypeNode) {
1338e5dd7070Spatrick if (auto *RD = TypeNode->getAsCXXRecordDecl())
1339e5dd7070Spatrick return RD;
1340e5dd7070Spatrick
1341e5dd7070Spatrick // Find the innermost TemplateSpecializationType that isn't an alias template.
1342e5dd7070Spatrick auto *TemplateType = TypeNode->getAs<TemplateSpecializationType>();
1343e5dd7070Spatrick while (TemplateType && TemplateType->isTypeAlias())
1344e5dd7070Spatrick TemplateType =
1345e5dd7070Spatrick TemplateType->getAliasedType()->getAs<TemplateSpecializationType>();
1346e5dd7070Spatrick
1347e5dd7070Spatrick // If this is the name of a (dependent) template specialization, use the
1348e5dd7070Spatrick // definition of the template, even though it might be specialized later.
1349e5dd7070Spatrick if (TemplateType)
1350e5dd7070Spatrick if (auto *ClassTemplate = dyn_cast_or_null<ClassTemplateDecl>(
1351e5dd7070Spatrick TemplateType->getTemplateName().getAsTemplateDecl()))
1352e5dd7070Spatrick return ClassTemplate->getTemplatedDecl();
1353e5dd7070Spatrick
1354e5dd7070Spatrick return nullptr;
1355e5dd7070Spatrick }
1356e5dd7070Spatrick
1357e5dd7070Spatrick // Returns true if the given C++ class is directly or indirectly derived
1358e5dd7070Spatrick // from a base type with the given name. A class is not considered to be
1359e5dd7070Spatrick // derived from itself.
classIsDerivedFrom(const CXXRecordDecl * Declaration,const Matcher<NamedDecl> & Base,BoundNodesTreeBuilder * Builder,bool Directly)1360e5dd7070Spatrick bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
1361e5dd7070Spatrick const Matcher<NamedDecl> &Base,
1362e5dd7070Spatrick BoundNodesTreeBuilder *Builder,
1363e5dd7070Spatrick bool Directly) {
1364e5dd7070Spatrick if (!Declaration->hasDefinition())
1365e5dd7070Spatrick return false;
1366e5dd7070Spatrick for (const auto &It : Declaration->bases()) {
1367e5dd7070Spatrick const Type *TypeNode = It.getType().getTypePtr();
1368e5dd7070Spatrick
1369e5dd7070Spatrick if (typeHasMatchingAlias(TypeNode, Base, Builder))
1370e5dd7070Spatrick return true;
1371e5dd7070Spatrick
1372e5dd7070Spatrick // FIXME: Going to the primary template here isn't really correct, but
1373e5dd7070Spatrick // unfortunately we accept a Decl matcher for the base class not a Type
1374e5dd7070Spatrick // matcher, so it's the best thing we can do with our current interface.
1375e5dd7070Spatrick CXXRecordDecl *ClassDecl = getAsCXXRecordDeclOrPrimaryTemplate(TypeNode);
1376e5dd7070Spatrick if (!ClassDecl)
1377e5dd7070Spatrick continue;
1378e5dd7070Spatrick if (ClassDecl == Declaration) {
1379ec727ea7Spatrick // This can happen for recursive template definitions.
1380ec727ea7Spatrick continue;
1381e5dd7070Spatrick }
1382e5dd7070Spatrick BoundNodesTreeBuilder Result(*Builder);
1383e5dd7070Spatrick if (Base.matches(*ClassDecl, this, &Result)) {
1384e5dd7070Spatrick *Builder = std::move(Result);
1385e5dd7070Spatrick return true;
1386e5dd7070Spatrick }
1387e5dd7070Spatrick if (!Directly && classIsDerivedFrom(ClassDecl, Base, Builder, Directly))
1388e5dd7070Spatrick return true;
1389e5dd7070Spatrick }
1390e5dd7070Spatrick return false;
1391e5dd7070Spatrick }
1392e5dd7070Spatrick
1393e5dd7070Spatrick // Returns true if the given Objective-C class is directly or indirectly
1394e5dd7070Spatrick // derived from a matching base class. A class is not considered to be derived
1395e5dd7070Spatrick // from itself.
objcClassIsDerivedFrom(const ObjCInterfaceDecl * Declaration,const Matcher<NamedDecl> & Base,BoundNodesTreeBuilder * Builder,bool Directly)1396e5dd7070Spatrick bool MatchASTVisitor::objcClassIsDerivedFrom(
1397e5dd7070Spatrick const ObjCInterfaceDecl *Declaration, const Matcher<NamedDecl> &Base,
1398e5dd7070Spatrick BoundNodesTreeBuilder *Builder, bool Directly) {
1399e5dd7070Spatrick // Check if any of the superclasses of the class match.
1400e5dd7070Spatrick for (const ObjCInterfaceDecl *ClassDecl = Declaration->getSuperClass();
1401e5dd7070Spatrick ClassDecl != nullptr; ClassDecl = ClassDecl->getSuperClass()) {
1402e5dd7070Spatrick // Check if there are any matching compatibility aliases.
1403e5dd7070Spatrick if (objcClassHasMatchingCompatibilityAlias(ClassDecl, Base, Builder))
1404e5dd7070Spatrick return true;
1405e5dd7070Spatrick
1406e5dd7070Spatrick // Check if there are any matching type aliases.
1407e5dd7070Spatrick const Type *TypeNode = ClassDecl->getTypeForDecl();
1408e5dd7070Spatrick if (typeHasMatchingAlias(TypeNode, Base, Builder))
1409e5dd7070Spatrick return true;
1410e5dd7070Spatrick
1411e5dd7070Spatrick if (Base.matches(*ClassDecl, this, Builder))
1412e5dd7070Spatrick return true;
1413e5dd7070Spatrick
1414e5dd7070Spatrick // Not `return false` as a temporary workaround for PR43879.
1415e5dd7070Spatrick if (Directly)
1416e5dd7070Spatrick break;
1417e5dd7070Spatrick }
1418e5dd7070Spatrick
1419e5dd7070Spatrick return false;
1420e5dd7070Spatrick }
1421e5dd7070Spatrick
TraverseDecl(Decl * DeclNode)1422e5dd7070Spatrick bool MatchASTVisitor::TraverseDecl(Decl *DeclNode) {
1423e5dd7070Spatrick if (!DeclNode) {
1424e5dd7070Spatrick return true;
1425e5dd7070Spatrick }
1426a9ac8606Spatrick
1427a9ac8606Spatrick bool ScopedTraversal =
1428a9ac8606Spatrick TraversingASTNodeNotSpelledInSource || DeclNode->isImplicit();
1429a9ac8606Spatrick bool ScopedChildren = TraversingASTChildrenNotSpelledInSource;
1430a9ac8606Spatrick
1431a9ac8606Spatrick if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(DeclNode)) {
1432a9ac8606Spatrick auto SK = CTSD->getSpecializationKind();
1433a9ac8606Spatrick if (SK == TSK_ExplicitInstantiationDeclaration ||
1434a9ac8606Spatrick SK == TSK_ExplicitInstantiationDefinition)
1435a9ac8606Spatrick ScopedChildren = true;
1436a9ac8606Spatrick } else if (const auto *FD = dyn_cast<FunctionDecl>(DeclNode)) {
1437a9ac8606Spatrick if (FD->isDefaulted())
1438a9ac8606Spatrick ScopedChildren = true;
1439a9ac8606Spatrick if (FD->isTemplateInstantiation())
1440a9ac8606Spatrick ScopedTraversal = true;
1441a9ac8606Spatrick } else if (isa<BindingDecl>(DeclNode)) {
1442a9ac8606Spatrick ScopedChildren = true;
1443a9ac8606Spatrick }
1444a9ac8606Spatrick
1445a9ac8606Spatrick ASTNodeNotSpelledInSourceScope RAII1(this, ScopedTraversal);
1446a9ac8606Spatrick ASTChildrenNotSpelledInSourceScope RAII2(this, ScopedChildren);
1447a9ac8606Spatrick
1448e5dd7070Spatrick match(*DeclNode);
1449e5dd7070Spatrick return RecursiveASTVisitor<MatchASTVisitor>::TraverseDecl(DeclNode);
1450e5dd7070Spatrick }
1451e5dd7070Spatrick
TraverseStmt(Stmt * StmtNode,DataRecursionQueue * Queue)1452e5dd7070Spatrick bool MatchASTVisitor::TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue) {
1453e5dd7070Spatrick if (!StmtNode) {
1454e5dd7070Spatrick return true;
1455e5dd7070Spatrick }
1456a9ac8606Spatrick bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
1457a9ac8606Spatrick TraversingASTChildrenNotSpelledInSource;
1458a9ac8606Spatrick
1459a9ac8606Spatrick ASTNodeNotSpelledInSourceScope RAII(this, ScopedTraversal);
1460e5dd7070Spatrick match(*StmtNode);
1461e5dd7070Spatrick return RecursiveASTVisitor<MatchASTVisitor>::TraverseStmt(StmtNode, Queue);
1462e5dd7070Spatrick }
1463e5dd7070Spatrick
TraverseType(QualType TypeNode)1464e5dd7070Spatrick bool MatchASTVisitor::TraverseType(QualType TypeNode) {
1465e5dd7070Spatrick match(TypeNode);
1466e5dd7070Spatrick return RecursiveASTVisitor<MatchASTVisitor>::TraverseType(TypeNode);
1467e5dd7070Spatrick }
1468e5dd7070Spatrick
TraverseTypeLoc(TypeLoc TypeLocNode)1469e5dd7070Spatrick bool MatchASTVisitor::TraverseTypeLoc(TypeLoc TypeLocNode) {
1470e5dd7070Spatrick // The RecursiveASTVisitor only visits types if they're not within TypeLocs.
1471e5dd7070Spatrick // We still want to find those types via matchers, so we match them here. Note
1472e5dd7070Spatrick // that the TypeLocs are structurally a shadow-hierarchy to the expressed
1473e5dd7070Spatrick // type, so we visit all involved parts of a compound type when matching on
1474e5dd7070Spatrick // each TypeLoc.
1475e5dd7070Spatrick match(TypeLocNode);
1476e5dd7070Spatrick match(TypeLocNode.getType());
1477e5dd7070Spatrick return RecursiveASTVisitor<MatchASTVisitor>::TraverseTypeLoc(TypeLocNode);
1478e5dd7070Spatrick }
1479e5dd7070Spatrick
TraverseNestedNameSpecifier(NestedNameSpecifier * NNS)1480e5dd7070Spatrick bool MatchASTVisitor::TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {
1481e5dd7070Spatrick match(*NNS);
1482e5dd7070Spatrick return RecursiveASTVisitor<MatchASTVisitor>::TraverseNestedNameSpecifier(NNS);
1483e5dd7070Spatrick }
1484e5dd7070Spatrick
TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS)1485e5dd7070Spatrick bool MatchASTVisitor::TraverseNestedNameSpecifierLoc(
1486e5dd7070Spatrick NestedNameSpecifierLoc NNS) {
1487e5dd7070Spatrick if (!NNS)
1488e5dd7070Spatrick return true;
1489e5dd7070Spatrick
1490e5dd7070Spatrick match(NNS);
1491e5dd7070Spatrick
1492e5dd7070Spatrick // We only match the nested name specifier here (as opposed to traversing it)
1493e5dd7070Spatrick // because the traversal is already done in the parallel "Loc"-hierarchy.
1494e5dd7070Spatrick if (NNS.hasQualifier())
1495e5dd7070Spatrick match(*NNS.getNestedNameSpecifier());
1496e5dd7070Spatrick return
1497e5dd7070Spatrick RecursiveASTVisitor<MatchASTVisitor>::TraverseNestedNameSpecifierLoc(NNS);
1498e5dd7070Spatrick }
1499e5dd7070Spatrick
TraverseConstructorInitializer(CXXCtorInitializer * CtorInit)1500e5dd7070Spatrick bool MatchASTVisitor::TraverseConstructorInitializer(
1501e5dd7070Spatrick CXXCtorInitializer *CtorInit) {
1502e5dd7070Spatrick if (!CtorInit)
1503e5dd7070Spatrick return true;
1504e5dd7070Spatrick
1505a9ac8606Spatrick bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
1506a9ac8606Spatrick TraversingASTChildrenNotSpelledInSource;
1507a9ac8606Spatrick
1508a9ac8606Spatrick if (!CtorInit->isWritten())
1509a9ac8606Spatrick ScopedTraversal = true;
1510a9ac8606Spatrick
1511a9ac8606Spatrick ASTNodeNotSpelledInSourceScope RAII1(this, ScopedTraversal);
1512a9ac8606Spatrick
1513e5dd7070Spatrick match(*CtorInit);
1514e5dd7070Spatrick
1515e5dd7070Spatrick return RecursiveASTVisitor<MatchASTVisitor>::TraverseConstructorInitializer(
1516e5dd7070Spatrick CtorInit);
1517e5dd7070Spatrick }
1518e5dd7070Spatrick
TraverseTemplateArgumentLoc(TemplateArgumentLoc Loc)1519a9ac8606Spatrick bool MatchASTVisitor::TraverseTemplateArgumentLoc(TemplateArgumentLoc Loc) {
1520a9ac8606Spatrick match(Loc);
1521a9ac8606Spatrick return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateArgumentLoc(Loc);
1522a9ac8606Spatrick }
1523a9ac8606Spatrick
TraverseAttr(Attr * AttrNode)1524*12c85518Srobert bool MatchASTVisitor::TraverseAttr(Attr *AttrNode) {
1525*12c85518Srobert match(*AttrNode);
1526*12c85518Srobert return RecursiveASTVisitor<MatchASTVisitor>::TraverseAttr(AttrNode);
1527*12c85518Srobert }
1528*12c85518Srobert
1529e5dd7070Spatrick class MatchASTConsumer : public ASTConsumer {
1530e5dd7070Spatrick public:
MatchASTConsumer(MatchFinder * Finder,MatchFinder::ParsingDoneTestCallback * ParsingDone)1531e5dd7070Spatrick MatchASTConsumer(MatchFinder *Finder,
1532e5dd7070Spatrick MatchFinder::ParsingDoneTestCallback *ParsingDone)
1533e5dd7070Spatrick : Finder(Finder), ParsingDone(ParsingDone) {}
1534e5dd7070Spatrick
1535e5dd7070Spatrick private:
HandleTranslationUnit(ASTContext & Context)1536e5dd7070Spatrick void HandleTranslationUnit(ASTContext &Context) override {
1537e5dd7070Spatrick if (ParsingDone != nullptr) {
1538e5dd7070Spatrick ParsingDone->run();
1539e5dd7070Spatrick }
1540e5dd7070Spatrick Finder->matchAST(Context);
1541e5dd7070Spatrick }
1542e5dd7070Spatrick
1543e5dd7070Spatrick MatchFinder *Finder;
1544e5dd7070Spatrick MatchFinder::ParsingDoneTestCallback *ParsingDone;
1545e5dd7070Spatrick };
1546e5dd7070Spatrick
1547e5dd7070Spatrick } // end namespace
1548e5dd7070Spatrick } // end namespace internal
1549e5dd7070Spatrick
MatchResult(const BoundNodes & Nodes,ASTContext * Context)1550e5dd7070Spatrick MatchFinder::MatchResult::MatchResult(const BoundNodes &Nodes,
1551e5dd7070Spatrick ASTContext *Context)
1552e5dd7070Spatrick : Nodes(Nodes), Context(Context),
1553e5dd7070Spatrick SourceManager(&Context->getSourceManager()) {}
1554e5dd7070Spatrick
~MatchCallback()1555e5dd7070Spatrick MatchFinder::MatchCallback::~MatchCallback() {}
~ParsingDoneTestCallback()1556e5dd7070Spatrick MatchFinder::ParsingDoneTestCallback::~ParsingDoneTestCallback() {}
1557e5dd7070Spatrick
MatchFinder(MatchFinderOptions Options)1558e5dd7070Spatrick MatchFinder::MatchFinder(MatchFinderOptions Options)
1559e5dd7070Spatrick : Options(std::move(Options)), ParsingDone(nullptr) {}
1560e5dd7070Spatrick
~MatchFinder()1561e5dd7070Spatrick MatchFinder::~MatchFinder() {}
1562e5dd7070Spatrick
addMatcher(const DeclarationMatcher & NodeMatch,MatchCallback * Action)1563e5dd7070Spatrick void MatchFinder::addMatcher(const DeclarationMatcher &NodeMatch,
1564e5dd7070Spatrick MatchCallback *Action) {
1565*12c85518Srobert std::optional<TraversalKind> TK;
1566a9ac8606Spatrick if (Action)
1567a9ac8606Spatrick TK = Action->getCheckTraversalKind();
1568a9ac8606Spatrick if (TK)
1569a9ac8606Spatrick Matchers.DeclOrStmt.emplace_back(traverse(*TK, NodeMatch), Action);
1570a9ac8606Spatrick else
1571e5dd7070Spatrick Matchers.DeclOrStmt.emplace_back(NodeMatch, Action);
1572e5dd7070Spatrick Matchers.AllCallbacks.insert(Action);
1573e5dd7070Spatrick }
1574e5dd7070Spatrick
addMatcher(const TypeMatcher & NodeMatch,MatchCallback * Action)1575e5dd7070Spatrick void MatchFinder::addMatcher(const TypeMatcher &NodeMatch,
1576e5dd7070Spatrick MatchCallback *Action) {
1577e5dd7070Spatrick Matchers.Type.emplace_back(NodeMatch, Action);
1578e5dd7070Spatrick Matchers.AllCallbacks.insert(Action);
1579e5dd7070Spatrick }
1580e5dd7070Spatrick
addMatcher(const StatementMatcher & NodeMatch,MatchCallback * Action)1581e5dd7070Spatrick void MatchFinder::addMatcher(const StatementMatcher &NodeMatch,
1582e5dd7070Spatrick MatchCallback *Action) {
1583*12c85518Srobert std::optional<TraversalKind> TK;
1584a9ac8606Spatrick if (Action)
1585a9ac8606Spatrick TK = Action->getCheckTraversalKind();
1586a9ac8606Spatrick if (TK)
1587a9ac8606Spatrick Matchers.DeclOrStmt.emplace_back(traverse(*TK, NodeMatch), Action);
1588a9ac8606Spatrick else
1589e5dd7070Spatrick Matchers.DeclOrStmt.emplace_back(NodeMatch, Action);
1590e5dd7070Spatrick Matchers.AllCallbacks.insert(Action);
1591e5dd7070Spatrick }
1592e5dd7070Spatrick
addMatcher(const NestedNameSpecifierMatcher & NodeMatch,MatchCallback * Action)1593e5dd7070Spatrick void MatchFinder::addMatcher(const NestedNameSpecifierMatcher &NodeMatch,
1594e5dd7070Spatrick MatchCallback *Action) {
1595e5dd7070Spatrick Matchers.NestedNameSpecifier.emplace_back(NodeMatch, Action);
1596e5dd7070Spatrick Matchers.AllCallbacks.insert(Action);
1597e5dd7070Spatrick }
1598e5dd7070Spatrick
addMatcher(const NestedNameSpecifierLocMatcher & NodeMatch,MatchCallback * Action)1599e5dd7070Spatrick void MatchFinder::addMatcher(const NestedNameSpecifierLocMatcher &NodeMatch,
1600e5dd7070Spatrick MatchCallback *Action) {
1601e5dd7070Spatrick Matchers.NestedNameSpecifierLoc.emplace_back(NodeMatch, Action);
1602e5dd7070Spatrick Matchers.AllCallbacks.insert(Action);
1603e5dd7070Spatrick }
1604e5dd7070Spatrick
addMatcher(const TypeLocMatcher & NodeMatch,MatchCallback * Action)1605e5dd7070Spatrick void MatchFinder::addMatcher(const TypeLocMatcher &NodeMatch,
1606e5dd7070Spatrick MatchCallback *Action) {
1607e5dd7070Spatrick Matchers.TypeLoc.emplace_back(NodeMatch, Action);
1608e5dd7070Spatrick Matchers.AllCallbacks.insert(Action);
1609e5dd7070Spatrick }
1610e5dd7070Spatrick
addMatcher(const CXXCtorInitializerMatcher & NodeMatch,MatchCallback * Action)1611e5dd7070Spatrick void MatchFinder::addMatcher(const CXXCtorInitializerMatcher &NodeMatch,
1612e5dd7070Spatrick MatchCallback *Action) {
1613e5dd7070Spatrick Matchers.CtorInit.emplace_back(NodeMatch, Action);
1614e5dd7070Spatrick Matchers.AllCallbacks.insert(Action);
1615e5dd7070Spatrick }
1616e5dd7070Spatrick
addMatcher(const TemplateArgumentLocMatcher & NodeMatch,MatchCallback * Action)1617a9ac8606Spatrick void MatchFinder::addMatcher(const TemplateArgumentLocMatcher &NodeMatch,
1618a9ac8606Spatrick MatchCallback *Action) {
1619a9ac8606Spatrick Matchers.TemplateArgumentLoc.emplace_back(NodeMatch, Action);
1620a9ac8606Spatrick Matchers.AllCallbacks.insert(Action);
1621a9ac8606Spatrick }
1622a9ac8606Spatrick
addMatcher(const AttrMatcher & AttrMatch,MatchCallback * Action)1623*12c85518Srobert void MatchFinder::addMatcher(const AttrMatcher &AttrMatch,
1624*12c85518Srobert MatchCallback *Action) {
1625*12c85518Srobert Matchers.Attr.emplace_back(AttrMatch, Action);
1626*12c85518Srobert Matchers.AllCallbacks.insert(Action);
1627*12c85518Srobert }
1628*12c85518Srobert
addDynamicMatcher(const internal::DynTypedMatcher & NodeMatch,MatchCallback * Action)1629e5dd7070Spatrick bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
1630e5dd7070Spatrick MatchCallback *Action) {
1631e5dd7070Spatrick if (NodeMatch.canConvertTo<Decl>()) {
1632e5dd7070Spatrick addMatcher(NodeMatch.convertTo<Decl>(), Action);
1633e5dd7070Spatrick return true;
1634e5dd7070Spatrick } else if (NodeMatch.canConvertTo<QualType>()) {
1635e5dd7070Spatrick addMatcher(NodeMatch.convertTo<QualType>(), Action);
1636e5dd7070Spatrick return true;
1637e5dd7070Spatrick } else if (NodeMatch.canConvertTo<Stmt>()) {
1638e5dd7070Spatrick addMatcher(NodeMatch.convertTo<Stmt>(), Action);
1639e5dd7070Spatrick return true;
1640e5dd7070Spatrick } else if (NodeMatch.canConvertTo<NestedNameSpecifier>()) {
1641e5dd7070Spatrick addMatcher(NodeMatch.convertTo<NestedNameSpecifier>(), Action);
1642e5dd7070Spatrick return true;
1643e5dd7070Spatrick } else if (NodeMatch.canConvertTo<NestedNameSpecifierLoc>()) {
1644e5dd7070Spatrick addMatcher(NodeMatch.convertTo<NestedNameSpecifierLoc>(), Action);
1645e5dd7070Spatrick return true;
1646e5dd7070Spatrick } else if (NodeMatch.canConvertTo<TypeLoc>()) {
1647e5dd7070Spatrick addMatcher(NodeMatch.convertTo<TypeLoc>(), Action);
1648e5dd7070Spatrick return true;
1649e5dd7070Spatrick } else if (NodeMatch.canConvertTo<CXXCtorInitializer>()) {
1650e5dd7070Spatrick addMatcher(NodeMatch.convertTo<CXXCtorInitializer>(), Action);
1651e5dd7070Spatrick return true;
1652a9ac8606Spatrick } else if (NodeMatch.canConvertTo<TemplateArgumentLoc>()) {
1653a9ac8606Spatrick addMatcher(NodeMatch.convertTo<TemplateArgumentLoc>(), Action);
1654a9ac8606Spatrick return true;
1655*12c85518Srobert } else if (NodeMatch.canConvertTo<Attr>()) {
1656*12c85518Srobert addMatcher(NodeMatch.convertTo<Attr>(), Action);
1657*12c85518Srobert return true;
1658e5dd7070Spatrick }
1659e5dd7070Spatrick return false;
1660e5dd7070Spatrick }
1661e5dd7070Spatrick
newASTConsumer()1662e5dd7070Spatrick std::unique_ptr<ASTConsumer> MatchFinder::newASTConsumer() {
1663e5dd7070Spatrick return std::make_unique<internal::MatchASTConsumer>(this, ParsingDone);
1664e5dd7070Spatrick }
1665e5dd7070Spatrick
match(const clang::DynTypedNode & Node,ASTContext & Context)1666ec727ea7Spatrick void MatchFinder::match(const clang::DynTypedNode &Node, ASTContext &Context) {
1667e5dd7070Spatrick internal::MatchASTVisitor Visitor(&Matchers, Options);
1668e5dd7070Spatrick Visitor.set_active_ast_context(&Context);
1669e5dd7070Spatrick Visitor.match(Node);
1670e5dd7070Spatrick }
1671e5dd7070Spatrick
matchAST(ASTContext & Context)1672e5dd7070Spatrick void MatchFinder::matchAST(ASTContext &Context) {
1673e5dd7070Spatrick internal::MatchASTVisitor Visitor(&Matchers, Options);
1674*12c85518Srobert internal::MatchASTVisitor::TraceReporter StackTrace(Visitor);
1675e5dd7070Spatrick Visitor.set_active_ast_context(&Context);
1676e5dd7070Spatrick Visitor.onStartOfTranslationUnit();
1677e5dd7070Spatrick Visitor.TraverseAST(Context);
1678e5dd7070Spatrick Visitor.onEndOfTranslationUnit();
1679e5dd7070Spatrick }
1680e5dd7070Spatrick
registerTestCallbackAfterParsing(MatchFinder::ParsingDoneTestCallback * NewParsingDone)1681e5dd7070Spatrick void MatchFinder::registerTestCallbackAfterParsing(
1682e5dd7070Spatrick MatchFinder::ParsingDoneTestCallback *NewParsingDone) {
1683e5dd7070Spatrick ParsingDone = NewParsingDone;
1684e5dd7070Spatrick }
1685e5dd7070Spatrick
getID() const1686e5dd7070Spatrick StringRef MatchFinder::MatchCallback::getID() const { return "<unknown>"; }
1687e5dd7070Spatrick
1688*12c85518Srobert std::optional<TraversalKind>
getCheckTraversalKind() const1689a9ac8606Spatrick MatchFinder::MatchCallback::getCheckTraversalKind() const {
1690*12c85518Srobert return std::nullopt;
1691a9ac8606Spatrick }
1692a9ac8606Spatrick
1693e5dd7070Spatrick } // end namespace ast_matchers
1694e5dd7070Spatrick } // end namespace clang
1695