ASTMatchFinder.h revision f7f295f321fd434e1e542844a71f538a56f2f8fb
1//===--- ASTMatchFinder.h - Structural query framework ----------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10//  Provides a way to construct an ASTConsumer that runs given matchers
11//  over the AST and invokes a given callback on every match.
12//
13//  The general idea is to construct a matcher expression that describes a
14//  subtree match on the AST. Next, a callback that is executed every time the
15//  expression matches is registered, and the matcher is run over the AST of
16//  some code. Matched subexpressions can be bound to string IDs and easily
17//  be accessed from the registered callback. The callback can than use the
18//  AST nodes that the subexpressions matched on to output information about
19//  the match or construct changes that can be applied to the code.
20//
21//  Example:
22//  class HandleMatch : public MatchFinder::MatchCallback {
23//  public:
24//    virtual void Run(const MatchFinder::MatchResult &Result) {
25//      const CXXRecordDecl *Class =
26//          Result.Nodes.GetDeclAs<CXXRecordDecl>("id");
27//      ...
28//    }
29//  };
30//
31//  int main(int argc, char **argv) {
32//    ClangTool Tool(argc, argv);
33//    MatchFinder finder;
34//    finder.AddMatcher(Id("id", record(hasName("::a_namespace::AClass"))),
35//                      new HandleMatch);
36//    return Tool.Run(newFrontendActionFactory(&finder));
37//  }
38//
39//===----------------------------------------------------------------------===//
40
41#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCH_FINDER_H
42#define LLVM_CLANG_AST_MATCHERS_AST_MATCH_FINDER_H
43
44#include "clang/ASTMatchers/ASTMatchers.h"
45
46namespace clang {
47
48namespace ast_matchers {
49
50/// \brief A class to allow finding matches over the Clang AST.
51///
52/// After creation, you can add multiple matchers to the MatchFinder via
53/// calls to addMatcher(...).
54///
55/// Once all matchers are added, newASTConsumer() returns an ASTConsumer
56/// that will trigger the callbacks specified via addMatcher(...) when a match
57/// is found.
58///
59/// The order of matches is guaranteed to be equivalent to doing a pre-order
60/// traversal on the AST, and applying the matchers in the order in which they
61/// were added to the MatchFinder.
62///
63/// See ASTMatchers.h for more information about how to create matchers.
64///
65/// Not intended to be subclassed.
66class MatchFinder {
67public:
68  /// \brief Contains all information for a given match.
69  ///
70  /// Every time a match is found, the MatchFinder will invoke the registered
71  /// MatchCallback with a MatchResult containing information about the match.
72  struct MatchResult {
73    MatchResult(const BoundNodes &Nodes, clang::ASTContext *Context);
74
75    /// \brief Contains the nodes bound on the current match.
76    ///
77    /// This allows user code to easily extract matched AST nodes.
78    const BoundNodes Nodes;
79
80    /// \brief Utilities for interpreting the matched AST structures.
81    /// @{
82    clang::ASTContext * const Context;
83    clang::SourceManager * const SourceManager;
84    /// @}
85  };
86
87  /// \brief Called when the Match registered for it was successfully found
88  /// in the AST.
89  class MatchCallback {
90  public:
91    virtual ~MatchCallback();
92
93    /// \brief Called on every match by the \c MatchFinder.
94    virtual void run(const MatchResult &Result) = 0;
95
96    /// \brief Called at the start of each translation unit.
97    ///
98    /// Optionally override to do per translation unit tasks.
99    virtual void onStartOfTranslationUnit() {}
100  };
101
102  /// \brief Called when parsing is finished. Intended for testing only.
103  class ParsingDoneTestCallback {
104  public:
105    virtual ~ParsingDoneTestCallback();
106    virtual void run() = 0;
107  };
108
109  MatchFinder();
110  ~MatchFinder();
111
112  /// \brief Adds a matcher to execute when running over the AST.
113  ///
114  /// Calls 'Action' with the BoundNodes on every match.
115  /// Adding more than one 'NodeMatch' allows finding different matches in a
116  /// single pass over the AST.
117  ///
118  /// Does not take ownership of 'Action'.
119  /// @{
120  void addMatcher(const DeclarationMatcher &NodeMatch,
121                  MatchCallback *Action);
122  void addMatcher(const TypeMatcher &NodeMatch,
123                  MatchCallback *Action);
124  void addMatcher(const StatementMatcher &NodeMatch,
125                  MatchCallback *Action);
126  void addMatcher(const NestedNameSpecifierMatcher &NodeMatch,
127                  MatchCallback *Action);
128  void addMatcher(const NestedNameSpecifierLocMatcher &NodeMatch,
129                  MatchCallback *Action);
130  void addMatcher(const TypeLocMatcher &NodeMatch,
131                  MatchCallback *Action);
132  /// @}
133
134  /// \brief Adds a matcher to execute when running over the AST.
135  ///
136  /// This is similar to \c addMatcher(), but it uses the dynamic interface. It
137  /// is more flexible, but the lost type information enables a caller to pass
138  /// a matcher that cannot match anything.
139  ///
140  /// \returns \c true if the matcher is a valid top-level matcher, \c false
141  ///   otherwise.
142  bool addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
143                         MatchCallback *Action);
144
145  /// \brief Creates a clang ASTConsumer that finds all matches.
146  clang::ASTConsumer *newASTConsumer();
147
148  /// \brief Calls the registered callbacks on all matches on the given \p Node.
149  ///
150  /// Note that there can be multiple matches on a single node, for
151  /// example when using decl(forEachDescendant(stmt())).
152  ///
153  /// @{
154  template <typename T> void match(const T &Node, ASTContext &Context) {
155    match(clang::ast_type_traits::DynTypedNode::create(Node), Context);
156  }
157  void match(const clang::ast_type_traits::DynTypedNode &Node,
158             ASTContext &Context);
159  /// @}
160
161  /// \brief Registers a callback to notify the end of parsing.
162  ///
163  /// The provided closure is called after parsing is done, before the AST is
164  /// traversed. Useful for benchmarking.
165  /// Each call to FindAll(...) will call the closure once.
166  void registerTestCallbackAfterParsing(ParsingDoneTestCallback *ParsingDone);
167
168private:
169  /// \brief For each \c DynTypedMatcher a \c MatchCallback that will be called
170  /// when it matches.
171  std::vector<std::pair<const internal::DynTypedMatcher*, MatchCallback*> >
172    MatcherCallbackPairs;
173
174  /// \brief Called when parsing is done.
175  ParsingDoneTestCallback *ParsingDone;
176};
177
178/// \brief Returns the results of matching \p Matcher on \p Node.
179///
180/// Collects the \c BoundNodes of all callback invocations when matching
181/// \p Matcher on \p Node and returns the collected results.
182///
183/// Multiple results occur when using matchers like \c forEachDescendant,
184/// which generate a result for each sub-match.
185///
186/// \see selectFirst
187/// @{
188template <typename MatcherT, typename NodeT>
189SmallVector<BoundNodes, 1>
190match(MatcherT Matcher, const NodeT &Node, ASTContext &Context);
191
192template <typename MatcherT>
193SmallVector<BoundNodes, 1>
194match(MatcherT Matcher, const ast_type_traits::DynTypedNode &Node,
195      ASTContext &Context);
196/// @}
197
198/// \brief Returns the first result of type \c NodeT bound to \p BoundTo.
199///
200/// Returns \c NULL if there is no match, or if the matching node cannot be
201/// casted to \c NodeT.
202///
203/// This is useful in combanation with \c match():
204/// \code
205///   Decl *D = selectFirst<Decl>("id", match(Matcher.bind("id"),
206///                                           Node, Context));
207/// \endcode
208template <typename NodeT>
209NodeT *
210selectFirst(StringRef BoundTo, const SmallVectorImpl<BoundNodes> &Results) {
211  for (SmallVectorImpl<BoundNodes>::const_iterator I = Results.begin(),
212                                                   E = Results.end();
213       I != E; ++I) {
214    if (NodeT *Node = I->getNodeAs<NodeT>(BoundTo))
215      return Node;
216  }
217  return NULL;
218}
219
220namespace internal {
221class CollectMatchesCallback : public MatchFinder::MatchCallback {
222public:
223  virtual void run(const MatchFinder::MatchResult &Result) {
224    Nodes.push_back(Result.Nodes);
225  }
226  SmallVector<BoundNodes, 1> Nodes;
227};
228}
229
230template <typename MatcherT>
231SmallVector<BoundNodes, 1>
232match(MatcherT Matcher, const ast_type_traits::DynTypedNode &Node,
233      ASTContext &Context) {
234  internal::CollectMatchesCallback Callback;
235  MatchFinder Finder;
236  Finder.addMatcher(Matcher, &Callback);
237  Finder.match(Node, Context);
238  return Callback.Nodes;
239}
240
241template <typename MatcherT, typename NodeT>
242SmallVector<BoundNodes, 1>
243match(MatcherT Matcher, const NodeT &Node, ASTContext &Context) {
244  return match(Matcher, ast_type_traits::DynTypedNode::create(Node), Context);
245}
246
247} // end namespace ast_matchers
248} // end namespace clang
249
250#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCH_FINDER_H
251