1 //===--- ASTMatchFinder.h - Structural query framework ----------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // Provides a way to construct an ASTConsumer that runs given matchers
11 // over the AST and invokes a given callback on every match.
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.
22 // class HandleMatch : public MatchFinder::MatchCallback {
24 // virtual void Run(const MatchFinder::MatchResult &Result) {
25 // const CXXRecordDecl *Class =
26 // Result.Nodes.GetDeclAs<CXXRecordDecl>("id");
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"))),
36 // return Tool.Run(newFrontendActionFactory(&finder));
39 //===----------------------------------------------------------------------===//
41 #ifndef LLVM_CLANG_ASTMATCHERS_ASTMATCHFINDER_H
42 #define LLVM_CLANG_ASTMATCHERS_ASTMATCHFINDER_H
44 #include "clang/ASTMatchers/ASTMatchers.h"
45 #include "llvm/ADT/SmallPtrSet.h"
46 #include "llvm/ADT/StringMap.h"
47 #include "llvm/Support/Timer.h"
51 namespace ast_matchers {
53 /// \brief A class to allow finding matches over the Clang AST.
55 /// After creation, you can add multiple matchers to the MatchFinder via
56 /// calls to addMatcher(...).
58 /// Once all matchers are added, newASTConsumer() returns an ASTConsumer
59 /// that will trigger the callbacks specified via addMatcher(...) when a match
62 /// The order of matches is guaranteed to be equivalent to doing a pre-order
63 /// traversal on the AST, and applying the matchers in the order in which they
64 /// were added to the MatchFinder.
66 /// See ASTMatchers.h for more information about how to create matchers.
68 /// Not intended to be subclassed.
71 /// \brief Contains all information for a given match.
73 /// Every time a match is found, the MatchFinder will invoke the registered
74 /// MatchCallback with a MatchResult containing information about the match.
76 MatchResult(const BoundNodes &Nodes, clang::ASTContext *Context);
78 /// \brief Contains the nodes bound on the current match.
80 /// This allows user code to easily extract matched AST nodes.
81 const BoundNodes Nodes;
83 /// \brief Utilities for interpreting the matched AST structures.
85 clang::ASTContext * const Context;
86 clang::SourceManager * const SourceManager;
90 /// \brief Called when the Match registered for it was successfully found
94 virtual ~MatchCallback();
96 /// \brief Called on every match by the \c MatchFinder.
97 virtual void run(const MatchResult &Result) = 0;
99 /// \brief Called at the start of each translation unit.
101 /// Optionally override to do per translation unit tasks.
102 virtual void onStartOfTranslationUnit() {}
104 /// \brief Called at the end of each translation unit.
106 /// Optionally override to do per translation unit tasks.
107 virtual void onEndOfTranslationUnit() {}
109 /// \brief An id used to group the matchers.
111 /// This id is used, for example, for the profiling output.
112 /// It defaults to "<unknown>".
113 virtual StringRef getID() const;
116 /// \brief Called when parsing is finished. Intended for testing only.
117 class ParsingDoneTestCallback {
119 virtual ~ParsingDoneTestCallback();
120 virtual void run() = 0;
123 struct MatchFinderOptions {
125 Profiling(llvm::StringMap<llvm::TimeRecord> &Records)
126 : Records(Records) {}
128 /// \brief Per bucket timing information.
129 llvm::StringMap<llvm::TimeRecord> &Records;
132 /// \brief Enables per-check timers.
134 /// It prints a report after match.
135 llvm::Optional<Profiling> CheckProfiling;
138 MatchFinder(MatchFinderOptions Options = MatchFinderOptions());
141 /// \brief Adds a matcher to execute when running over the AST.
143 /// Calls 'Action' with the BoundNodes on every match.
144 /// Adding more than one 'NodeMatch' allows finding different matches in a
145 /// single pass over the AST.
147 /// Does not take ownership of 'Action'.
149 void addMatcher(const DeclarationMatcher &NodeMatch,
150 MatchCallback *Action);
151 void addMatcher(const TypeMatcher &NodeMatch,
152 MatchCallback *Action);
153 void addMatcher(const StatementMatcher &NodeMatch,
154 MatchCallback *Action);
155 void addMatcher(const NestedNameSpecifierMatcher &NodeMatch,
156 MatchCallback *Action);
157 void addMatcher(const NestedNameSpecifierLocMatcher &NodeMatch,
158 MatchCallback *Action);
159 void addMatcher(const TypeLocMatcher &NodeMatch,
160 MatchCallback *Action);
163 /// \brief Adds a matcher to execute when running over the AST.
165 /// This is similar to \c addMatcher(), but it uses the dynamic interface. It
166 /// is more flexible, but the lost type information enables a caller to pass
167 /// a matcher that cannot match anything.
169 /// \returns \c true if the matcher is a valid top-level matcher, \c false
171 bool addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
172 MatchCallback *Action);
174 /// \brief Creates a clang ASTConsumer that finds all matches.
175 std::unique_ptr<clang::ASTConsumer> newASTConsumer();
177 /// \brief Calls the registered callbacks on all matches on the given \p Node.
179 /// Note that there can be multiple matches on a single node, for
180 /// example when using decl(forEachDescendant(stmt())).
183 template <typename T> void match(const T &Node, ASTContext &Context) {
184 match(clang::ast_type_traits::DynTypedNode::create(Node), Context);
186 void match(const clang::ast_type_traits::DynTypedNode &Node,
187 ASTContext &Context);
190 /// \brief Finds all matches in the given AST.
191 void matchAST(ASTContext &Context);
193 /// \brief Registers a callback to notify the end of parsing.
195 /// The provided closure is called after parsing is done, before the AST is
196 /// traversed. Useful for benchmarking.
197 /// Each call to FindAll(...) will call the closure once.
198 void registerTestCallbackAfterParsing(ParsingDoneTestCallback *ParsingDone);
200 /// \brief For each \c Matcher<> a \c MatchCallback that will be called
202 struct MatchersByType {
203 std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *>>
205 std::vector<std::pair<TypeMatcher, MatchCallback *>> Type;
206 std::vector<std::pair<NestedNameSpecifierMatcher, MatchCallback *>>
208 std::vector<std::pair<NestedNameSpecifierLocMatcher, MatchCallback *>>
209 NestedNameSpecifierLoc;
210 std::vector<std::pair<TypeLocMatcher, MatchCallback *>> TypeLoc;
211 /// \brief All the callbacks in one container to simplify iteration.
212 llvm::SmallPtrSet<MatchCallback *, 16> AllCallbacks;
216 MatchersByType Matchers;
218 MatchFinderOptions Options;
220 /// \brief Called when parsing is done.
221 ParsingDoneTestCallback *ParsingDone;
224 /// \brief Returns the results of matching \p Matcher on \p Node.
226 /// Collects the \c BoundNodes of all callback invocations when matching
227 /// \p Matcher on \p Node and returns the collected results.
229 /// Multiple results occur when using matchers like \c forEachDescendant,
230 /// which generate a result for each sub-match.
234 template <typename MatcherT, typename NodeT>
235 SmallVector<BoundNodes, 1>
236 match(MatcherT Matcher, const NodeT &Node, ASTContext &Context);
238 template <typename MatcherT>
239 SmallVector<BoundNodes, 1>
240 match(MatcherT Matcher, const ast_type_traits::DynTypedNode &Node,
241 ASTContext &Context);
244 /// \brief Returns the results of matching \p Matcher on the translation unit of
245 /// \p Context and collects the \c BoundNodes of all callback invocations.
246 template <typename MatcherT>
247 SmallVector<BoundNodes, 1> match(MatcherT Matcher, ASTContext &Context);
249 /// \brief Returns the first result of type \c NodeT bound to \p BoundTo.
251 /// Returns \c NULL if there is no match, or if the matching node cannot be
252 /// casted to \c NodeT.
254 /// This is useful in combanation with \c match():
256 /// const Decl *D = selectFirst<Decl>("id", match(Matcher.bind("id"),
259 template <typename NodeT>
261 selectFirst(StringRef BoundTo, const SmallVectorImpl<BoundNodes> &Results) {
262 for (const BoundNodes &N : Results) {
263 if (const NodeT *Node = N.getNodeAs<NodeT>(BoundTo))
270 class CollectMatchesCallback : public MatchFinder::MatchCallback {
272 void run(const MatchFinder::MatchResult &Result) override {
273 Nodes.push_back(Result.Nodes);
275 SmallVector<BoundNodes, 1> Nodes;
279 template <typename MatcherT>
280 SmallVector<BoundNodes, 1>
281 match(MatcherT Matcher, const ast_type_traits::DynTypedNode &Node,
282 ASTContext &Context) {
283 internal::CollectMatchesCallback Callback;
285 Finder.addMatcher(Matcher, &Callback);
286 Finder.match(Node, Context);
287 return std::move(Callback.Nodes);
290 template <typename MatcherT, typename NodeT>
291 SmallVector<BoundNodes, 1>
292 match(MatcherT Matcher, const NodeT &Node, ASTContext &Context) {
293 return match(Matcher, ast_type_traits::DynTypedNode::create(Node), Context);
296 template <typename MatcherT>
297 SmallVector<BoundNodes, 1>
298 match(MatcherT Matcher, ASTContext &Context) {
299 internal::CollectMatchesCallback Callback;
301 Finder.addMatcher(Matcher, &Callback);
302 Finder.matchAST(Context);
303 return std::move(Callback.Nodes);
306 } // end namespace ast_matchers
307 } // end namespace clang