17330f729Sjoerg //===--- ASTMatchFinder.cpp - Structural query framework ------------------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // Implements an algorithm to efficiently search for matches on AST nodes.
107330f729Sjoerg // Uses memoization to support recursive matches like HasDescendant.
117330f729Sjoerg //
127330f729Sjoerg // The general idea is to visit all AST nodes with a RecursiveASTVisitor,
137330f729Sjoerg // calling the Matches(...) method of each matcher we are running on each
147330f729Sjoerg // AST node. The matcher can recurse via the ASTMatchFinder interface.
157330f729Sjoerg //
167330f729Sjoerg //===----------------------------------------------------------------------===//
177330f729Sjoerg
187330f729Sjoerg #include "clang/ASTMatchers/ASTMatchFinder.h"
197330f729Sjoerg #include "clang/AST/ASTConsumer.h"
207330f729Sjoerg #include "clang/AST/ASTContext.h"
217330f729Sjoerg #include "clang/AST/RecursiveASTVisitor.h"
227330f729Sjoerg #include "llvm/ADT/DenseMap.h"
237330f729Sjoerg #include "llvm/ADT/StringMap.h"
247330f729Sjoerg #include "llvm/Support/Timer.h"
257330f729Sjoerg #include <deque>
267330f729Sjoerg #include <memory>
277330f729Sjoerg #include <set>
287330f729Sjoerg
297330f729Sjoerg namespace clang {
307330f729Sjoerg namespace ast_matchers {
317330f729Sjoerg namespace internal {
327330f729Sjoerg namespace {
337330f729Sjoerg
347330f729Sjoerg typedef MatchFinder::MatchCallback MatchCallback;
357330f729Sjoerg
367330f729Sjoerg // The maximum number of memoization entries to store.
377330f729Sjoerg // 10k has been experimentally found to give a good trade-off
387330f729Sjoerg // of performance vs. memory consumption by running matcher
397330f729Sjoerg // that match on every statement over a very large codebase.
407330f729Sjoerg //
417330f729Sjoerg // FIXME: Do some performance optimization in general and
427330f729Sjoerg // revisit this number; also, put up micro-benchmarks that we can
437330f729Sjoerg // optimize this on.
447330f729Sjoerg static const unsigned MaxMemoizationEntries = 10000;
457330f729Sjoerg
46*e038c9c4Sjoerg enum class MatchType {
47*e038c9c4Sjoerg Ancestors,
48*e038c9c4Sjoerg
49*e038c9c4Sjoerg Descendants,
50*e038c9c4Sjoerg Child,
51*e038c9c4Sjoerg };
52*e038c9c4Sjoerg
537330f729Sjoerg // We use memoization to avoid running the same matcher on the same
547330f729Sjoerg // AST node twice. This struct is the key for looking up match
557330f729Sjoerg // result. It consists of an ID of the MatcherInterface (for
567330f729Sjoerg // identifying the matcher), a pointer to the AST node and the
577330f729Sjoerg // bound nodes before the matcher was executed.
587330f729Sjoerg //
597330f729Sjoerg // We currently only memoize on nodes whose pointers identify the
607330f729Sjoerg // nodes (\c Stmt and \c Decl, but not \c QualType or \c TypeLoc).
617330f729Sjoerg // For \c QualType and \c TypeLoc it is possible to implement
627330f729Sjoerg // generation of keys for each type.
637330f729Sjoerg // FIXME: Benchmark whether memoization of non-pointer typed nodes
647330f729Sjoerg // provides enough benefit for the additional amount of code.
657330f729Sjoerg struct MatchKey {
667330f729Sjoerg DynTypedMatcher::MatcherIDType MatcherID;
67*e038c9c4Sjoerg DynTypedNode Node;
687330f729Sjoerg BoundNodesTreeBuilder BoundNodes;
69*e038c9c4Sjoerg TraversalKind Traversal = TK_AsIs;
70*e038c9c4Sjoerg MatchType Type;
717330f729Sjoerg
operator <clang::ast_matchers::internal::__anon62d4f9200111::MatchKey727330f729Sjoerg bool operator<(const MatchKey &Other) const {
73*e038c9c4Sjoerg return std::tie(Traversal, Type, MatcherID, Node, BoundNodes) <
74*e038c9c4Sjoerg std::tie(Other.Traversal, Other.Type, Other.MatcherID, Other.Node,
75*e038c9c4Sjoerg Other.BoundNodes);
767330f729Sjoerg }
777330f729Sjoerg };
787330f729Sjoerg
797330f729Sjoerg // Used to store the result of a match and possibly bound nodes.
807330f729Sjoerg struct MemoizedMatchResult {
817330f729Sjoerg bool ResultOfMatch;
827330f729Sjoerg BoundNodesTreeBuilder Nodes;
837330f729Sjoerg };
847330f729Sjoerg
857330f729Sjoerg // A RecursiveASTVisitor that traverses all children or all descendants of
867330f729Sjoerg // a node.
877330f729Sjoerg class MatchChildASTVisitor
887330f729Sjoerg : public RecursiveASTVisitor<MatchChildASTVisitor> {
897330f729Sjoerg public:
907330f729Sjoerg typedef RecursiveASTVisitor<MatchChildASTVisitor> VisitorBase;
917330f729Sjoerg
927330f729Sjoerg // Creates an AST visitor that matches 'matcher' on all children or
937330f729Sjoerg // descendants of a traversed node. max_depth is the maximum depth
947330f729Sjoerg // to traverse: use 1 for matching the children and INT_MAX for
957330f729Sjoerg // matching the descendants.
MatchChildASTVisitor(const DynTypedMatcher * Matcher,ASTMatchFinder * Finder,BoundNodesTreeBuilder * Builder,int MaxDepth,bool IgnoreImplicitChildren,ASTMatchFinder::BindKind Bind)967330f729Sjoerg MatchChildASTVisitor(const DynTypedMatcher *Matcher, ASTMatchFinder *Finder,
977330f729Sjoerg BoundNodesTreeBuilder *Builder, int MaxDepth,
98*e038c9c4Sjoerg bool IgnoreImplicitChildren,
997330f729Sjoerg ASTMatchFinder::BindKind Bind)
1007330f729Sjoerg : Matcher(Matcher), Finder(Finder), Builder(Builder), CurrentDepth(0),
101*e038c9c4Sjoerg MaxDepth(MaxDepth), IgnoreImplicitChildren(IgnoreImplicitChildren),
102*e038c9c4Sjoerg Bind(Bind), Matches(false) {}
1037330f729Sjoerg
1047330f729Sjoerg // Returns true if a match is found in the subtree rooted at the
1057330f729Sjoerg // given AST node. This is done via a set of mutually recursive
1067330f729Sjoerg // functions. Here's how the recursion is done (the *wildcard can
1077330f729Sjoerg // actually be Decl, Stmt, or Type):
1087330f729Sjoerg //
1097330f729Sjoerg // - Traverse(node) calls BaseTraverse(node) when it needs
1107330f729Sjoerg // to visit the descendants of node.
1117330f729Sjoerg // - BaseTraverse(node) then calls (via VisitorBase::Traverse*(node))
1127330f729Sjoerg // Traverse*(c) for each child c of 'node'.
1137330f729Sjoerg // - Traverse*(c) in turn calls Traverse(c), completing the
1147330f729Sjoerg // recursion.
findMatch(const DynTypedNode & DynNode)115*e038c9c4Sjoerg bool findMatch(const DynTypedNode &DynNode) {
1167330f729Sjoerg reset();
1177330f729Sjoerg if (const Decl *D = DynNode.get<Decl>())
1187330f729Sjoerg traverse(*D);
1197330f729Sjoerg else if (const Stmt *S = DynNode.get<Stmt>())
1207330f729Sjoerg traverse(*S);
1217330f729Sjoerg else if (const NestedNameSpecifier *NNS =
1227330f729Sjoerg DynNode.get<NestedNameSpecifier>())
1237330f729Sjoerg traverse(*NNS);
1247330f729Sjoerg else if (const NestedNameSpecifierLoc *NNSLoc =
1257330f729Sjoerg DynNode.get<NestedNameSpecifierLoc>())
1267330f729Sjoerg traverse(*NNSLoc);
1277330f729Sjoerg else if (const QualType *Q = DynNode.get<QualType>())
1287330f729Sjoerg traverse(*Q);
1297330f729Sjoerg else if (const TypeLoc *T = DynNode.get<TypeLoc>())
1307330f729Sjoerg traverse(*T);
1317330f729Sjoerg else if (const auto *C = DynNode.get<CXXCtorInitializer>())
1327330f729Sjoerg traverse(*C);
133*e038c9c4Sjoerg else if (const TemplateArgumentLoc *TALoc =
134*e038c9c4Sjoerg DynNode.get<TemplateArgumentLoc>())
135*e038c9c4Sjoerg traverse(*TALoc);
1367330f729Sjoerg // FIXME: Add other base types after adding tests.
1377330f729Sjoerg
1387330f729Sjoerg // It's OK to always overwrite the bound nodes, as if there was
1397330f729Sjoerg // no match in this recursive branch, the result set is empty
1407330f729Sjoerg // anyway.
1417330f729Sjoerg *Builder = ResultBindings;
1427330f729Sjoerg
1437330f729Sjoerg return Matches;
1447330f729Sjoerg }
1457330f729Sjoerg
1467330f729Sjoerg // The following are overriding methods from the base visitor class.
1477330f729Sjoerg // They are public only to allow CRTP to work. They are *not *part
1487330f729Sjoerg // of the public API of this class.
TraverseDecl(Decl * DeclNode)1497330f729Sjoerg bool TraverseDecl(Decl *DeclNode) {
150*e038c9c4Sjoerg
151*e038c9c4Sjoerg if (DeclNode && DeclNode->isImplicit() &&
152*e038c9c4Sjoerg Finder->isTraversalIgnoringImplicitNodes())
153*e038c9c4Sjoerg return baseTraverse(*DeclNode);
154*e038c9c4Sjoerg
1557330f729Sjoerg ScopedIncrement ScopedDepth(&CurrentDepth);
1567330f729Sjoerg return (DeclNode == nullptr) || traverse(*DeclNode);
1577330f729Sjoerg }
158*e038c9c4Sjoerg
getStmtToTraverse(Stmt * StmtNode)159*e038c9c4Sjoerg Stmt *getStmtToTraverse(Stmt *StmtNode) {
160*e038c9c4Sjoerg Stmt *StmtToTraverse = StmtNode;
161*e038c9c4Sjoerg if (auto *ExprNode = dyn_cast_or_null<Expr>(StmtNode)) {
162*e038c9c4Sjoerg auto *LambdaNode = dyn_cast_or_null<LambdaExpr>(StmtNode);
163*e038c9c4Sjoerg if (LambdaNode && Finder->isTraversalIgnoringImplicitNodes())
164*e038c9c4Sjoerg StmtToTraverse = LambdaNode;
165*e038c9c4Sjoerg else
166*e038c9c4Sjoerg StmtToTraverse =
167*e038c9c4Sjoerg Finder->getASTContext().getParentMapContext().traverseIgnored(
168*e038c9c4Sjoerg ExprNode);
169*e038c9c4Sjoerg }
170*e038c9c4Sjoerg return StmtToTraverse;
171*e038c9c4Sjoerg }
172*e038c9c4Sjoerg
TraverseStmt(Stmt * StmtNode,DataRecursionQueue * Queue=nullptr)1737330f729Sjoerg bool TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue = nullptr) {
1747330f729Sjoerg // If we need to keep track of the depth, we can't perform data recursion.
1757330f729Sjoerg if (CurrentDepth == 0 || (CurrentDepth <= MaxDepth && MaxDepth < INT_MAX))
1767330f729Sjoerg Queue = nullptr;
1777330f729Sjoerg
1787330f729Sjoerg ScopedIncrement ScopedDepth(&CurrentDepth);
179*e038c9c4Sjoerg Stmt *StmtToTraverse = getStmtToTraverse(StmtNode);
1807330f729Sjoerg if (!StmtToTraverse)
1817330f729Sjoerg return true;
182*e038c9c4Sjoerg
183*e038c9c4Sjoerg if (IgnoreImplicitChildren && isa<CXXDefaultArgExpr>(StmtNode))
184*e038c9c4Sjoerg return true;
185*e038c9c4Sjoerg
1867330f729Sjoerg if (!match(*StmtToTraverse))
1877330f729Sjoerg return false;
1887330f729Sjoerg return VisitorBase::TraverseStmt(StmtToTraverse, Queue);
1897330f729Sjoerg }
1907330f729Sjoerg // We assume that the QualType and the contained type are on the same
1917330f729Sjoerg // hierarchy level. Thus, we try to match either of them.
TraverseType(QualType TypeNode)1927330f729Sjoerg bool TraverseType(QualType TypeNode) {
1937330f729Sjoerg if (TypeNode.isNull())
1947330f729Sjoerg return true;
1957330f729Sjoerg ScopedIncrement ScopedDepth(&CurrentDepth);
1967330f729Sjoerg // Match the Type.
1977330f729Sjoerg if (!match(*TypeNode))
1987330f729Sjoerg return false;
1997330f729Sjoerg // The QualType is matched inside traverse.
2007330f729Sjoerg return traverse(TypeNode);
2017330f729Sjoerg }
2027330f729Sjoerg // We assume that the TypeLoc, contained QualType and contained Type all are
2037330f729Sjoerg // on the same hierarchy level. Thus, we try to match all of them.
TraverseTypeLoc(TypeLoc TypeLocNode)2047330f729Sjoerg bool TraverseTypeLoc(TypeLoc TypeLocNode) {
2057330f729Sjoerg if (TypeLocNode.isNull())
2067330f729Sjoerg return true;
2077330f729Sjoerg ScopedIncrement ScopedDepth(&CurrentDepth);
2087330f729Sjoerg // Match the Type.
2097330f729Sjoerg if (!match(*TypeLocNode.getType()))
2107330f729Sjoerg return false;
2117330f729Sjoerg // Match the QualType.
2127330f729Sjoerg if (!match(TypeLocNode.getType()))
2137330f729Sjoerg return false;
2147330f729Sjoerg // The TypeLoc is matched inside traverse.
2157330f729Sjoerg return traverse(TypeLocNode);
2167330f729Sjoerg }
TraverseNestedNameSpecifier(NestedNameSpecifier * NNS)2177330f729Sjoerg bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {
2187330f729Sjoerg ScopedIncrement ScopedDepth(&CurrentDepth);
2197330f729Sjoerg return (NNS == nullptr) || traverse(*NNS);
2207330f729Sjoerg }
TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS)2217330f729Sjoerg bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
2227330f729Sjoerg if (!NNS)
2237330f729Sjoerg return true;
2247330f729Sjoerg ScopedIncrement ScopedDepth(&CurrentDepth);
2257330f729Sjoerg if (!match(*NNS.getNestedNameSpecifier()))
2267330f729Sjoerg return false;
2277330f729Sjoerg return traverse(NNS);
2287330f729Sjoerg }
TraverseConstructorInitializer(CXXCtorInitializer * CtorInit)2297330f729Sjoerg bool TraverseConstructorInitializer(CXXCtorInitializer *CtorInit) {
2307330f729Sjoerg if (!CtorInit)
2317330f729Sjoerg return true;
2327330f729Sjoerg ScopedIncrement ScopedDepth(&CurrentDepth);
2337330f729Sjoerg return traverse(*CtorInit);
2347330f729Sjoerg }
TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL)235*e038c9c4Sjoerg bool TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL) {
236*e038c9c4Sjoerg ScopedIncrement ScopedDepth(&CurrentDepth);
237*e038c9c4Sjoerg return traverse(TAL);
238*e038c9c4Sjoerg }
TraverseCXXForRangeStmt(CXXForRangeStmt * Node)239*e038c9c4Sjoerg bool TraverseCXXForRangeStmt(CXXForRangeStmt *Node) {
240*e038c9c4Sjoerg if (!Finder->isTraversalIgnoringImplicitNodes())
241*e038c9c4Sjoerg return VisitorBase::TraverseCXXForRangeStmt(Node);
242*e038c9c4Sjoerg if (!Node)
243*e038c9c4Sjoerg return true;
244*e038c9c4Sjoerg ScopedIncrement ScopedDepth(&CurrentDepth);
245*e038c9c4Sjoerg if (auto *Init = Node->getInit())
246*e038c9c4Sjoerg if (!traverse(*Init))
247*e038c9c4Sjoerg return false;
248*e038c9c4Sjoerg if (!match(*Node->getLoopVariable()))
249*e038c9c4Sjoerg return false;
250*e038c9c4Sjoerg if (match(*Node->getRangeInit()))
251*e038c9c4Sjoerg if (!VisitorBase::TraverseStmt(Node->getRangeInit()))
252*e038c9c4Sjoerg return false;
253*e038c9c4Sjoerg if (!match(*Node->getBody()))
254*e038c9c4Sjoerg return false;
255*e038c9c4Sjoerg return VisitorBase::TraverseStmt(Node->getBody());
256*e038c9c4Sjoerg }
TraverseCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator * Node)257*e038c9c4Sjoerg bool TraverseCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *Node) {
258*e038c9c4Sjoerg if (!Finder->isTraversalIgnoringImplicitNodes())
259*e038c9c4Sjoerg return VisitorBase::TraverseCXXRewrittenBinaryOperator(Node);
260*e038c9c4Sjoerg if (!Node)
261*e038c9c4Sjoerg return true;
262*e038c9c4Sjoerg ScopedIncrement ScopedDepth(&CurrentDepth);
263*e038c9c4Sjoerg
264*e038c9c4Sjoerg return match(*Node->getLHS()) && match(*Node->getRHS());
265*e038c9c4Sjoerg }
TraverseLambdaExpr(LambdaExpr * Node)266*e038c9c4Sjoerg bool TraverseLambdaExpr(LambdaExpr *Node) {
267*e038c9c4Sjoerg if (!Finder->isTraversalIgnoringImplicitNodes())
268*e038c9c4Sjoerg return VisitorBase::TraverseLambdaExpr(Node);
269*e038c9c4Sjoerg if (!Node)
270*e038c9c4Sjoerg return true;
271*e038c9c4Sjoerg ScopedIncrement ScopedDepth(&CurrentDepth);
272*e038c9c4Sjoerg
273*e038c9c4Sjoerg for (unsigned I = 0, N = Node->capture_size(); I != N; ++I) {
274*e038c9c4Sjoerg const auto *C = Node->capture_begin() + I;
275*e038c9c4Sjoerg if (!C->isExplicit())
276*e038c9c4Sjoerg continue;
277*e038c9c4Sjoerg if (Node->isInitCapture(C) && !match(*C->getCapturedVar()))
278*e038c9c4Sjoerg return false;
279*e038c9c4Sjoerg if (!match(*Node->capture_init_begin()[I]))
280*e038c9c4Sjoerg return false;
281*e038c9c4Sjoerg }
282*e038c9c4Sjoerg
283*e038c9c4Sjoerg if (const auto *TPL = Node->getTemplateParameterList()) {
284*e038c9c4Sjoerg for (const auto *TP : *TPL) {
285*e038c9c4Sjoerg if (!match(*TP))
286*e038c9c4Sjoerg return false;
287*e038c9c4Sjoerg }
288*e038c9c4Sjoerg }
289*e038c9c4Sjoerg
290*e038c9c4Sjoerg for (const auto *P : Node->getCallOperator()->parameters()) {
291*e038c9c4Sjoerg if (!match(*P))
292*e038c9c4Sjoerg return false;
293*e038c9c4Sjoerg }
294*e038c9c4Sjoerg
295*e038c9c4Sjoerg if (!match(*Node->getBody()))
296*e038c9c4Sjoerg return false;
297*e038c9c4Sjoerg
298*e038c9c4Sjoerg return VisitorBase::TraverseStmt(Node->getBody());
299*e038c9c4Sjoerg }
3007330f729Sjoerg
shouldVisitTemplateInstantiations() const3017330f729Sjoerg bool shouldVisitTemplateInstantiations() const { return true; }
shouldVisitImplicitCode() const302*e038c9c4Sjoerg bool shouldVisitImplicitCode() const { return !IgnoreImplicitChildren; }
3037330f729Sjoerg
3047330f729Sjoerg private:
3057330f729Sjoerg // Used for updating the depth during traversal.
3067330f729Sjoerg struct ScopedIncrement {
ScopedIncrementclang::ast_matchers::internal::__anon62d4f9200111::MatchChildASTVisitor::ScopedIncrement3077330f729Sjoerg explicit ScopedIncrement(int *Depth) : Depth(Depth) { ++(*Depth); }
~ScopedIncrementclang::ast_matchers::internal::__anon62d4f9200111::MatchChildASTVisitor::ScopedIncrement3087330f729Sjoerg ~ScopedIncrement() { --(*Depth); }
3097330f729Sjoerg
3107330f729Sjoerg private:
3117330f729Sjoerg int *Depth;
3127330f729Sjoerg };
3137330f729Sjoerg
3147330f729Sjoerg // Resets the state of this object.
reset()3157330f729Sjoerg void reset() {
3167330f729Sjoerg Matches = false;
3177330f729Sjoerg CurrentDepth = 0;
3187330f729Sjoerg }
3197330f729Sjoerg
3207330f729Sjoerg // Forwards the call to the corresponding Traverse*() method in the
3217330f729Sjoerg // base visitor class.
baseTraverse(const Decl & DeclNode)3227330f729Sjoerg bool baseTraverse(const Decl &DeclNode) {
3237330f729Sjoerg return VisitorBase::TraverseDecl(const_cast<Decl*>(&DeclNode));
3247330f729Sjoerg }
baseTraverse(const Stmt & StmtNode)3257330f729Sjoerg bool baseTraverse(const Stmt &StmtNode) {
3267330f729Sjoerg return VisitorBase::TraverseStmt(const_cast<Stmt*>(&StmtNode));
3277330f729Sjoerg }
baseTraverse(QualType TypeNode)3287330f729Sjoerg bool baseTraverse(QualType TypeNode) {
3297330f729Sjoerg return VisitorBase::TraverseType(TypeNode);
3307330f729Sjoerg }
baseTraverse(TypeLoc TypeLocNode)3317330f729Sjoerg bool baseTraverse(TypeLoc TypeLocNode) {
3327330f729Sjoerg return VisitorBase::TraverseTypeLoc(TypeLocNode);
3337330f729Sjoerg }
baseTraverse(const NestedNameSpecifier & NNS)3347330f729Sjoerg bool baseTraverse(const NestedNameSpecifier &NNS) {
3357330f729Sjoerg return VisitorBase::TraverseNestedNameSpecifier(
3367330f729Sjoerg const_cast<NestedNameSpecifier*>(&NNS));
3377330f729Sjoerg }
baseTraverse(NestedNameSpecifierLoc NNS)3387330f729Sjoerg bool baseTraverse(NestedNameSpecifierLoc NNS) {
3397330f729Sjoerg return VisitorBase::TraverseNestedNameSpecifierLoc(NNS);
3407330f729Sjoerg }
baseTraverse(const CXXCtorInitializer & CtorInit)3417330f729Sjoerg bool baseTraverse(const CXXCtorInitializer &CtorInit) {
3427330f729Sjoerg return VisitorBase::TraverseConstructorInitializer(
3437330f729Sjoerg const_cast<CXXCtorInitializer *>(&CtorInit));
3447330f729Sjoerg }
baseTraverse(TemplateArgumentLoc TAL)345*e038c9c4Sjoerg bool baseTraverse(TemplateArgumentLoc TAL) {
346*e038c9c4Sjoerg return VisitorBase::TraverseTemplateArgumentLoc(TAL);
347*e038c9c4Sjoerg }
3487330f729Sjoerg
3497330f729Sjoerg // Sets 'Matched' to true if 'Matcher' matches 'Node' and:
3507330f729Sjoerg // 0 < CurrentDepth <= MaxDepth.
3517330f729Sjoerg //
3527330f729Sjoerg // Returns 'true' if traversal should continue after this function
3537330f729Sjoerg // returns, i.e. if no match is found or 'Bind' is 'BK_All'.
3547330f729Sjoerg template <typename T>
match(const T & Node)3557330f729Sjoerg bool match(const T &Node) {
3567330f729Sjoerg if (CurrentDepth == 0 || CurrentDepth > MaxDepth) {
3577330f729Sjoerg return true;
3587330f729Sjoerg }
3597330f729Sjoerg if (Bind != ASTMatchFinder::BK_All) {
3607330f729Sjoerg BoundNodesTreeBuilder RecursiveBuilder(*Builder);
361*e038c9c4Sjoerg if (Matcher->matches(DynTypedNode::create(Node), Finder,
3627330f729Sjoerg &RecursiveBuilder)) {
3637330f729Sjoerg Matches = true;
3647330f729Sjoerg ResultBindings.addMatch(RecursiveBuilder);
3657330f729Sjoerg return false; // Abort as soon as a match is found.
3667330f729Sjoerg }
3677330f729Sjoerg } else {
3687330f729Sjoerg BoundNodesTreeBuilder RecursiveBuilder(*Builder);
369*e038c9c4Sjoerg if (Matcher->matches(DynTypedNode::create(Node), Finder,
3707330f729Sjoerg &RecursiveBuilder)) {
3717330f729Sjoerg // After the first match the matcher succeeds.
3727330f729Sjoerg Matches = true;
3737330f729Sjoerg ResultBindings.addMatch(RecursiveBuilder);
3747330f729Sjoerg }
3757330f729Sjoerg }
3767330f729Sjoerg return true;
3777330f729Sjoerg }
3787330f729Sjoerg
3797330f729Sjoerg // Traverses the subtree rooted at 'Node'; returns true if the
3807330f729Sjoerg // traversal should continue after this function returns.
3817330f729Sjoerg template <typename T>
traverse(const T & Node)3827330f729Sjoerg bool traverse(const T &Node) {
3837330f729Sjoerg static_assert(IsBaseType<T>::value,
3847330f729Sjoerg "traverse can only be instantiated with base type");
3857330f729Sjoerg if (!match(Node))
3867330f729Sjoerg return false;
3877330f729Sjoerg return baseTraverse(Node);
3887330f729Sjoerg }
3897330f729Sjoerg
3907330f729Sjoerg const DynTypedMatcher *const Matcher;
3917330f729Sjoerg ASTMatchFinder *const Finder;
3927330f729Sjoerg BoundNodesTreeBuilder *const Builder;
3937330f729Sjoerg BoundNodesTreeBuilder ResultBindings;
3947330f729Sjoerg int CurrentDepth;
3957330f729Sjoerg const int MaxDepth;
396*e038c9c4Sjoerg const bool IgnoreImplicitChildren;
3977330f729Sjoerg const ASTMatchFinder::BindKind Bind;
3987330f729Sjoerg bool Matches;
3997330f729Sjoerg };
4007330f729Sjoerg
4017330f729Sjoerg // Controls the outermost traversal of the AST and allows to match multiple
4027330f729Sjoerg // matchers.
4037330f729Sjoerg class MatchASTVisitor : public RecursiveASTVisitor<MatchASTVisitor>,
4047330f729Sjoerg public ASTMatchFinder {
4057330f729Sjoerg public:
MatchASTVisitor(const MatchFinder::MatchersByType * Matchers,const MatchFinder::MatchFinderOptions & Options)4067330f729Sjoerg MatchASTVisitor(const MatchFinder::MatchersByType *Matchers,
4077330f729Sjoerg const MatchFinder::MatchFinderOptions &Options)
4087330f729Sjoerg : Matchers(Matchers), Options(Options), ActiveASTContext(nullptr) {}
4097330f729Sjoerg
~MatchASTVisitor()4107330f729Sjoerg ~MatchASTVisitor() override {
4117330f729Sjoerg if (Options.CheckProfiling) {
4127330f729Sjoerg Options.CheckProfiling->Records = std::move(TimeByBucket);
4137330f729Sjoerg }
4147330f729Sjoerg }
4157330f729Sjoerg
onStartOfTranslationUnit()4167330f729Sjoerg void onStartOfTranslationUnit() {
4177330f729Sjoerg const bool EnableCheckProfiling = Options.CheckProfiling.hasValue();
4187330f729Sjoerg TimeBucketRegion Timer;
4197330f729Sjoerg for (MatchCallback *MC : Matchers->AllCallbacks) {
4207330f729Sjoerg if (EnableCheckProfiling)
4217330f729Sjoerg Timer.setBucket(&TimeByBucket[MC->getID()]);
4227330f729Sjoerg MC->onStartOfTranslationUnit();
4237330f729Sjoerg }
4247330f729Sjoerg }
4257330f729Sjoerg
onEndOfTranslationUnit()4267330f729Sjoerg void onEndOfTranslationUnit() {
4277330f729Sjoerg const bool EnableCheckProfiling = Options.CheckProfiling.hasValue();
4287330f729Sjoerg TimeBucketRegion Timer;
4297330f729Sjoerg for (MatchCallback *MC : Matchers->AllCallbacks) {
4307330f729Sjoerg if (EnableCheckProfiling)
4317330f729Sjoerg Timer.setBucket(&TimeByBucket[MC->getID()]);
4327330f729Sjoerg MC->onEndOfTranslationUnit();
4337330f729Sjoerg }
4347330f729Sjoerg }
4357330f729Sjoerg
set_active_ast_context(ASTContext * NewActiveASTContext)4367330f729Sjoerg void set_active_ast_context(ASTContext *NewActiveASTContext) {
4377330f729Sjoerg ActiveASTContext = NewActiveASTContext;
4387330f729Sjoerg }
4397330f729Sjoerg
4407330f729Sjoerg // The following Visit*() and Traverse*() functions "override"
4417330f729Sjoerg // methods in RecursiveASTVisitor.
4427330f729Sjoerg
VisitTypedefNameDecl(TypedefNameDecl * DeclNode)4437330f729Sjoerg bool VisitTypedefNameDecl(TypedefNameDecl *DeclNode) {
4447330f729Sjoerg // When we see 'typedef A B', we add name 'B' to the set of names
4457330f729Sjoerg // A's canonical type maps to. This is necessary for implementing
4467330f729Sjoerg // isDerivedFrom(x) properly, where x can be the name of the base
4477330f729Sjoerg // class or any of its aliases.
4487330f729Sjoerg //
4497330f729Sjoerg // In general, the is-alias-of (as defined by typedefs) relation
4507330f729Sjoerg // is tree-shaped, as you can typedef a type more than once. For
4517330f729Sjoerg // example,
4527330f729Sjoerg //
4537330f729Sjoerg // typedef A B;
4547330f729Sjoerg // typedef A C;
4557330f729Sjoerg // typedef C D;
4567330f729Sjoerg // typedef C E;
4577330f729Sjoerg //
4587330f729Sjoerg // gives you
4597330f729Sjoerg //
4607330f729Sjoerg // A
4617330f729Sjoerg // |- B
4627330f729Sjoerg // `- C
4637330f729Sjoerg // |- D
4647330f729Sjoerg // `- E
4657330f729Sjoerg //
4667330f729Sjoerg // It is wrong to assume that the relation is a chain. A correct
4677330f729Sjoerg // implementation of isDerivedFrom() needs to recognize that B and
4687330f729Sjoerg // E are aliases, even though neither is a typedef of the other.
4697330f729Sjoerg // Therefore, we cannot simply walk through one typedef chain to
4707330f729Sjoerg // find out whether the type name matches.
4717330f729Sjoerg const Type *TypeNode = DeclNode->getUnderlyingType().getTypePtr();
4727330f729Sjoerg const Type *CanonicalType = // root of the typedef tree
4737330f729Sjoerg ActiveASTContext->getCanonicalType(TypeNode);
4747330f729Sjoerg TypeAliases[CanonicalType].insert(DeclNode);
4757330f729Sjoerg return true;
4767330f729Sjoerg }
4777330f729Sjoerg
VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl * CAD)4787330f729Sjoerg bool VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) {
4797330f729Sjoerg const ObjCInterfaceDecl *InterfaceDecl = CAD->getClassInterface();
4807330f729Sjoerg CompatibleAliases[InterfaceDecl].insert(CAD);
4817330f729Sjoerg return true;
4827330f729Sjoerg }
4837330f729Sjoerg
4847330f729Sjoerg bool TraverseDecl(Decl *DeclNode);
4857330f729Sjoerg bool TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue = nullptr);
4867330f729Sjoerg bool TraverseType(QualType TypeNode);
4877330f729Sjoerg bool TraverseTypeLoc(TypeLoc TypeNode);
4887330f729Sjoerg bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS);
4897330f729Sjoerg bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);
4907330f729Sjoerg bool TraverseConstructorInitializer(CXXCtorInitializer *CtorInit);
491*e038c9c4Sjoerg bool TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL);
492*e038c9c4Sjoerg
dataTraverseNode(Stmt * S,DataRecursionQueue * Queue)493*e038c9c4Sjoerg bool dataTraverseNode(Stmt *S, DataRecursionQueue *Queue) {
494*e038c9c4Sjoerg if (auto *RF = dyn_cast<CXXForRangeStmt>(S)) {
495*e038c9c4Sjoerg {
496*e038c9c4Sjoerg ASTNodeNotAsIsSourceScope RAII(this, true);
497*e038c9c4Sjoerg TraverseStmt(RF->getInit());
498*e038c9c4Sjoerg // Don't traverse under the loop variable
499*e038c9c4Sjoerg match(*RF->getLoopVariable());
500*e038c9c4Sjoerg TraverseStmt(RF->getRangeInit());
501*e038c9c4Sjoerg }
502*e038c9c4Sjoerg {
503*e038c9c4Sjoerg ASTNodeNotSpelledInSourceScope RAII(this, true);
504*e038c9c4Sjoerg for (auto *SubStmt : RF->children()) {
505*e038c9c4Sjoerg if (SubStmt != RF->getBody())
506*e038c9c4Sjoerg TraverseStmt(SubStmt);
507*e038c9c4Sjoerg }
508*e038c9c4Sjoerg }
509*e038c9c4Sjoerg TraverseStmt(RF->getBody());
510*e038c9c4Sjoerg return true;
511*e038c9c4Sjoerg } else if (auto *RBO = dyn_cast<CXXRewrittenBinaryOperator>(S)) {
512*e038c9c4Sjoerg {
513*e038c9c4Sjoerg ASTNodeNotAsIsSourceScope RAII(this, true);
514*e038c9c4Sjoerg TraverseStmt(const_cast<Expr *>(RBO->getLHS()));
515*e038c9c4Sjoerg TraverseStmt(const_cast<Expr *>(RBO->getRHS()));
516*e038c9c4Sjoerg }
517*e038c9c4Sjoerg {
518*e038c9c4Sjoerg ASTNodeNotSpelledInSourceScope RAII(this, true);
519*e038c9c4Sjoerg for (auto *SubStmt : RBO->children()) {
520*e038c9c4Sjoerg TraverseStmt(SubStmt);
521*e038c9c4Sjoerg }
522*e038c9c4Sjoerg }
523*e038c9c4Sjoerg return true;
524*e038c9c4Sjoerg } else if (auto *LE = dyn_cast<LambdaExpr>(S)) {
525*e038c9c4Sjoerg for (auto I : llvm::zip(LE->captures(), LE->capture_inits())) {
526*e038c9c4Sjoerg auto C = std::get<0>(I);
527*e038c9c4Sjoerg ASTNodeNotSpelledInSourceScope RAII(
528*e038c9c4Sjoerg this, TraversingASTNodeNotSpelledInSource || !C.isExplicit());
529*e038c9c4Sjoerg TraverseLambdaCapture(LE, &C, std::get<1>(I));
530*e038c9c4Sjoerg }
531*e038c9c4Sjoerg
532*e038c9c4Sjoerg {
533*e038c9c4Sjoerg ASTNodeNotSpelledInSourceScope RAII(this, true);
534*e038c9c4Sjoerg TraverseDecl(LE->getLambdaClass());
535*e038c9c4Sjoerg }
536*e038c9c4Sjoerg {
537*e038c9c4Sjoerg ASTNodeNotAsIsSourceScope RAII(this, true);
538*e038c9c4Sjoerg
539*e038c9c4Sjoerg // We need to poke around to find the bits that might be explicitly
540*e038c9c4Sjoerg // written.
541*e038c9c4Sjoerg TypeLoc TL = LE->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
542*e038c9c4Sjoerg FunctionProtoTypeLoc Proto = TL.getAsAdjusted<FunctionProtoTypeLoc>();
543*e038c9c4Sjoerg
544*e038c9c4Sjoerg if (auto *TPL = LE->getTemplateParameterList()) {
545*e038c9c4Sjoerg for (NamedDecl *D : *TPL) {
546*e038c9c4Sjoerg TraverseDecl(D);
547*e038c9c4Sjoerg }
548*e038c9c4Sjoerg if (Expr *RequiresClause = TPL->getRequiresClause()) {
549*e038c9c4Sjoerg TraverseStmt(RequiresClause);
550*e038c9c4Sjoerg }
551*e038c9c4Sjoerg }
552*e038c9c4Sjoerg
553*e038c9c4Sjoerg if (LE->hasExplicitParameters()) {
554*e038c9c4Sjoerg // Visit parameters.
555*e038c9c4Sjoerg for (ParmVarDecl *Param : Proto.getParams())
556*e038c9c4Sjoerg TraverseDecl(Param);
557*e038c9c4Sjoerg }
558*e038c9c4Sjoerg
559*e038c9c4Sjoerg const auto *T = Proto.getTypePtr();
560*e038c9c4Sjoerg for (const auto &E : T->exceptions())
561*e038c9c4Sjoerg TraverseType(E);
562*e038c9c4Sjoerg
563*e038c9c4Sjoerg if (Expr *NE = T->getNoexceptExpr())
564*e038c9c4Sjoerg TraverseStmt(NE, Queue);
565*e038c9c4Sjoerg
566*e038c9c4Sjoerg if (LE->hasExplicitResultType())
567*e038c9c4Sjoerg TraverseTypeLoc(Proto.getReturnLoc());
568*e038c9c4Sjoerg TraverseStmt(LE->getTrailingRequiresClause());
569*e038c9c4Sjoerg }
570*e038c9c4Sjoerg
571*e038c9c4Sjoerg TraverseStmt(LE->getBody());
572*e038c9c4Sjoerg return true;
573*e038c9c4Sjoerg }
574*e038c9c4Sjoerg return RecursiveASTVisitor<MatchASTVisitor>::dataTraverseNode(S, Queue);
575*e038c9c4Sjoerg }
5767330f729Sjoerg
5777330f729Sjoerg // Matches children or descendants of 'Node' with 'BaseMatcher'.
memoizedMatchesRecursively(const DynTypedNode & Node,ASTContext & Ctx,const DynTypedMatcher & Matcher,BoundNodesTreeBuilder * Builder,int MaxDepth,BindKind Bind)578*e038c9c4Sjoerg bool memoizedMatchesRecursively(const DynTypedNode &Node, ASTContext &Ctx,
5797330f729Sjoerg const DynTypedMatcher &Matcher,
5807330f729Sjoerg BoundNodesTreeBuilder *Builder, int MaxDepth,
5817330f729Sjoerg BindKind Bind) {
5827330f729Sjoerg // For AST-nodes that don't have an identity, we can't memoize.
5837330f729Sjoerg if (!Node.getMemoizationData() || !Builder->isComparable())
584*e038c9c4Sjoerg return matchesRecursively(Node, Matcher, Builder, MaxDepth, Bind);
5857330f729Sjoerg
5867330f729Sjoerg MatchKey Key;
5877330f729Sjoerg Key.MatcherID = Matcher.getID();
5887330f729Sjoerg Key.Node = Node;
5897330f729Sjoerg // Note that we key on the bindings *before* the match.
5907330f729Sjoerg Key.BoundNodes = *Builder;
591*e038c9c4Sjoerg Key.Traversal = Ctx.getParentMapContext().getTraversalKind();
592*e038c9c4Sjoerg // Memoize result even doing a single-level match, it might be expensive.
593*e038c9c4Sjoerg Key.Type = MaxDepth == 1 ? MatchType::Child : MatchType::Descendants;
5947330f729Sjoerg MemoizationMap::iterator I = ResultCache.find(Key);
5957330f729Sjoerg if (I != ResultCache.end()) {
5967330f729Sjoerg *Builder = I->second.Nodes;
5977330f729Sjoerg return I->second.ResultOfMatch;
5987330f729Sjoerg }
5997330f729Sjoerg
6007330f729Sjoerg MemoizedMatchResult Result;
6017330f729Sjoerg Result.Nodes = *Builder;
602*e038c9c4Sjoerg Result.ResultOfMatch =
603*e038c9c4Sjoerg matchesRecursively(Node, Matcher, &Result.Nodes, MaxDepth, Bind);
6047330f729Sjoerg
6057330f729Sjoerg MemoizedMatchResult &CachedResult = ResultCache[Key];
6067330f729Sjoerg CachedResult = std::move(Result);
6077330f729Sjoerg
6087330f729Sjoerg *Builder = CachedResult.Nodes;
6097330f729Sjoerg return CachedResult.ResultOfMatch;
6107330f729Sjoerg }
6117330f729Sjoerg
6127330f729Sjoerg // Matches children or descendants of 'Node' with 'BaseMatcher'.
matchesRecursively(const DynTypedNode & Node,const DynTypedMatcher & Matcher,BoundNodesTreeBuilder * Builder,int MaxDepth,BindKind Bind)613*e038c9c4Sjoerg bool matchesRecursively(const DynTypedNode &Node,
6147330f729Sjoerg const DynTypedMatcher &Matcher,
6157330f729Sjoerg BoundNodesTreeBuilder *Builder, int MaxDepth,
6167330f729Sjoerg BindKind Bind) {
617*e038c9c4Sjoerg bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
618*e038c9c4Sjoerg TraversingASTChildrenNotSpelledInSource;
619*e038c9c4Sjoerg
620*e038c9c4Sjoerg bool IgnoreImplicitChildren = false;
621*e038c9c4Sjoerg
622*e038c9c4Sjoerg if (isTraversalIgnoringImplicitNodes()) {
623*e038c9c4Sjoerg IgnoreImplicitChildren = true;
624*e038c9c4Sjoerg }
625*e038c9c4Sjoerg
626*e038c9c4Sjoerg ASTNodeNotSpelledInSourceScope RAII(this, ScopedTraversal);
627*e038c9c4Sjoerg
628*e038c9c4Sjoerg MatchChildASTVisitor Visitor(&Matcher, this, Builder, MaxDepth,
629*e038c9c4Sjoerg IgnoreImplicitChildren, Bind);
6307330f729Sjoerg return Visitor.findMatch(Node);
6317330f729Sjoerg }
6327330f729Sjoerg
6337330f729Sjoerg bool classIsDerivedFrom(const CXXRecordDecl *Declaration,
6347330f729Sjoerg const Matcher<NamedDecl> &Base,
6357330f729Sjoerg BoundNodesTreeBuilder *Builder,
6367330f729Sjoerg bool Directly) override;
6377330f729Sjoerg
6387330f729Sjoerg bool objcClassIsDerivedFrom(const ObjCInterfaceDecl *Declaration,
6397330f729Sjoerg const Matcher<NamedDecl> &Base,
6407330f729Sjoerg BoundNodesTreeBuilder *Builder,
6417330f729Sjoerg bool Directly) override;
6427330f729Sjoerg
6437330f729Sjoerg // Implements ASTMatchFinder::matchesChildOf.
matchesChildOf(const DynTypedNode & Node,ASTContext & Ctx,const DynTypedMatcher & Matcher,BoundNodesTreeBuilder * Builder,BindKind Bind)644*e038c9c4Sjoerg bool matchesChildOf(const DynTypedNode &Node, ASTContext &Ctx,
6457330f729Sjoerg const DynTypedMatcher &Matcher,
646*e038c9c4Sjoerg BoundNodesTreeBuilder *Builder, BindKind Bind) override {
6477330f729Sjoerg if (ResultCache.size() > MaxMemoizationEntries)
6487330f729Sjoerg ResultCache.clear();
649*e038c9c4Sjoerg return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder, 1, Bind);
6507330f729Sjoerg }
6517330f729Sjoerg // Implements ASTMatchFinder::matchesDescendantOf.
matchesDescendantOf(const DynTypedNode & Node,ASTContext & Ctx,const DynTypedMatcher & Matcher,BoundNodesTreeBuilder * Builder,BindKind Bind)652*e038c9c4Sjoerg bool matchesDescendantOf(const DynTypedNode &Node, ASTContext &Ctx,
6537330f729Sjoerg const DynTypedMatcher &Matcher,
6547330f729Sjoerg BoundNodesTreeBuilder *Builder,
6557330f729Sjoerg BindKind Bind) override {
6567330f729Sjoerg if (ResultCache.size() > MaxMemoizationEntries)
6577330f729Sjoerg ResultCache.clear();
658*e038c9c4Sjoerg return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder, INT_MAX,
6597330f729Sjoerg Bind);
6607330f729Sjoerg }
6617330f729Sjoerg // Implements ASTMatchFinder::matchesAncestorOf.
matchesAncestorOf(const DynTypedNode & Node,ASTContext & Ctx,const DynTypedMatcher & Matcher,BoundNodesTreeBuilder * Builder,AncestorMatchMode MatchMode)662*e038c9c4Sjoerg bool matchesAncestorOf(const DynTypedNode &Node, ASTContext &Ctx,
6637330f729Sjoerg const DynTypedMatcher &Matcher,
6647330f729Sjoerg BoundNodesTreeBuilder *Builder,
6657330f729Sjoerg AncestorMatchMode MatchMode) override {
6667330f729Sjoerg // Reset the cache outside of the recursive call to make sure we
6677330f729Sjoerg // don't invalidate any iterators.
6687330f729Sjoerg if (ResultCache.size() > MaxMemoizationEntries)
6697330f729Sjoerg ResultCache.clear();
670*e038c9c4Sjoerg if (MatchMode == AncestorMatchMode::AMM_ParentOnly)
671*e038c9c4Sjoerg return matchesParentOf(Node, Matcher, Builder);
672*e038c9c4Sjoerg return matchesAnyAncestorOf(Node, Ctx, Matcher, Builder);
6737330f729Sjoerg }
6747330f729Sjoerg
6757330f729Sjoerg // Matches all registered matchers on the given node and calls the
6767330f729Sjoerg // result callback for every node that matches.
match(const DynTypedNode & Node)677*e038c9c4Sjoerg void match(const DynTypedNode &Node) {
6787330f729Sjoerg // FIXME: Improve this with a switch or a visitor pattern.
6797330f729Sjoerg if (auto *N = Node.get<Decl>()) {
6807330f729Sjoerg match(*N);
6817330f729Sjoerg } else if (auto *N = Node.get<Stmt>()) {
6827330f729Sjoerg match(*N);
6837330f729Sjoerg } else if (auto *N = Node.get<Type>()) {
6847330f729Sjoerg match(*N);
6857330f729Sjoerg } else if (auto *N = Node.get<QualType>()) {
6867330f729Sjoerg match(*N);
6877330f729Sjoerg } else if (auto *N = Node.get<NestedNameSpecifier>()) {
6887330f729Sjoerg match(*N);
6897330f729Sjoerg } else if (auto *N = Node.get<NestedNameSpecifierLoc>()) {
6907330f729Sjoerg match(*N);
6917330f729Sjoerg } else if (auto *N = Node.get<TypeLoc>()) {
6927330f729Sjoerg match(*N);
6937330f729Sjoerg } else if (auto *N = Node.get<CXXCtorInitializer>()) {
6947330f729Sjoerg match(*N);
695*e038c9c4Sjoerg } else if (auto *N = Node.get<TemplateArgumentLoc>()) {
696*e038c9c4Sjoerg match(*N);
6977330f729Sjoerg }
6987330f729Sjoerg }
6997330f729Sjoerg
match(const T & Node)7007330f729Sjoerg template <typename T> void match(const T &Node) {
7017330f729Sjoerg matchDispatch(&Node);
7027330f729Sjoerg }
7037330f729Sjoerg
7047330f729Sjoerg // Implements ASTMatchFinder::getASTContext.
getASTContext() const7057330f729Sjoerg ASTContext &getASTContext() const override { return *ActiveASTContext; }
7067330f729Sjoerg
shouldVisitTemplateInstantiations() const7077330f729Sjoerg bool shouldVisitTemplateInstantiations() const { return true; }
shouldVisitImplicitCode() const7087330f729Sjoerg bool shouldVisitImplicitCode() const { return true; }
7097330f729Sjoerg
710*e038c9c4Sjoerg // We visit the lambda body explicitly, so instruct the RAV
711*e038c9c4Sjoerg // to not visit it on our behalf too.
shouldVisitLambdaBody() const712*e038c9c4Sjoerg bool shouldVisitLambdaBody() const { return false; }
713*e038c9c4Sjoerg
IsMatchingInASTNodeNotSpelledInSource() const714*e038c9c4Sjoerg bool IsMatchingInASTNodeNotSpelledInSource() const override {
715*e038c9c4Sjoerg return TraversingASTNodeNotSpelledInSource;
716*e038c9c4Sjoerg }
isMatchingChildrenNotSpelledInSource() const717*e038c9c4Sjoerg bool isMatchingChildrenNotSpelledInSource() const override {
718*e038c9c4Sjoerg return TraversingASTChildrenNotSpelledInSource;
719*e038c9c4Sjoerg }
setMatchingChildrenNotSpelledInSource(bool Set)720*e038c9c4Sjoerg void setMatchingChildrenNotSpelledInSource(bool Set) override {
721*e038c9c4Sjoerg TraversingASTChildrenNotSpelledInSource = Set;
722*e038c9c4Sjoerg }
723*e038c9c4Sjoerg
IsMatchingInASTNodeNotAsIs() const724*e038c9c4Sjoerg bool IsMatchingInASTNodeNotAsIs() const override {
725*e038c9c4Sjoerg return TraversingASTNodeNotAsIs;
726*e038c9c4Sjoerg }
727*e038c9c4Sjoerg
TraverseTemplateInstantiations(ClassTemplateDecl * D)728*e038c9c4Sjoerg bool TraverseTemplateInstantiations(ClassTemplateDecl *D) {
729*e038c9c4Sjoerg ASTNodeNotSpelledInSourceScope RAII(this, true);
730*e038c9c4Sjoerg return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
731*e038c9c4Sjoerg D);
732*e038c9c4Sjoerg }
733*e038c9c4Sjoerg
TraverseTemplateInstantiations(VarTemplateDecl * D)734*e038c9c4Sjoerg bool TraverseTemplateInstantiations(VarTemplateDecl *D) {
735*e038c9c4Sjoerg ASTNodeNotSpelledInSourceScope RAII(this, true);
736*e038c9c4Sjoerg return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
737*e038c9c4Sjoerg D);
738*e038c9c4Sjoerg }
739*e038c9c4Sjoerg
TraverseTemplateInstantiations(FunctionTemplateDecl * D)740*e038c9c4Sjoerg bool TraverseTemplateInstantiations(FunctionTemplateDecl *D) {
741*e038c9c4Sjoerg ASTNodeNotSpelledInSourceScope RAII(this, true);
742*e038c9c4Sjoerg return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
743*e038c9c4Sjoerg D);
744*e038c9c4Sjoerg }
745*e038c9c4Sjoerg
7467330f729Sjoerg private:
747*e038c9c4Sjoerg bool TraversingASTNodeNotSpelledInSource = false;
748*e038c9c4Sjoerg bool TraversingASTNodeNotAsIs = false;
749*e038c9c4Sjoerg bool TraversingASTChildrenNotSpelledInSource = false;
750*e038c9c4Sjoerg
751*e038c9c4Sjoerg struct ASTNodeNotSpelledInSourceScope {
ASTNodeNotSpelledInSourceScopeclang::ast_matchers::internal::__anon62d4f9200111::MatchASTVisitor::ASTNodeNotSpelledInSourceScope752*e038c9c4Sjoerg ASTNodeNotSpelledInSourceScope(MatchASTVisitor *V, bool B)
753*e038c9c4Sjoerg : MV(V), MB(V->TraversingASTNodeNotSpelledInSource) {
754*e038c9c4Sjoerg V->TraversingASTNodeNotSpelledInSource = B;
755*e038c9c4Sjoerg }
~ASTNodeNotSpelledInSourceScopeclang::ast_matchers::internal::__anon62d4f9200111::MatchASTVisitor::ASTNodeNotSpelledInSourceScope756*e038c9c4Sjoerg ~ASTNodeNotSpelledInSourceScope() {
757*e038c9c4Sjoerg MV->TraversingASTNodeNotSpelledInSource = MB;
758*e038c9c4Sjoerg }
759*e038c9c4Sjoerg
760*e038c9c4Sjoerg private:
761*e038c9c4Sjoerg MatchASTVisitor *MV;
762*e038c9c4Sjoerg bool MB;
763*e038c9c4Sjoerg };
764*e038c9c4Sjoerg
765*e038c9c4Sjoerg struct ASTNodeNotAsIsSourceScope {
ASTNodeNotAsIsSourceScopeclang::ast_matchers::internal::__anon62d4f9200111::MatchASTVisitor::ASTNodeNotAsIsSourceScope766*e038c9c4Sjoerg ASTNodeNotAsIsSourceScope(MatchASTVisitor *V, bool B)
767*e038c9c4Sjoerg : MV(V), MB(V->TraversingASTNodeNotAsIs) {
768*e038c9c4Sjoerg V->TraversingASTNodeNotAsIs = B;
769*e038c9c4Sjoerg }
~ASTNodeNotAsIsSourceScopeclang::ast_matchers::internal::__anon62d4f9200111::MatchASTVisitor::ASTNodeNotAsIsSourceScope770*e038c9c4Sjoerg ~ASTNodeNotAsIsSourceScope() { MV->TraversingASTNodeNotAsIs = MB; }
771*e038c9c4Sjoerg
772*e038c9c4Sjoerg private:
773*e038c9c4Sjoerg MatchASTVisitor *MV;
774*e038c9c4Sjoerg bool MB;
775*e038c9c4Sjoerg };
776*e038c9c4Sjoerg
7777330f729Sjoerg class TimeBucketRegion {
7787330f729Sjoerg public:
TimeBucketRegion()7797330f729Sjoerg TimeBucketRegion() : Bucket(nullptr) {}
~TimeBucketRegion()7807330f729Sjoerg ~TimeBucketRegion() { setBucket(nullptr); }
7817330f729Sjoerg
7827330f729Sjoerg /// Start timing for \p NewBucket.
7837330f729Sjoerg ///
7847330f729Sjoerg /// If there was a bucket already set, it will finish the timing for that
7857330f729Sjoerg /// other bucket.
7867330f729Sjoerg /// \p NewBucket will be timed until the next call to \c setBucket() or
7877330f729Sjoerg /// until the \c TimeBucketRegion is destroyed.
7887330f729Sjoerg /// If \p NewBucket is the same as the currently timed bucket, this call
7897330f729Sjoerg /// does nothing.
setBucket(llvm::TimeRecord * NewBucket)7907330f729Sjoerg void setBucket(llvm::TimeRecord *NewBucket) {
7917330f729Sjoerg if (Bucket != NewBucket) {
7927330f729Sjoerg auto Now = llvm::TimeRecord::getCurrentTime(true);
7937330f729Sjoerg if (Bucket)
7947330f729Sjoerg *Bucket += Now;
7957330f729Sjoerg if (NewBucket)
7967330f729Sjoerg *NewBucket -= Now;
7977330f729Sjoerg Bucket = NewBucket;
7987330f729Sjoerg }
7997330f729Sjoerg }
8007330f729Sjoerg
8017330f729Sjoerg private:
8027330f729Sjoerg llvm::TimeRecord *Bucket;
8037330f729Sjoerg };
8047330f729Sjoerg
8057330f729Sjoerg /// Runs all the \p Matchers on \p Node.
8067330f729Sjoerg ///
8077330f729Sjoerg /// Used by \c matchDispatch() below.
8087330f729Sjoerg template <typename T, typename MC>
matchWithoutFilter(const T & Node,const MC & Matchers)8097330f729Sjoerg void matchWithoutFilter(const T &Node, const MC &Matchers) {
8107330f729Sjoerg const bool EnableCheckProfiling = Options.CheckProfiling.hasValue();
8117330f729Sjoerg TimeBucketRegion Timer;
8127330f729Sjoerg for (const auto &MP : Matchers) {
8137330f729Sjoerg if (EnableCheckProfiling)
8147330f729Sjoerg Timer.setBucket(&TimeByBucket[MP.second->getID()]);
8157330f729Sjoerg BoundNodesTreeBuilder Builder;
8167330f729Sjoerg if (MP.first.matches(Node, this, &Builder)) {
8177330f729Sjoerg MatchVisitor Visitor(ActiveASTContext, MP.second);
8187330f729Sjoerg Builder.visitMatches(&Visitor);
8197330f729Sjoerg }
8207330f729Sjoerg }
8217330f729Sjoerg }
8227330f729Sjoerg
matchWithFilter(const DynTypedNode & DynNode)823*e038c9c4Sjoerg void matchWithFilter(const DynTypedNode &DynNode) {
8247330f729Sjoerg auto Kind = DynNode.getNodeKind();
8257330f729Sjoerg auto it = MatcherFiltersMap.find(Kind);
8267330f729Sjoerg const auto &Filter =
8277330f729Sjoerg it != MatcherFiltersMap.end() ? it->second : getFilterForKind(Kind);
8287330f729Sjoerg
8297330f729Sjoerg if (Filter.empty())
8307330f729Sjoerg return;
8317330f729Sjoerg
8327330f729Sjoerg const bool EnableCheckProfiling = Options.CheckProfiling.hasValue();
8337330f729Sjoerg TimeBucketRegion Timer;
8347330f729Sjoerg auto &Matchers = this->Matchers->DeclOrStmt;
8357330f729Sjoerg for (unsigned short I : Filter) {
8367330f729Sjoerg auto &MP = Matchers[I];
8377330f729Sjoerg if (EnableCheckProfiling)
8387330f729Sjoerg Timer.setBucket(&TimeByBucket[MP.second->getID()]);
8397330f729Sjoerg BoundNodesTreeBuilder Builder;
840*e038c9c4Sjoerg
841*e038c9c4Sjoerg {
842*e038c9c4Sjoerg TraversalKindScope RAII(getASTContext(), MP.first.getTraversalKind());
843*e038c9c4Sjoerg if (getASTContext().getParentMapContext().traverseIgnored(DynNode) !=
844*e038c9c4Sjoerg DynNode)
845*e038c9c4Sjoerg continue;
846*e038c9c4Sjoerg }
847*e038c9c4Sjoerg
848*e038c9c4Sjoerg if (MP.first.matches(DynNode, this, &Builder)) {
8497330f729Sjoerg MatchVisitor Visitor(ActiveASTContext, MP.second);
8507330f729Sjoerg Builder.visitMatches(&Visitor);
8517330f729Sjoerg }
8527330f729Sjoerg }
8537330f729Sjoerg }
8547330f729Sjoerg
getFilterForKind(ASTNodeKind Kind)855*e038c9c4Sjoerg const std::vector<unsigned short> &getFilterForKind(ASTNodeKind Kind) {
8567330f729Sjoerg auto &Filter = MatcherFiltersMap[Kind];
8577330f729Sjoerg auto &Matchers = this->Matchers->DeclOrStmt;
8587330f729Sjoerg assert((Matchers.size() < USHRT_MAX) && "Too many matchers.");
8597330f729Sjoerg for (unsigned I = 0, E = Matchers.size(); I != E; ++I) {
8607330f729Sjoerg if (Matchers[I].first.canMatchNodesOfKind(Kind)) {
8617330f729Sjoerg Filter.push_back(I);
8627330f729Sjoerg }
8637330f729Sjoerg }
8647330f729Sjoerg return Filter;
8657330f729Sjoerg }
8667330f729Sjoerg
8677330f729Sjoerg /// @{
8687330f729Sjoerg /// Overloads to pair the different node types to their matchers.
matchDispatch(const Decl * Node)8697330f729Sjoerg void matchDispatch(const Decl *Node) {
870*e038c9c4Sjoerg return matchWithFilter(DynTypedNode::create(*Node));
8717330f729Sjoerg }
matchDispatch(const Stmt * Node)8727330f729Sjoerg void matchDispatch(const Stmt *Node) {
873*e038c9c4Sjoerg return matchWithFilter(DynTypedNode::create(*Node));
8747330f729Sjoerg }
8757330f729Sjoerg
matchDispatch(const Type * Node)8767330f729Sjoerg void matchDispatch(const Type *Node) {
8777330f729Sjoerg matchWithoutFilter(QualType(Node, 0), Matchers->Type);
8787330f729Sjoerg }
matchDispatch(const TypeLoc * Node)8797330f729Sjoerg void matchDispatch(const TypeLoc *Node) {
8807330f729Sjoerg matchWithoutFilter(*Node, Matchers->TypeLoc);
8817330f729Sjoerg }
matchDispatch(const QualType * Node)8827330f729Sjoerg void matchDispatch(const QualType *Node) {
8837330f729Sjoerg matchWithoutFilter(*Node, Matchers->Type);
8847330f729Sjoerg }
matchDispatch(const NestedNameSpecifier * Node)8857330f729Sjoerg void matchDispatch(const NestedNameSpecifier *Node) {
8867330f729Sjoerg matchWithoutFilter(*Node, Matchers->NestedNameSpecifier);
8877330f729Sjoerg }
matchDispatch(const NestedNameSpecifierLoc * Node)8887330f729Sjoerg void matchDispatch(const NestedNameSpecifierLoc *Node) {
8897330f729Sjoerg matchWithoutFilter(*Node, Matchers->NestedNameSpecifierLoc);
8907330f729Sjoerg }
matchDispatch(const CXXCtorInitializer * Node)8917330f729Sjoerg void matchDispatch(const CXXCtorInitializer *Node) {
8927330f729Sjoerg matchWithoutFilter(*Node, Matchers->CtorInit);
8937330f729Sjoerg }
matchDispatch(const TemplateArgumentLoc * Node)894*e038c9c4Sjoerg void matchDispatch(const TemplateArgumentLoc *Node) {
895*e038c9c4Sjoerg matchWithoutFilter(*Node, Matchers->TemplateArgumentLoc);
896*e038c9c4Sjoerg }
matchDispatch(const void *)8977330f729Sjoerg void matchDispatch(const void *) { /* Do nothing. */ }
8987330f729Sjoerg /// @}
8997330f729Sjoerg
900*e038c9c4Sjoerg // Returns whether a direct parent of \p Node matches \p Matcher.
901*e038c9c4Sjoerg // Unlike matchesAnyAncestorOf there's no memoization: it doesn't save much.
matchesParentOf(const DynTypedNode & Node,const DynTypedMatcher & Matcher,BoundNodesTreeBuilder * Builder)902*e038c9c4Sjoerg bool matchesParentOf(const DynTypedNode &Node, const DynTypedMatcher &Matcher,
903*e038c9c4Sjoerg BoundNodesTreeBuilder *Builder) {
904*e038c9c4Sjoerg for (const auto &Parent : ActiveASTContext->getParents(Node)) {
905*e038c9c4Sjoerg BoundNodesTreeBuilder BuilderCopy = *Builder;
906*e038c9c4Sjoerg if (Matcher.matches(Parent, this, &BuilderCopy)) {
907*e038c9c4Sjoerg *Builder = std::move(BuilderCopy);
908*e038c9c4Sjoerg return true;
909*e038c9c4Sjoerg }
910*e038c9c4Sjoerg }
911*e038c9c4Sjoerg return false;
912*e038c9c4Sjoerg }
913*e038c9c4Sjoerg
9147330f729Sjoerg // Returns whether an ancestor of \p Node matches \p Matcher.
9157330f729Sjoerg //
916*e038c9c4Sjoerg // The order of matching (which can lead to different nodes being bound in
9177330f729Sjoerg // case there are multiple matches) is breadth first search.
9187330f729Sjoerg //
9197330f729Sjoerg // To allow memoization in the very common case of having deeply nested
9207330f729Sjoerg // expressions inside a template function, we first walk up the AST, memoizing
9217330f729Sjoerg // the result of the match along the way, as long as there is only a single
9227330f729Sjoerg // parent.
9237330f729Sjoerg //
9247330f729Sjoerg // Once there are multiple parents, the breadth first search order does not
9257330f729Sjoerg // allow simple memoization on the ancestors. Thus, we only memoize as long
9267330f729Sjoerg // as there is a single parent.
927*e038c9c4Sjoerg //
928*e038c9c4Sjoerg // We avoid a recursive implementation to prevent excessive stack use on
929*e038c9c4Sjoerg // very deep ASTs (similarly to RecursiveASTVisitor's data recursion).
matchesAnyAncestorOf(DynTypedNode Node,ASTContext & Ctx,const DynTypedMatcher & Matcher,BoundNodesTreeBuilder * Builder)930*e038c9c4Sjoerg bool matchesAnyAncestorOf(DynTypedNode Node, ASTContext &Ctx,
9317330f729Sjoerg const DynTypedMatcher &Matcher,
932*e038c9c4Sjoerg BoundNodesTreeBuilder *Builder) {
933*e038c9c4Sjoerg
934*e038c9c4Sjoerg // Memoization keys that can be updated with the result.
935*e038c9c4Sjoerg // These are the memoizable nodes in the chain of unique parents, which
936*e038c9c4Sjoerg // terminates when a node has multiple parents, or matches, or is the root.
937*e038c9c4Sjoerg std::vector<MatchKey> Keys;
938*e038c9c4Sjoerg // When returning, update the memoization cache.
939*e038c9c4Sjoerg auto Finish = [&](bool Matched) {
940*e038c9c4Sjoerg for (const auto &Key : Keys) {
941*e038c9c4Sjoerg MemoizedMatchResult &CachedResult = ResultCache[Key];
942*e038c9c4Sjoerg CachedResult.ResultOfMatch = Matched;
943*e038c9c4Sjoerg CachedResult.Nodes = *Builder;
944*e038c9c4Sjoerg }
945*e038c9c4Sjoerg return Matched;
946*e038c9c4Sjoerg };
947*e038c9c4Sjoerg
948*e038c9c4Sjoerg // Loop while there's a single parent and we want to attempt memoization.
949*e038c9c4Sjoerg DynTypedNodeList Parents{ArrayRef<DynTypedNode>()}; // after loop: size != 1
950*e038c9c4Sjoerg for (;;) {
951*e038c9c4Sjoerg // A cache key only makes sense if memoization is possible.
952*e038c9c4Sjoerg if (Builder->isComparable()) {
953*e038c9c4Sjoerg Keys.emplace_back();
954*e038c9c4Sjoerg Keys.back().MatcherID = Matcher.getID();
955*e038c9c4Sjoerg Keys.back().Node = Node;
956*e038c9c4Sjoerg Keys.back().BoundNodes = *Builder;
957*e038c9c4Sjoerg Keys.back().Traversal = Ctx.getParentMapContext().getTraversalKind();
958*e038c9c4Sjoerg Keys.back().Type = MatchType::Ancestors;
959*e038c9c4Sjoerg
960*e038c9c4Sjoerg // Check the cache.
961*e038c9c4Sjoerg MemoizationMap::iterator I = ResultCache.find(Keys.back());
962*e038c9c4Sjoerg if (I != ResultCache.end()) {
963*e038c9c4Sjoerg Keys.pop_back(); // Don't populate the cache for the matching node!
964*e038c9c4Sjoerg *Builder = I->second.Nodes;
965*e038c9c4Sjoerg return Finish(I->second.ResultOfMatch);
966*e038c9c4Sjoerg }
967*e038c9c4Sjoerg }
968*e038c9c4Sjoerg
969*e038c9c4Sjoerg Parents = ActiveASTContext->getParents(Node);
970*e038c9c4Sjoerg // Either no parents or multiple parents: leave chain+memoize mode and
971*e038c9c4Sjoerg // enter bfs+forgetful mode.
972*e038c9c4Sjoerg if (Parents.size() != 1)
973*e038c9c4Sjoerg break;
974*e038c9c4Sjoerg
975*e038c9c4Sjoerg // Check the next parent.
976*e038c9c4Sjoerg Node = *Parents.begin();
977*e038c9c4Sjoerg BoundNodesTreeBuilder BuilderCopy = *Builder;
978*e038c9c4Sjoerg if (Matcher.matches(Node, this, &BuilderCopy)) {
979*e038c9c4Sjoerg *Builder = std::move(BuilderCopy);
980*e038c9c4Sjoerg return Finish(true);
981*e038c9c4Sjoerg }
982*e038c9c4Sjoerg }
983*e038c9c4Sjoerg // We reached the end of the chain.
984*e038c9c4Sjoerg
9857330f729Sjoerg if (Parents.empty()) {
9867330f729Sjoerg // Nodes may have no parents if:
9877330f729Sjoerg // a) the node is the TranslationUnitDecl
9887330f729Sjoerg // b) we have a limited traversal scope that excludes the parent edges
9897330f729Sjoerg // c) there is a bug in the AST, and the node is not reachable
9907330f729Sjoerg // Usually the traversal scope is the whole AST, which precludes b.
9917330f729Sjoerg // Bugs are common enough that it's worthwhile asserting when we can.
9927330f729Sjoerg #ifndef NDEBUG
9937330f729Sjoerg if (!Node.get<TranslationUnitDecl>() &&
9947330f729Sjoerg /* Traversal scope is full AST if any of the bounds are the TU */
9957330f729Sjoerg llvm::any_of(ActiveASTContext->getTraversalScope(), [](Decl *D) {
9967330f729Sjoerg return D->getKind() == Decl::TranslationUnit;
9977330f729Sjoerg })) {
9987330f729Sjoerg llvm::errs() << "Tried to match orphan node:\n";
999*e038c9c4Sjoerg Node.dump(llvm::errs(), *ActiveASTContext);
10007330f729Sjoerg llvm_unreachable("Parent map should be complete!");
10017330f729Sjoerg }
10027330f729Sjoerg #endif
10037330f729Sjoerg } else {
1004*e038c9c4Sjoerg assert(Parents.size() > 1);
1005*e038c9c4Sjoerg // BFS starting from the parents not yet considered.
1006*e038c9c4Sjoerg // Memoization of newly visited nodes is not possible (but we still update
1007*e038c9c4Sjoerg // results for the elements in the chain we found above).
1008*e038c9c4Sjoerg std::deque<DynTypedNode> Queue(Parents.begin(), Parents.end());
10097330f729Sjoerg llvm::DenseSet<const void *> Visited;
10107330f729Sjoerg while (!Queue.empty()) {
10117330f729Sjoerg BoundNodesTreeBuilder BuilderCopy = *Builder;
10127330f729Sjoerg if (Matcher.matches(Queue.front(), this, &BuilderCopy)) {
10137330f729Sjoerg *Builder = std::move(BuilderCopy);
1014*e038c9c4Sjoerg return Finish(true);
10157330f729Sjoerg }
1016*e038c9c4Sjoerg for (const auto &Parent : ActiveASTContext->getParents(Queue.front())) {
10177330f729Sjoerg // Make sure we do not visit the same node twice.
10187330f729Sjoerg // Otherwise, we'll visit the common ancestors as often as there
10197330f729Sjoerg // are splits on the way down.
10207330f729Sjoerg if (Visited.insert(Parent.getMemoizationData()).second)
10217330f729Sjoerg Queue.push_back(Parent);
10227330f729Sjoerg }
10237330f729Sjoerg Queue.pop_front();
10247330f729Sjoerg }
10257330f729Sjoerg }
1026*e038c9c4Sjoerg return Finish(false);
10277330f729Sjoerg }
10287330f729Sjoerg
10297330f729Sjoerg // Implements a BoundNodesTree::Visitor that calls a MatchCallback with
10307330f729Sjoerg // the aggregated bound nodes for each match.
10317330f729Sjoerg class MatchVisitor : public BoundNodesTreeBuilder::Visitor {
10327330f729Sjoerg public:
MatchVisitor(ASTContext * Context,MatchFinder::MatchCallback * Callback)10337330f729Sjoerg MatchVisitor(ASTContext* Context,
10347330f729Sjoerg MatchFinder::MatchCallback* Callback)
10357330f729Sjoerg : Context(Context),
10367330f729Sjoerg Callback(Callback) {}
10377330f729Sjoerg
visitMatch(const BoundNodes & BoundNodesView)10387330f729Sjoerg void visitMatch(const BoundNodes& BoundNodesView) override {
1039*e038c9c4Sjoerg TraversalKindScope RAII(*Context, Callback->getCheckTraversalKind());
10407330f729Sjoerg Callback->run(MatchFinder::MatchResult(BoundNodesView, Context));
10417330f729Sjoerg }
10427330f729Sjoerg
10437330f729Sjoerg private:
10447330f729Sjoerg ASTContext* Context;
10457330f729Sjoerg MatchFinder::MatchCallback* Callback;
10467330f729Sjoerg };
10477330f729Sjoerg
10487330f729Sjoerg // Returns true if 'TypeNode' has an alias that matches the given matcher.
typeHasMatchingAlias(const Type * TypeNode,const Matcher<NamedDecl> & Matcher,BoundNodesTreeBuilder * Builder)10497330f729Sjoerg bool typeHasMatchingAlias(const Type *TypeNode,
10507330f729Sjoerg const Matcher<NamedDecl> &Matcher,
10517330f729Sjoerg BoundNodesTreeBuilder *Builder) {
10527330f729Sjoerg const Type *const CanonicalType =
10537330f729Sjoerg ActiveASTContext->getCanonicalType(TypeNode);
10547330f729Sjoerg auto Aliases = TypeAliases.find(CanonicalType);
10557330f729Sjoerg if (Aliases == TypeAliases.end())
10567330f729Sjoerg return false;
10577330f729Sjoerg for (const TypedefNameDecl *Alias : Aliases->second) {
10587330f729Sjoerg BoundNodesTreeBuilder Result(*Builder);
10597330f729Sjoerg if (Matcher.matches(*Alias, this, &Result)) {
10607330f729Sjoerg *Builder = std::move(Result);
10617330f729Sjoerg return true;
10627330f729Sjoerg }
10637330f729Sjoerg }
10647330f729Sjoerg return false;
10657330f729Sjoerg }
10667330f729Sjoerg
10677330f729Sjoerg bool
objcClassHasMatchingCompatibilityAlias(const ObjCInterfaceDecl * InterfaceDecl,const Matcher<NamedDecl> & Matcher,BoundNodesTreeBuilder * Builder)10687330f729Sjoerg objcClassHasMatchingCompatibilityAlias(const ObjCInterfaceDecl *InterfaceDecl,
10697330f729Sjoerg const Matcher<NamedDecl> &Matcher,
10707330f729Sjoerg BoundNodesTreeBuilder *Builder) {
10717330f729Sjoerg auto Aliases = CompatibleAliases.find(InterfaceDecl);
10727330f729Sjoerg if (Aliases == CompatibleAliases.end())
10737330f729Sjoerg return false;
10747330f729Sjoerg for (const ObjCCompatibleAliasDecl *Alias : Aliases->second) {
10757330f729Sjoerg BoundNodesTreeBuilder Result(*Builder);
10767330f729Sjoerg if (Matcher.matches(*Alias, this, &Result)) {
10777330f729Sjoerg *Builder = std::move(Result);
10787330f729Sjoerg return true;
10797330f729Sjoerg }
10807330f729Sjoerg }
10817330f729Sjoerg return false;
10827330f729Sjoerg }
10837330f729Sjoerg
10847330f729Sjoerg /// Bucket to record map.
10857330f729Sjoerg ///
10867330f729Sjoerg /// Used to get the appropriate bucket for each matcher.
10877330f729Sjoerg llvm::StringMap<llvm::TimeRecord> TimeByBucket;
10887330f729Sjoerg
10897330f729Sjoerg const MatchFinder::MatchersByType *Matchers;
10907330f729Sjoerg
10917330f729Sjoerg /// Filtered list of matcher indices for each matcher kind.
10927330f729Sjoerg ///
10937330f729Sjoerg /// \c Decl and \c Stmt toplevel matchers usually apply to a specific node
10947330f729Sjoerg /// kind (and derived kinds) so it is a waste to try every matcher on every
10957330f729Sjoerg /// node.
10967330f729Sjoerg /// We precalculate a list of matchers that pass the toplevel restrict check.
1097*e038c9c4Sjoerg llvm::DenseMap<ASTNodeKind, std::vector<unsigned short>> MatcherFiltersMap;
10987330f729Sjoerg
10997330f729Sjoerg const MatchFinder::MatchFinderOptions &Options;
11007330f729Sjoerg ASTContext *ActiveASTContext;
11017330f729Sjoerg
11027330f729Sjoerg // Maps a canonical type to its TypedefDecls.
11037330f729Sjoerg llvm::DenseMap<const Type*, std::set<const TypedefNameDecl*> > TypeAliases;
11047330f729Sjoerg
11057330f729Sjoerg // Maps an Objective-C interface to its ObjCCompatibleAliasDecls.
11067330f729Sjoerg llvm::DenseMap<const ObjCInterfaceDecl *,
11077330f729Sjoerg llvm::SmallPtrSet<const ObjCCompatibleAliasDecl *, 2>>
11087330f729Sjoerg CompatibleAliases;
11097330f729Sjoerg
11107330f729Sjoerg // Maps (matcher, node) -> the match result for memoization.
11117330f729Sjoerg typedef std::map<MatchKey, MemoizedMatchResult> MemoizationMap;
11127330f729Sjoerg MemoizationMap ResultCache;
11137330f729Sjoerg };
11147330f729Sjoerg
11157330f729Sjoerg static CXXRecordDecl *
getAsCXXRecordDeclOrPrimaryTemplate(const Type * TypeNode)11167330f729Sjoerg getAsCXXRecordDeclOrPrimaryTemplate(const Type *TypeNode) {
11177330f729Sjoerg if (auto *RD = TypeNode->getAsCXXRecordDecl())
11187330f729Sjoerg return RD;
11197330f729Sjoerg
11207330f729Sjoerg // Find the innermost TemplateSpecializationType that isn't an alias template.
11217330f729Sjoerg auto *TemplateType = TypeNode->getAs<TemplateSpecializationType>();
11227330f729Sjoerg while (TemplateType && TemplateType->isTypeAlias())
11237330f729Sjoerg TemplateType =
11247330f729Sjoerg TemplateType->getAliasedType()->getAs<TemplateSpecializationType>();
11257330f729Sjoerg
11267330f729Sjoerg // If this is the name of a (dependent) template specialization, use the
11277330f729Sjoerg // definition of the template, even though it might be specialized later.
11287330f729Sjoerg if (TemplateType)
11297330f729Sjoerg if (auto *ClassTemplate = dyn_cast_or_null<ClassTemplateDecl>(
11307330f729Sjoerg TemplateType->getTemplateName().getAsTemplateDecl()))
11317330f729Sjoerg return ClassTemplate->getTemplatedDecl();
11327330f729Sjoerg
11337330f729Sjoerg return nullptr;
11347330f729Sjoerg }
11357330f729Sjoerg
11367330f729Sjoerg // Returns true if the given C++ class is directly or indirectly derived
11377330f729Sjoerg // from a base type with the given name. A class is not considered to be
11387330f729Sjoerg // derived from itself.
classIsDerivedFrom(const CXXRecordDecl * Declaration,const Matcher<NamedDecl> & Base,BoundNodesTreeBuilder * Builder,bool Directly)11397330f729Sjoerg bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
11407330f729Sjoerg const Matcher<NamedDecl> &Base,
11417330f729Sjoerg BoundNodesTreeBuilder *Builder,
11427330f729Sjoerg bool Directly) {
11437330f729Sjoerg if (!Declaration->hasDefinition())
11447330f729Sjoerg return false;
11457330f729Sjoerg for (const auto &It : Declaration->bases()) {
11467330f729Sjoerg const Type *TypeNode = It.getType().getTypePtr();
11477330f729Sjoerg
11487330f729Sjoerg if (typeHasMatchingAlias(TypeNode, Base, Builder))
11497330f729Sjoerg return true;
11507330f729Sjoerg
11517330f729Sjoerg // FIXME: Going to the primary template here isn't really correct, but
11527330f729Sjoerg // unfortunately we accept a Decl matcher for the base class not a Type
11537330f729Sjoerg // matcher, so it's the best thing we can do with our current interface.
11547330f729Sjoerg CXXRecordDecl *ClassDecl = getAsCXXRecordDeclOrPrimaryTemplate(TypeNode);
11557330f729Sjoerg if (!ClassDecl)
11567330f729Sjoerg continue;
11577330f729Sjoerg if (ClassDecl == Declaration) {
1158*e038c9c4Sjoerg // This can happen for recursive template definitions.
1159*e038c9c4Sjoerg continue;
11607330f729Sjoerg }
11617330f729Sjoerg BoundNodesTreeBuilder Result(*Builder);
11627330f729Sjoerg if (Base.matches(*ClassDecl, this, &Result)) {
11637330f729Sjoerg *Builder = std::move(Result);
11647330f729Sjoerg return true;
11657330f729Sjoerg }
11667330f729Sjoerg if (!Directly && classIsDerivedFrom(ClassDecl, Base, Builder, Directly))
11677330f729Sjoerg return true;
11687330f729Sjoerg }
11697330f729Sjoerg return false;
11707330f729Sjoerg }
11717330f729Sjoerg
11727330f729Sjoerg // Returns true if the given Objective-C class is directly or indirectly
11737330f729Sjoerg // derived from a matching base class. A class is not considered to be derived
11747330f729Sjoerg // from itself.
objcClassIsDerivedFrom(const ObjCInterfaceDecl * Declaration,const Matcher<NamedDecl> & Base,BoundNodesTreeBuilder * Builder,bool Directly)11757330f729Sjoerg bool MatchASTVisitor::objcClassIsDerivedFrom(
11767330f729Sjoerg const ObjCInterfaceDecl *Declaration, const Matcher<NamedDecl> &Base,
11777330f729Sjoerg BoundNodesTreeBuilder *Builder, bool Directly) {
11787330f729Sjoerg // Check if any of the superclasses of the class match.
11797330f729Sjoerg for (const ObjCInterfaceDecl *ClassDecl = Declaration->getSuperClass();
11807330f729Sjoerg ClassDecl != nullptr; ClassDecl = ClassDecl->getSuperClass()) {
11817330f729Sjoerg // Check if there are any matching compatibility aliases.
11827330f729Sjoerg if (objcClassHasMatchingCompatibilityAlias(ClassDecl, Base, Builder))
11837330f729Sjoerg return true;
11847330f729Sjoerg
11857330f729Sjoerg // Check if there are any matching type aliases.
11867330f729Sjoerg const Type *TypeNode = ClassDecl->getTypeForDecl();
11877330f729Sjoerg if (typeHasMatchingAlias(TypeNode, Base, Builder))
11887330f729Sjoerg return true;
11897330f729Sjoerg
11907330f729Sjoerg if (Base.matches(*ClassDecl, this, Builder))
11917330f729Sjoerg return true;
11927330f729Sjoerg
1193*e038c9c4Sjoerg // Not `return false` as a temporary workaround for PR43879.
11947330f729Sjoerg if (Directly)
1195*e038c9c4Sjoerg break;
11967330f729Sjoerg }
11977330f729Sjoerg
11987330f729Sjoerg return false;
11997330f729Sjoerg }
12007330f729Sjoerg
TraverseDecl(Decl * DeclNode)12017330f729Sjoerg bool MatchASTVisitor::TraverseDecl(Decl *DeclNode) {
12027330f729Sjoerg if (!DeclNode) {
12037330f729Sjoerg return true;
12047330f729Sjoerg }
1205*e038c9c4Sjoerg
1206*e038c9c4Sjoerg bool ScopedTraversal =
1207*e038c9c4Sjoerg TraversingASTNodeNotSpelledInSource || DeclNode->isImplicit();
1208*e038c9c4Sjoerg bool ScopedChildren = TraversingASTChildrenNotSpelledInSource;
1209*e038c9c4Sjoerg
1210*e038c9c4Sjoerg if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(DeclNode)) {
1211*e038c9c4Sjoerg auto SK = CTSD->getSpecializationKind();
1212*e038c9c4Sjoerg if (SK == TSK_ExplicitInstantiationDeclaration ||
1213*e038c9c4Sjoerg SK == TSK_ExplicitInstantiationDefinition)
1214*e038c9c4Sjoerg ScopedChildren = true;
1215*e038c9c4Sjoerg } else if (const auto *FD = dyn_cast<FunctionDecl>(DeclNode)) {
1216*e038c9c4Sjoerg if (FD->isDefaulted())
1217*e038c9c4Sjoerg ScopedChildren = true;
1218*e038c9c4Sjoerg if (FD->isTemplateInstantiation())
1219*e038c9c4Sjoerg ScopedTraversal = true;
1220*e038c9c4Sjoerg } else if (isa<BindingDecl>(DeclNode)) {
1221*e038c9c4Sjoerg ScopedChildren = true;
1222*e038c9c4Sjoerg }
1223*e038c9c4Sjoerg
1224*e038c9c4Sjoerg ASTNodeNotSpelledInSourceScope RAII1(this, ScopedTraversal);
1225*e038c9c4Sjoerg ASTChildrenNotSpelledInSourceScope RAII2(this, ScopedChildren);
1226*e038c9c4Sjoerg
12277330f729Sjoerg match(*DeclNode);
12287330f729Sjoerg return RecursiveASTVisitor<MatchASTVisitor>::TraverseDecl(DeclNode);
12297330f729Sjoerg }
12307330f729Sjoerg
TraverseStmt(Stmt * StmtNode,DataRecursionQueue * Queue)12317330f729Sjoerg bool MatchASTVisitor::TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue) {
12327330f729Sjoerg if (!StmtNode) {
12337330f729Sjoerg return true;
12347330f729Sjoerg }
1235*e038c9c4Sjoerg bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
1236*e038c9c4Sjoerg TraversingASTChildrenNotSpelledInSource;
1237*e038c9c4Sjoerg
1238*e038c9c4Sjoerg ASTNodeNotSpelledInSourceScope RAII(this, ScopedTraversal);
12397330f729Sjoerg match(*StmtNode);
12407330f729Sjoerg return RecursiveASTVisitor<MatchASTVisitor>::TraverseStmt(StmtNode, Queue);
12417330f729Sjoerg }
12427330f729Sjoerg
TraverseType(QualType TypeNode)12437330f729Sjoerg bool MatchASTVisitor::TraverseType(QualType TypeNode) {
12447330f729Sjoerg match(TypeNode);
12457330f729Sjoerg return RecursiveASTVisitor<MatchASTVisitor>::TraverseType(TypeNode);
12467330f729Sjoerg }
12477330f729Sjoerg
TraverseTypeLoc(TypeLoc TypeLocNode)12487330f729Sjoerg bool MatchASTVisitor::TraverseTypeLoc(TypeLoc TypeLocNode) {
12497330f729Sjoerg // The RecursiveASTVisitor only visits types if they're not within TypeLocs.
12507330f729Sjoerg // We still want to find those types via matchers, so we match them here. Note
12517330f729Sjoerg // that the TypeLocs are structurally a shadow-hierarchy to the expressed
12527330f729Sjoerg // type, so we visit all involved parts of a compound type when matching on
12537330f729Sjoerg // each TypeLoc.
12547330f729Sjoerg match(TypeLocNode);
12557330f729Sjoerg match(TypeLocNode.getType());
12567330f729Sjoerg return RecursiveASTVisitor<MatchASTVisitor>::TraverseTypeLoc(TypeLocNode);
12577330f729Sjoerg }
12587330f729Sjoerg
TraverseNestedNameSpecifier(NestedNameSpecifier * NNS)12597330f729Sjoerg bool MatchASTVisitor::TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {
12607330f729Sjoerg match(*NNS);
12617330f729Sjoerg return RecursiveASTVisitor<MatchASTVisitor>::TraverseNestedNameSpecifier(NNS);
12627330f729Sjoerg }
12637330f729Sjoerg
TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS)12647330f729Sjoerg bool MatchASTVisitor::TraverseNestedNameSpecifierLoc(
12657330f729Sjoerg NestedNameSpecifierLoc NNS) {
12667330f729Sjoerg if (!NNS)
12677330f729Sjoerg return true;
12687330f729Sjoerg
12697330f729Sjoerg match(NNS);
12707330f729Sjoerg
12717330f729Sjoerg // We only match the nested name specifier here (as opposed to traversing it)
12727330f729Sjoerg // because the traversal is already done in the parallel "Loc"-hierarchy.
12737330f729Sjoerg if (NNS.hasQualifier())
12747330f729Sjoerg match(*NNS.getNestedNameSpecifier());
12757330f729Sjoerg return
12767330f729Sjoerg RecursiveASTVisitor<MatchASTVisitor>::TraverseNestedNameSpecifierLoc(NNS);
12777330f729Sjoerg }
12787330f729Sjoerg
TraverseConstructorInitializer(CXXCtorInitializer * CtorInit)12797330f729Sjoerg bool MatchASTVisitor::TraverseConstructorInitializer(
12807330f729Sjoerg CXXCtorInitializer *CtorInit) {
12817330f729Sjoerg if (!CtorInit)
12827330f729Sjoerg return true;
12837330f729Sjoerg
1284*e038c9c4Sjoerg bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
1285*e038c9c4Sjoerg TraversingASTChildrenNotSpelledInSource;
1286*e038c9c4Sjoerg
1287*e038c9c4Sjoerg if (!CtorInit->isWritten())
1288*e038c9c4Sjoerg ScopedTraversal = true;
1289*e038c9c4Sjoerg
1290*e038c9c4Sjoerg ASTNodeNotSpelledInSourceScope RAII1(this, ScopedTraversal);
1291*e038c9c4Sjoerg
12927330f729Sjoerg match(*CtorInit);
12937330f729Sjoerg
12947330f729Sjoerg return RecursiveASTVisitor<MatchASTVisitor>::TraverseConstructorInitializer(
12957330f729Sjoerg CtorInit);
12967330f729Sjoerg }
12977330f729Sjoerg
TraverseTemplateArgumentLoc(TemplateArgumentLoc Loc)1298*e038c9c4Sjoerg bool MatchASTVisitor::TraverseTemplateArgumentLoc(TemplateArgumentLoc Loc) {
1299*e038c9c4Sjoerg match(Loc);
1300*e038c9c4Sjoerg return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateArgumentLoc(Loc);
1301*e038c9c4Sjoerg }
1302*e038c9c4Sjoerg
13037330f729Sjoerg class MatchASTConsumer : public ASTConsumer {
13047330f729Sjoerg public:
MatchASTConsumer(MatchFinder * Finder,MatchFinder::ParsingDoneTestCallback * ParsingDone)13057330f729Sjoerg MatchASTConsumer(MatchFinder *Finder,
13067330f729Sjoerg MatchFinder::ParsingDoneTestCallback *ParsingDone)
13077330f729Sjoerg : Finder(Finder), ParsingDone(ParsingDone) {}
13087330f729Sjoerg
13097330f729Sjoerg private:
HandleTranslationUnit(ASTContext & Context)13107330f729Sjoerg void HandleTranslationUnit(ASTContext &Context) override {
13117330f729Sjoerg if (ParsingDone != nullptr) {
13127330f729Sjoerg ParsingDone->run();
13137330f729Sjoerg }
13147330f729Sjoerg Finder->matchAST(Context);
13157330f729Sjoerg }
13167330f729Sjoerg
13177330f729Sjoerg MatchFinder *Finder;
13187330f729Sjoerg MatchFinder::ParsingDoneTestCallback *ParsingDone;
13197330f729Sjoerg };
13207330f729Sjoerg
13217330f729Sjoerg } // end namespace
13227330f729Sjoerg } // end namespace internal
13237330f729Sjoerg
MatchResult(const BoundNodes & Nodes,ASTContext * Context)13247330f729Sjoerg MatchFinder::MatchResult::MatchResult(const BoundNodes &Nodes,
13257330f729Sjoerg ASTContext *Context)
13267330f729Sjoerg : Nodes(Nodes), Context(Context),
13277330f729Sjoerg SourceManager(&Context->getSourceManager()) {}
13287330f729Sjoerg
~MatchCallback()13297330f729Sjoerg MatchFinder::MatchCallback::~MatchCallback() {}
~ParsingDoneTestCallback()13307330f729Sjoerg MatchFinder::ParsingDoneTestCallback::~ParsingDoneTestCallback() {}
13317330f729Sjoerg
MatchFinder(MatchFinderOptions Options)13327330f729Sjoerg MatchFinder::MatchFinder(MatchFinderOptions Options)
13337330f729Sjoerg : Options(std::move(Options)), ParsingDone(nullptr) {}
13347330f729Sjoerg
~MatchFinder()13357330f729Sjoerg MatchFinder::~MatchFinder() {}
13367330f729Sjoerg
addMatcher(const DeclarationMatcher & NodeMatch,MatchCallback * Action)13377330f729Sjoerg void MatchFinder::addMatcher(const DeclarationMatcher &NodeMatch,
13387330f729Sjoerg MatchCallback *Action) {
1339*e038c9c4Sjoerg llvm::Optional<TraversalKind> TK;
1340*e038c9c4Sjoerg if (Action)
1341*e038c9c4Sjoerg TK = Action->getCheckTraversalKind();
1342*e038c9c4Sjoerg if (TK)
1343*e038c9c4Sjoerg Matchers.DeclOrStmt.emplace_back(traverse(*TK, NodeMatch), Action);
1344*e038c9c4Sjoerg else
13457330f729Sjoerg Matchers.DeclOrStmt.emplace_back(NodeMatch, Action);
13467330f729Sjoerg Matchers.AllCallbacks.insert(Action);
13477330f729Sjoerg }
13487330f729Sjoerg
addMatcher(const TypeMatcher & NodeMatch,MatchCallback * Action)13497330f729Sjoerg void MatchFinder::addMatcher(const TypeMatcher &NodeMatch,
13507330f729Sjoerg MatchCallback *Action) {
13517330f729Sjoerg Matchers.Type.emplace_back(NodeMatch, Action);
13527330f729Sjoerg Matchers.AllCallbacks.insert(Action);
13537330f729Sjoerg }
13547330f729Sjoerg
addMatcher(const StatementMatcher & NodeMatch,MatchCallback * Action)13557330f729Sjoerg void MatchFinder::addMatcher(const StatementMatcher &NodeMatch,
13567330f729Sjoerg MatchCallback *Action) {
1357*e038c9c4Sjoerg llvm::Optional<TraversalKind> TK;
1358*e038c9c4Sjoerg if (Action)
1359*e038c9c4Sjoerg TK = Action->getCheckTraversalKind();
1360*e038c9c4Sjoerg if (TK)
1361*e038c9c4Sjoerg Matchers.DeclOrStmt.emplace_back(traverse(*TK, NodeMatch), Action);
1362*e038c9c4Sjoerg else
13637330f729Sjoerg Matchers.DeclOrStmt.emplace_back(NodeMatch, Action);
13647330f729Sjoerg Matchers.AllCallbacks.insert(Action);
13657330f729Sjoerg }
13667330f729Sjoerg
addMatcher(const NestedNameSpecifierMatcher & NodeMatch,MatchCallback * Action)13677330f729Sjoerg void MatchFinder::addMatcher(const NestedNameSpecifierMatcher &NodeMatch,
13687330f729Sjoerg MatchCallback *Action) {
13697330f729Sjoerg Matchers.NestedNameSpecifier.emplace_back(NodeMatch, Action);
13707330f729Sjoerg Matchers.AllCallbacks.insert(Action);
13717330f729Sjoerg }
13727330f729Sjoerg
addMatcher(const NestedNameSpecifierLocMatcher & NodeMatch,MatchCallback * Action)13737330f729Sjoerg void MatchFinder::addMatcher(const NestedNameSpecifierLocMatcher &NodeMatch,
13747330f729Sjoerg MatchCallback *Action) {
13757330f729Sjoerg Matchers.NestedNameSpecifierLoc.emplace_back(NodeMatch, Action);
13767330f729Sjoerg Matchers.AllCallbacks.insert(Action);
13777330f729Sjoerg }
13787330f729Sjoerg
addMatcher(const TypeLocMatcher & NodeMatch,MatchCallback * Action)13797330f729Sjoerg void MatchFinder::addMatcher(const TypeLocMatcher &NodeMatch,
13807330f729Sjoerg MatchCallback *Action) {
13817330f729Sjoerg Matchers.TypeLoc.emplace_back(NodeMatch, Action);
13827330f729Sjoerg Matchers.AllCallbacks.insert(Action);
13837330f729Sjoerg }
13847330f729Sjoerg
addMatcher(const CXXCtorInitializerMatcher & NodeMatch,MatchCallback * Action)13857330f729Sjoerg void MatchFinder::addMatcher(const CXXCtorInitializerMatcher &NodeMatch,
13867330f729Sjoerg MatchCallback *Action) {
13877330f729Sjoerg Matchers.CtorInit.emplace_back(NodeMatch, Action);
13887330f729Sjoerg Matchers.AllCallbacks.insert(Action);
13897330f729Sjoerg }
13907330f729Sjoerg
addMatcher(const TemplateArgumentLocMatcher & NodeMatch,MatchCallback * Action)1391*e038c9c4Sjoerg void MatchFinder::addMatcher(const TemplateArgumentLocMatcher &NodeMatch,
1392*e038c9c4Sjoerg MatchCallback *Action) {
1393*e038c9c4Sjoerg Matchers.TemplateArgumentLoc.emplace_back(NodeMatch, Action);
1394*e038c9c4Sjoerg Matchers.AllCallbacks.insert(Action);
1395*e038c9c4Sjoerg }
1396*e038c9c4Sjoerg
addDynamicMatcher(const internal::DynTypedMatcher & NodeMatch,MatchCallback * Action)13977330f729Sjoerg bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
13987330f729Sjoerg MatchCallback *Action) {
13997330f729Sjoerg if (NodeMatch.canConvertTo<Decl>()) {
14007330f729Sjoerg addMatcher(NodeMatch.convertTo<Decl>(), Action);
14017330f729Sjoerg return true;
14027330f729Sjoerg } else if (NodeMatch.canConvertTo<QualType>()) {
14037330f729Sjoerg addMatcher(NodeMatch.convertTo<QualType>(), Action);
14047330f729Sjoerg return true;
14057330f729Sjoerg } else if (NodeMatch.canConvertTo<Stmt>()) {
14067330f729Sjoerg addMatcher(NodeMatch.convertTo<Stmt>(), Action);
14077330f729Sjoerg return true;
14087330f729Sjoerg } else if (NodeMatch.canConvertTo<NestedNameSpecifier>()) {
14097330f729Sjoerg addMatcher(NodeMatch.convertTo<NestedNameSpecifier>(), Action);
14107330f729Sjoerg return true;
14117330f729Sjoerg } else if (NodeMatch.canConvertTo<NestedNameSpecifierLoc>()) {
14127330f729Sjoerg addMatcher(NodeMatch.convertTo<NestedNameSpecifierLoc>(), Action);
14137330f729Sjoerg return true;
14147330f729Sjoerg } else if (NodeMatch.canConvertTo<TypeLoc>()) {
14157330f729Sjoerg addMatcher(NodeMatch.convertTo<TypeLoc>(), Action);
14167330f729Sjoerg return true;
14177330f729Sjoerg } else if (NodeMatch.canConvertTo<CXXCtorInitializer>()) {
14187330f729Sjoerg addMatcher(NodeMatch.convertTo<CXXCtorInitializer>(), Action);
14197330f729Sjoerg return true;
1420*e038c9c4Sjoerg } else if (NodeMatch.canConvertTo<TemplateArgumentLoc>()) {
1421*e038c9c4Sjoerg addMatcher(NodeMatch.convertTo<TemplateArgumentLoc>(), Action);
1422*e038c9c4Sjoerg return true;
14237330f729Sjoerg }
14247330f729Sjoerg return false;
14257330f729Sjoerg }
14267330f729Sjoerg
newASTConsumer()14277330f729Sjoerg std::unique_ptr<ASTConsumer> MatchFinder::newASTConsumer() {
14287330f729Sjoerg return std::make_unique<internal::MatchASTConsumer>(this, ParsingDone);
14297330f729Sjoerg }
14307330f729Sjoerg
match(const clang::DynTypedNode & Node,ASTContext & Context)1431*e038c9c4Sjoerg void MatchFinder::match(const clang::DynTypedNode &Node, ASTContext &Context) {
14327330f729Sjoerg internal::MatchASTVisitor Visitor(&Matchers, Options);
14337330f729Sjoerg Visitor.set_active_ast_context(&Context);
14347330f729Sjoerg Visitor.match(Node);
14357330f729Sjoerg }
14367330f729Sjoerg
matchAST(ASTContext & Context)14377330f729Sjoerg void MatchFinder::matchAST(ASTContext &Context) {
14387330f729Sjoerg internal::MatchASTVisitor Visitor(&Matchers, Options);
14397330f729Sjoerg Visitor.set_active_ast_context(&Context);
14407330f729Sjoerg Visitor.onStartOfTranslationUnit();
14417330f729Sjoerg Visitor.TraverseAST(Context);
14427330f729Sjoerg Visitor.onEndOfTranslationUnit();
14437330f729Sjoerg }
14447330f729Sjoerg
registerTestCallbackAfterParsing(MatchFinder::ParsingDoneTestCallback * NewParsingDone)14457330f729Sjoerg void MatchFinder::registerTestCallbackAfterParsing(
14467330f729Sjoerg MatchFinder::ParsingDoneTestCallback *NewParsingDone) {
14477330f729Sjoerg ParsingDone = NewParsingDone;
14487330f729Sjoerg }
14497330f729Sjoerg
getID() const14507330f729Sjoerg StringRef MatchFinder::MatchCallback::getID() const { return "<unknown>"; }
14517330f729Sjoerg
1452*e038c9c4Sjoerg llvm::Optional<TraversalKind>
getCheckTraversalKind() const1453*e038c9c4Sjoerg MatchFinder::MatchCallback::getCheckTraversalKind() const {
1454*e038c9c4Sjoerg return llvm::None;
1455*e038c9c4Sjoerg }
1456*e038c9c4Sjoerg
14577330f729Sjoerg } // end namespace ast_matchers
14587330f729Sjoerg } // end namespace clang
1459