ASTMatchFinder.h 12 KB

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