Clang Project

clang_source_code/include/clang/ASTMatchers/ASTMatchFinder.h
1//===--- ASTMatchFinder.h - Structural query framework ----------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9//  Provides a way to construct an ASTConsumer that runs given matchers
10//  over the AST and invokes a given callback on every match.
11//
12//  The general idea is to construct a matcher expression that describes a
13//  subtree match on the AST. Next, a callback that is executed every time the
14//  expression matches is registered, and the matcher is run over the AST of
15//  some code. Matched subexpressions can be bound to string IDs and easily
16//  be accessed from the registered callback. The callback can than use the
17//  AST nodes that the subexpressions matched on to output information about
18//  the match or construct changes that can be applied to the code.
19//
20//  Example:
21//  class HandleMatch : public MatchFinder::MatchCallback {
22//  public:
23//    virtual void Run(const MatchFinder::MatchResult &Result) {
24//      const CXXRecordDecl *Class =
25//          Result.Nodes.GetDeclAs<CXXRecordDecl>("id");
26//      ...
27//    }
28//  };
29//
30//  int main(int argc, char **argv) {
31//    ClangTool Tool(argc, argv);
32//    MatchFinder finder;
33//    finder.AddMatcher(Id("id", record(hasName("::a_namespace::AClass"))),
34//                      new HandleMatch);
35//    return Tool.Run(newFrontendActionFactory(&finder));
36//  }
37//
38//===----------------------------------------------------------------------===//
39
40#ifndef LLVM_CLANG_ASTMATCHERS_ASTMATCHFINDER_H
41#define LLVM_CLANG_ASTMATCHERS_ASTMATCHFINDER_H
42
43#include "clang/ASTMatchers/ASTMatchers.h"
44#include "llvm/ADT/SmallPtrSet.h"
45#include "llvm/ADT/StringMap.h"
46#include "llvm/Support/Timer.h"
47
48namespace clang {
49
50namespace ast_matchers {
51
52/// A class to allow finding matches over the Clang AST.
53///
54/// After creation, you can add multiple matchers to the MatchFinder via
55/// calls to addMatcher(...).
56///
57/// Once all matchers are added, newASTConsumer() returns an ASTConsumer
58/// that will trigger the callbacks specified via addMatcher(...) when a match
59/// is found.
60///
61/// The order of matches is guaranteed to be equivalent to doing a pre-order
62/// traversal on the AST, and applying the matchers in the order in which they
63/// were added to the MatchFinder.
64///
65/// See ASTMatchers.h for more information about how to create matchers.
66///
67/// Not intended to be subclassed.
68class MatchFinder {
69public:
70  /// Contains all information for a given match.
71  ///
72  /// Every time a match is found, the MatchFinder will invoke the registered
73  /// MatchCallback with a MatchResult containing information about the match.
74  struct MatchResult {
75    MatchResult(const BoundNodes &Nodesclang::ASTContext *Context);
76
77    /// Contains the nodes bound on the current match.
78    ///
79    /// This allows user code to easily extract matched AST nodes.
80    const BoundNodes Nodes;
81
82    /// Utilities for interpreting the matched AST structures.
83    /// @{
84    clang::ASTContext * const Context;
85    clang::SourceManager * const SourceManager;
86    /// @}
87  };
88
89  /// Called when the Match registered for it was successfully found
90  /// in the AST.
91  class MatchCallback {
92  public:
93    virtual ~MatchCallback();
94
95    /// Called on every match by the \c MatchFinder.
96    virtual void run(const MatchResult &Result) = 0;
97
98    /// Called at the start of each translation unit.
99    ///
100    /// Optionally override to do per translation unit tasks.
101    virtual void onStartOfTranslationUnit() {}
102
103    /// Called at the end of each translation unit.
104    ///
105    /// Optionally override to do per translation unit tasks.
106    virtual void onEndOfTranslationUnit() {}
107
108    /// An id used to group the matchers.
109    ///
110    /// This id is used, for example, for the profiling output.
111    /// It defaults to "<unknown>".
112    virtual StringRef getID() const;
113  };
114
115  /// Called when parsing is finished. Intended for testing only.
116  class ParsingDoneTestCallback {
117  public:
118    virtual ~ParsingDoneTestCallback();
119    virtual void run() = 0;
120  };
121
122  struct MatchFinderOptions {
123    struct Profiling {
124      Profiling(llvm::StringMap<llvm::TimeRecord> &Records)
125          : Records(Records) {}
126
127      /// Per bucket timing information.
128      llvm::StringMap<llvm::TimeRecord> &Records;
129    };
130
131    /// Enables per-check timers.
132    ///
133    /// It prints a report after match.
134    llvm::Optional<ProfilingCheckProfiling;
135  };
136
137  MatchFinder(MatchFinderOptions Options = MatchFinderOptions());
138  ~MatchFinder();
139
140  /// Adds a matcher to execute when running over the AST.
141  ///
142  /// Calls 'Action' with the BoundNodes on every match.
143  /// Adding more than one 'NodeMatch' allows finding different matches in a
144  /// single pass over the AST.
145  ///
146  /// Does not take ownership of 'Action'.
147  /// @{
148  void addMatcher(const DeclarationMatcher &NodeMatch,
149                  MatchCallback *Action);
150  void addMatcher(const TypeMatcher &NodeMatch,
151                  MatchCallback *Action);
152  void addMatcher(const StatementMatcher &NodeMatch,
153                  MatchCallback *Action);
154  void addMatcher(const NestedNameSpecifierMatcher &NodeMatch,
155                  MatchCallback *Action);
156  void addMatcher(const NestedNameSpecifierLocMatcher &NodeMatch,
157                  MatchCallback *Action);
158  void addMatcher(const TypeLocMatcher &NodeMatch,
159                  MatchCallback *Action);
160  void addMatcher(const CXXCtorInitializerMatcher &NodeMatch,
161                  MatchCallback *Action);
162  /// @}
163
164  /// Adds a matcher to execute when running over the AST.
165  ///
166  /// This is similar to \c addMatcher(), but it uses the dynamic interface. It
167  /// is more flexible, but the lost type information enables a caller to pass
168  /// a matcher that cannot match anything.
169  ///
170  /// \returns \c true if the matcher is a valid top-level matcher, \c false
171  ///   otherwise.
172  bool addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
173                         MatchCallback *Action);
174
175  /// Creates a clang ASTConsumer that finds all matches.
176  std::unique_ptr<clang::ASTConsumernewASTConsumer();
177
178  /// Calls the registered callbacks on all matches on the given \p Node.
179  ///
180  /// Note that there can be multiple matches on a single node, for
181  /// example when using decl(forEachDescendant(stmt())).
182  ///
183  /// @{
184  template <typename T> void match(const T &NodeASTContext &Context) {
185    match(clang::ast_type_traits::DynTypedNode::create(Node), Context);
186  }
187  void match(const clang::ast_type_traits::DynTypedNode &Node,
188             ASTContext &Context);
189  /// @}
190
191  /// Finds all matches in the given AST.
192  void matchAST(ASTContext &Context);
193
194  /// Registers a callback to notify the end of parsing.
195  ///
196  /// The provided closure is called after parsing is done, before the AST is
197  /// traversed. Useful for benchmarking.
198  /// Each call to FindAll(...) will call the closure once.
199  void registerTestCallbackAfterParsing(ParsingDoneTestCallback *ParsingDone);
200
201  /// For each \c Matcher<> a \c MatchCallback that will be called
202  /// when it matches.
203  struct MatchersByType {
204    std::vector<std::pair<internal::DynTypedMatcherMatchCallback *>>
205        DeclOrStmt;
206    std::vector<std::pair<TypeMatcherMatchCallback *>> Type;
207    std::vector<std::pair<NestedNameSpecifierMatcherMatchCallback *>>
208        NestedNameSpecifier;
209    std::vector<std::pair<NestedNameSpecifierLocMatcherMatchCallback *>>
210        NestedNameSpecifierLoc;
211    std::vector<std::pair<TypeLocMatcherMatchCallback *>> TypeLoc;
212    std::vector<std::pair<CXXCtorInitializerMatcherMatchCallback *>> CtorInit;
213    /// All the callbacks in one container to simplify iteration.
214    llvm::SmallPtrSet<MatchCallback *, 16AllCallbacks;
215  };
216
217private:
218  MatchersByType Matchers;
219
220  MatchFinderOptions Options;
221
222  /// Called when parsing is done.
223  ParsingDoneTestCallback *ParsingDone;
224};
225
226/// Returns the results of matching \p Matcher on \p Node.
227///
228/// Collects the \c BoundNodes of all callback invocations when matching
229/// \p Matcher on \p Node and returns the collected results.
230///
231/// Multiple results occur when using matchers like \c forEachDescendant,
232/// which generate a result for each sub-match.
233///
234/// If you want to find all matches on the sub-tree rooted at \c Node (rather
235/// than only the matches on \c Node itself), surround the \c Matcher with a
236/// \c findAll().
237///
238/// \see selectFirst
239/// @{
240template <typename MatcherT, typename NodeT>
241SmallVector<BoundNodes1>
242match(MatcherT Matcherconst NodeT &NodeASTContext &Context);
243
244template <typename MatcherT>
245SmallVector<BoundNodes1>
246match(MatcherT Matcherconst ast_type_traits::DynTypedNode &Node,
247      ASTContext &Context);
248/// @}
249
250/// Returns the results of matching \p Matcher on the translation unit of
251/// \p Context and collects the \c BoundNodes of all callback invocations.
252template <typename MatcherT>
253SmallVector<BoundNodes1match(MatcherT MatcherASTContext &Context);
254
255/// Returns the first result of type \c NodeT bound to \p BoundTo.
256///
257/// Returns \c NULL if there is no match, or if the matching node cannot be
258/// casted to \c NodeT.
259///
260/// This is useful in combanation with \c match():
261/// \code
262///   const Decl *D = selectFirst<Decl>("id", match(Matcher.bind("id"),
263///                                                 Node, Context));
264/// \endcode
265template <typename NodeT>
266const NodeT *
267selectFirst(StringRef BoundToconst SmallVectorImpl<BoundNodes> &Results) {
268  for (const BoundNodes &N : Results) {
269    if (const NodeT *Node = N.getNodeAs<NodeT>(BoundTo))
270      return Node;
271  }
272  return nullptr;
273}
274
275namespace internal {
276class CollectMatchesCallback : public MatchFinder::MatchCallback {
277public:
278  void run(const MatchFinder::MatchResult &Result) override {
279    Nodes.push_back(Result.Nodes);
280  }
281  SmallVector<BoundNodes1Nodes;
282};
283}
284
285template <typename MatcherT>
286SmallVector<BoundNodes1>
287match(MatcherT Matcherconst ast_type_traits::DynTypedNode &Node,
288      ASTContext &Context) {
289  internal::CollectMatchesCallback Callback;
290  MatchFinder Finder;
291  Finder.addMatcher(Matcher, &Callback);
292  Finder.match(NodeContext);
293  return std::move(Callback.Nodes);
294}
295
296template <typename MatcherT, typename NodeT>
297SmallVector<BoundNodes1>
298match(MatcherT Matcherconst NodeT &NodeASTContext &Context) {
299  return match(Matcherast_type_traits::DynTypedNode::create(Node), Context);
300}
301
302template <typename MatcherT>
303SmallVector<BoundNodes1>
304match(MatcherT MatcherASTContext &Context) {
305  internal::CollectMatchesCallback Callback;
306  MatchFinder Finder;
307  Finder.addMatcher(Matcher, &Callback);
308  Finder.matchAST(Context);
309  return std::move(Callback.Nodes);
310}
311
312// end namespace ast_matchers
313// end namespace clang
314
315#endif
316
clang::ast_matchers::MatchFinder::MatchResult
clang::ast_matchers::MatchFinder::MatchResult::Nodes
clang::ast_matchers::MatchFinder::MatchResult::Context
clang::ast_matchers::MatchFinder::MatchResult::SourceManager
clang::ast_matchers::MatchFinder::MatchCallback
clang::ast_matchers::MatchFinder::MatchCallback::run
clang::ast_matchers::MatchFinder::MatchCallback::onStartOfTranslationUnit
clang::ast_matchers::MatchFinder::MatchCallback::onEndOfTranslationUnit
clang::ast_matchers::MatchFinder::MatchCallback::getID
clang::ast_matchers::MatchFinder::ParsingDoneTestCallback
clang::ast_matchers::MatchFinder::ParsingDoneTestCallback::run
clang::ast_matchers::MatchFinder::MatchFinderOptions
clang::ast_matchers::MatchFinder::MatchFinderOptions::Profiling
clang::ast_matchers::MatchFinder::MatchFinderOptions::Profiling::Records
clang::ast_matchers::MatchFinder::MatchFinderOptions::CheckProfiling
clang::ast_matchers::MatchFinder::addMatcher
clang::ast_matchers::MatchFinder::addMatcher
clang::ast_matchers::MatchFinder::addMatcher
clang::ast_matchers::MatchFinder::addMatcher
clang::ast_matchers::MatchFinder::addMatcher
clang::ast_matchers::MatchFinder::addMatcher
clang::ast_matchers::MatchFinder::addMatcher
clang::ast_matchers::MatchFinder::addDynamicMatcher
clang::ast_matchers::MatchFinder::newASTConsumer
clang::ast_matchers::MatchFinder::match
clang::ast_matchers::MatchFinder::match
clang::ast_matchers::MatchFinder::matchAST
clang::ast_matchers::MatchFinder::registerTestCallbackAfterParsing
clang::ast_matchers::MatchFinder::MatchersByType
clang::ast_matchers::MatchFinder::MatchersByType::DeclOrStmt
clang::ast_matchers::MatchFinder::MatchersByType::Type
clang::ast_matchers::MatchFinder::MatchersByType::NestedNameSpecifier
clang::ast_matchers::MatchFinder::MatchersByType::NestedNameSpecifierLoc
clang::ast_matchers::MatchFinder::MatchersByType::TypeLoc
clang::ast_matchers::MatchFinder::MatchersByType::CtorInit
clang::ast_matchers::MatchFinder::MatchersByType::AllCallbacks
clang::ast_matchers::MatchFinder::Matchers
clang::ast_matchers::MatchFinder::Options
clang::ast_matchers::MatchFinder::ParsingDone
clang::ast_matchers::internal::CollectMatchesCallback::run
clang::ast_matchers::internal::CollectMatchesCallback::Nodes