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