1 //===--- ASTMatchFinder.h - Structural query framework ----------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // Provides a way to construct an ASTConsumer that runs given matchers
10 // over the AST and invokes a given callback on every match.
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.
21 // class HandleMatch : public MatchFinder::MatchCallback {
23 // virtual void Run(const MatchFinder::MatchResult &Result) {
24 // const CXXRecordDecl *Class =
25 // Result.Nodes.GetDeclAs<CXXRecordDecl>("id");
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"))),
35 // return Tool.Run(newFrontendActionFactory(&finder));
38 //===----------------------------------------------------------------------===//
40 #ifndef LLVM_CLANG_ASTMATCHERS_ASTMATCHFINDER_H
41 #define LLVM_CLANG_ASTMATCHERS_ASTMATCHFINDER_H
43 #include "clang/ASTMatchers/ASTMatchers.h"
44 #include "llvm/ADT/SmallPtrSet.h"
45 #include "llvm/ADT/StringMap.h"
46 #include "llvm/Support/Timer.h"
50 namespace ast_matchers {
52 /// A class to allow finding matches over the Clang AST.
54 /// After creation, you can add multiple matchers to the MatchFinder via
55 /// calls to addMatcher(...).
57 /// Once all matchers are added, newASTConsumer() returns an ASTConsumer
58 /// that will trigger the callbacks specified via addMatcher(...) when a match
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.
65 /// See ASTMatchers.h for more information about how to create matchers.
67 /// Not intended to be subclassed.
70 /// Contains all information for a given match.
72 /// Every time a match is found, the MatchFinder will invoke the registered
73 /// MatchCallback with a MatchResult containing information about the match.
75 MatchResult(const BoundNodes &Nodes, clang::ASTContext *Context);
77 /// Contains the nodes bound on the current match.
79 /// This allows user code to easily extract matched AST nodes.
80 const BoundNodes Nodes;
82 /// Utilities for interpreting the matched AST structures.
84 clang::ASTContext * const Context;
85 clang::SourceManager * const SourceManager;
89 /// Called when the Match registered for it was successfully found
93 virtual ~MatchCallback();
95 /// Called on every match by the \c MatchFinder.
96 virtual void run(const MatchResult &Result) = 0;
98 /// Called at the start of each translation unit.
100 /// Optionally override to do per translation unit tasks.
101 virtual void onStartOfTranslationUnit() {}
103 /// Called at the end of each translation unit.
105 /// Optionally override to do per translation unit tasks.
106 virtual void onEndOfTranslationUnit() {}
108 /// An id used to group the matchers.
110 /// This id is used, for example, for the profiling output.
111 /// It defaults to "<unknown>".
112 virtual StringRef getID() const;
115 /// Called when parsing is finished. Intended for testing only.
116 class ParsingDoneTestCallback {
118 virtual ~ParsingDoneTestCallback();
119 virtual void run() = 0;
122 struct MatchFinderOptions {
124 Profiling(llvm::StringMap<llvm::TimeRecord> &Records)
125 : Records(Records) {}
127 /// Per bucket timing information.
128 llvm::StringMap<llvm::TimeRecord> &Records;
131 /// Enables per-check timers.
133 /// It prints a report after match.
134 llvm::Optional<Profiling> CheckProfiling;
137 MatchFinder(MatchFinderOptions Options = MatchFinderOptions());
140 /// Adds a matcher to execute when running over the AST.
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.
146 /// Does not take ownership of 'Action'.
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);
164 /// Adds a matcher to execute when running over the AST.
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.
170 /// \returns \c true if the matcher is a valid top-level matcher, \c false
172 bool addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
173 MatchCallback *Action);
175 /// Creates a clang ASTConsumer that finds all matches.
176 std::unique_ptr<clang::ASTConsumer> newASTConsumer();
178 /// Calls the registered callbacks on all matches on the given \p Node.
180 /// Note that there can be multiple matches on a single node, for
181 /// example when using decl(forEachDescendant(stmt())).
184 template <typename T> void match(const T &Node, ASTContext &Context) {
185 match(clang::ast_type_traits::DynTypedNode::create(Node), Context);
187 void match(const clang::ast_type_traits::DynTypedNode &Node,
188 ASTContext &Context);
191 /// Finds all matches in the given AST.
192 void matchAST(ASTContext &Context);
194 /// Registers a callback to notify the end of parsing.
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);
201 /// For each \c Matcher<> a \c MatchCallback that will be called
203 struct MatchersByType {
204 std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *>>
206 std::vector<std::pair<TypeMatcher, MatchCallback *>> Type;
207 std::vector<std::pair<NestedNameSpecifierMatcher, MatchCallback *>>
209 std::vector<std::pair<NestedNameSpecifierLocMatcher, MatchCallback *>>
210 NestedNameSpecifierLoc;
211 std::vector<std::pair<TypeLocMatcher, MatchCallback *>> TypeLoc;
212 std::vector<std::pair<CXXCtorInitializerMatcher, MatchCallback *>> CtorInit;
213 /// All the callbacks in one container to simplify iteration.
214 llvm::SmallPtrSet<MatchCallback *, 16> AllCallbacks;
218 MatchersByType Matchers;
220 MatchFinderOptions Options;
222 /// Called when parsing is done.
223 ParsingDoneTestCallback *ParsingDone;
226 /// Returns the results of matching \p Matcher on \p Node.
228 /// Collects the \c BoundNodes of all callback invocations when matching
229 /// \p Matcher on \p Node and returns the collected results.
231 /// Multiple results occur when using matchers like \c forEachDescendant,
232 /// which generate a result for each sub-match.
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
240 template <typename MatcherT, typename NodeT>
241 SmallVector<BoundNodes, 1>
242 match(MatcherT Matcher, const NodeT &Node, ASTContext &Context);
244 template <typename MatcherT>
245 SmallVector<BoundNodes, 1>
246 match(MatcherT Matcher, const ast_type_traits::DynTypedNode &Node,
247 ASTContext &Context);
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.
252 template <typename MatcherT>
253 SmallVector<BoundNodes, 1> match(MatcherT Matcher, ASTContext &Context);
255 /// Returns the first result of type \c NodeT bound to \p BoundTo.
257 /// Returns \c NULL if there is no match, or if the matching node cannot be
258 /// casted to \c NodeT.
260 /// This is useful in combanation with \c match():
262 /// const Decl *D = selectFirst<Decl>("id", match(Matcher.bind("id"),
265 template <typename NodeT>
267 selectFirst(StringRef BoundTo, const SmallVectorImpl<BoundNodes> &Results) {
268 for (const BoundNodes &N : Results) {
269 if (const NodeT *Node = N.getNodeAs<NodeT>(BoundTo))
276 class CollectMatchesCallback : public MatchFinder::MatchCallback {
278 void run(const MatchFinder::MatchResult &Result) override {
279 Nodes.push_back(Result.Nodes);
281 SmallVector<BoundNodes, 1> Nodes;
285 template <typename MatcherT>
286 SmallVector<BoundNodes, 1>
287 match(MatcherT Matcher, const ast_type_traits::DynTypedNode &Node,
288 ASTContext &Context) {
289 internal::CollectMatchesCallback Callback;
291 Finder.addMatcher(Matcher, &Callback);
292 Finder.match(Node, Context);
293 return std::move(Callback.Nodes);
296 template <typename MatcherT, typename NodeT>
297 SmallVector<BoundNodes, 1>
298 match(MatcherT Matcher, const NodeT &Node, ASTContext &Context) {
299 return match(Matcher, ast_type_traits::DynTypedNode::create(Node), Context);
302 template <typename MatcherT>
303 SmallVector<BoundNodes, 1>
304 match(MatcherT Matcher, ASTContext &Context) {
305 internal::CollectMatchesCallback Callback;
307 Finder.addMatcher(Matcher, &Callback);
308 Finder.matchAST(Context);
309 return std::move(Callback.Nodes);
312 } // end namespace ast_matchers
313 } // end namespace clang