ASTMatchFinder.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  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. #include <optional>
  51. namespace clang {
  52. namespace ast_matchers {
  53. /// A class to allow finding matches over the Clang AST.
  54. ///
  55. /// After creation, you can add multiple matchers to the MatchFinder via
  56. /// calls to addMatcher(...).
  57. ///
  58. /// Once all matchers are added, newASTConsumer() returns an ASTConsumer
  59. /// that will trigger the callbacks specified via addMatcher(...) when a match
  60. /// is found.
  61. ///
  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.
  65. ///
  66. /// See ASTMatchers.h for more information about how to create matchers.
  67. ///
  68. /// Not intended to be subclassed.
  69. class MatchFinder {
  70. public:
  71. /// Contains all information for a given match.
  72. ///
  73. /// Every time a match is found, the MatchFinder will invoke the registered
  74. /// MatchCallback with a MatchResult containing information about the match.
  75. struct MatchResult {
  76. MatchResult(const BoundNodes &Nodes, clang::ASTContext *Context);
  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. /// Utilities for interpreting the matched AST structures.
  82. /// @{
  83. clang::ASTContext * const Context;
  84. clang::SourceManager * const SourceManager;
  85. /// @}
  86. };
  87. /// Called when the Match registered for it was successfully found
  88. /// in the AST.
  89. class MatchCallback {
  90. public:
  91. virtual ~MatchCallback();
  92. /// Called on every match by the \c MatchFinder.
  93. virtual void run(const MatchResult &Result) = 0;
  94. /// Called at the start of each translation unit.
  95. ///
  96. /// Optionally override to do per translation unit tasks.
  97. virtual void onStartOfTranslationUnit() {}
  98. /// Called at the end of each translation unit.
  99. ///
  100. /// Optionally override to do per translation unit tasks.
  101. virtual void onEndOfTranslationUnit() {}
  102. /// An id used to group the matchers.
  103. ///
  104. /// This id is used, for example, for the profiling output.
  105. /// It defaults to "<unknown>".
  106. virtual StringRef getID() const;
  107. /// TraversalKind to use while matching and processing
  108. /// the result nodes. This API is temporary to facilitate
  109. /// third parties porting existing code to the default
  110. /// behavior of clang-tidy.
  111. virtual std::optional<TraversalKind> getCheckTraversalKind() const;
  112. };
  113. /// Called when parsing is finished. Intended for testing only.
  114. class ParsingDoneTestCallback {
  115. public:
  116. virtual ~ParsingDoneTestCallback();
  117. virtual void run() = 0;
  118. };
  119. struct MatchFinderOptions {
  120. struct Profiling {
  121. Profiling(llvm::StringMap<llvm::TimeRecord> &Records)
  122. : Records(Records) {}
  123. /// Per bucket timing information.
  124. llvm::StringMap<llvm::TimeRecord> &Records;
  125. };
  126. /// Enables per-check timers.
  127. ///
  128. /// It prints a report after match.
  129. std::optional<Profiling> CheckProfiling;
  130. };
  131. MatchFinder(MatchFinderOptions Options = MatchFinderOptions());
  132. ~MatchFinder();
  133. /// Adds a matcher to execute when running over the AST.
  134. ///
  135. /// Calls 'Action' with the BoundNodes on every match.
  136. /// Adding more than one 'NodeMatch' allows finding different matches in a
  137. /// single pass over the AST.
  138. ///
  139. /// Does not take ownership of 'Action'.
  140. /// @{
  141. void addMatcher(const DeclarationMatcher &NodeMatch,
  142. MatchCallback *Action);
  143. void addMatcher(const TypeMatcher &NodeMatch,
  144. MatchCallback *Action);
  145. void addMatcher(const StatementMatcher &NodeMatch,
  146. MatchCallback *Action);
  147. void addMatcher(const NestedNameSpecifierMatcher &NodeMatch,
  148. MatchCallback *Action);
  149. void addMatcher(const NestedNameSpecifierLocMatcher &NodeMatch,
  150. MatchCallback *Action);
  151. void addMatcher(const TypeLocMatcher &NodeMatch,
  152. MatchCallback *Action);
  153. void addMatcher(const CXXCtorInitializerMatcher &NodeMatch,
  154. MatchCallback *Action);
  155. void addMatcher(const TemplateArgumentLocMatcher &NodeMatch,
  156. MatchCallback *Action);
  157. void addMatcher(const AttrMatcher &NodeMatch, MatchCallback *Action);
  158. /// @}
  159. /// Adds a matcher to execute when running over the AST.
  160. ///
  161. /// This is similar to \c addMatcher(), but it uses the dynamic interface. It
  162. /// is more flexible, but the lost type information enables a caller to pass
  163. /// a matcher that cannot match anything.
  164. ///
  165. /// \returns \c true if the matcher is a valid top-level matcher, \c false
  166. /// otherwise.
  167. bool addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
  168. MatchCallback *Action);
  169. /// Creates a clang ASTConsumer that finds all matches.
  170. std::unique_ptr<clang::ASTConsumer> newASTConsumer();
  171. /// Calls the registered callbacks on all matches on the given \p Node.
  172. ///
  173. /// Note that there can be multiple matches on a single node, for
  174. /// example when using decl(forEachDescendant(stmt())).
  175. ///
  176. /// @{
  177. template <typename T> void match(const T &Node, ASTContext &Context) {
  178. match(clang::DynTypedNode::create(Node), Context);
  179. }
  180. void match(const clang::DynTypedNode &Node, ASTContext &Context);
  181. /// @}
  182. /// Finds all matches in the given AST.
  183. void matchAST(ASTContext &Context);
  184. /// Registers a callback to notify the end of parsing.
  185. ///
  186. /// The provided closure is called after parsing is done, before the AST is
  187. /// traversed. Useful for benchmarking.
  188. /// Each call to FindAll(...) will call the closure once.
  189. void registerTestCallbackAfterParsing(ParsingDoneTestCallback *ParsingDone);
  190. /// For each \c Matcher<> a \c MatchCallback that will be called
  191. /// when it matches.
  192. struct MatchersByType {
  193. std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *>>
  194. DeclOrStmt;
  195. std::vector<std::pair<TypeMatcher, MatchCallback *>> Type;
  196. std::vector<std::pair<NestedNameSpecifierMatcher, MatchCallback *>>
  197. NestedNameSpecifier;
  198. std::vector<std::pair<NestedNameSpecifierLocMatcher, MatchCallback *>>
  199. NestedNameSpecifierLoc;
  200. std::vector<std::pair<TypeLocMatcher, MatchCallback *>> TypeLoc;
  201. std::vector<std::pair<CXXCtorInitializerMatcher, MatchCallback *>> CtorInit;
  202. std::vector<std::pair<TemplateArgumentLocMatcher, MatchCallback *>>
  203. TemplateArgumentLoc;
  204. std::vector<std::pair<AttrMatcher, MatchCallback *>> Attr;
  205. /// All the callbacks in one container to simplify iteration.
  206. llvm::SmallPtrSet<MatchCallback *, 16> AllCallbacks;
  207. };
  208. private:
  209. MatchersByType Matchers;
  210. MatchFinderOptions Options;
  211. /// Called when parsing is done.
  212. ParsingDoneTestCallback *ParsingDone;
  213. };
  214. /// Returns the results of matching \p Matcher on \p Node.
  215. ///
  216. /// Collects the \c BoundNodes of all callback invocations when matching
  217. /// \p Matcher on \p Node and returns the collected results.
  218. ///
  219. /// Multiple results occur when using matchers like \c forEachDescendant,
  220. /// which generate a result for each sub-match.
  221. ///
  222. /// If you want to find all matches on the sub-tree rooted at \c Node (rather
  223. /// than only the matches on \c Node itself), surround the \c Matcher with a
  224. /// \c findAll().
  225. ///
  226. /// \see selectFirst
  227. /// @{
  228. template <typename MatcherT, typename NodeT>
  229. SmallVector<BoundNodes, 1>
  230. match(MatcherT Matcher, const NodeT &Node, ASTContext &Context);
  231. template <typename MatcherT>
  232. SmallVector<BoundNodes, 1> match(MatcherT Matcher, const DynTypedNode &Node,
  233. ASTContext &Context);
  234. /// @}
  235. /// Returns the results of matching \p Matcher on the translation unit of
  236. /// \p Context and collects the \c BoundNodes of all callback invocations.
  237. template <typename MatcherT>
  238. SmallVector<BoundNodes, 1> match(MatcherT Matcher, ASTContext &Context);
  239. /// Returns the first result of type \c NodeT bound to \p BoundTo.
  240. ///
  241. /// Returns \c NULL if there is no match, or if the matching node cannot be
  242. /// casted to \c NodeT.
  243. ///
  244. /// This is useful in combanation with \c match():
  245. /// \code
  246. /// const Decl *D = selectFirst<Decl>("id", match(Matcher.bind("id"),
  247. /// Node, Context));
  248. /// \endcode
  249. template <typename NodeT>
  250. const NodeT *
  251. selectFirst(StringRef BoundTo, const SmallVectorImpl<BoundNodes> &Results) {
  252. for (const BoundNodes &N : Results) {
  253. if (const NodeT *Node = N.getNodeAs<NodeT>(BoundTo))
  254. return Node;
  255. }
  256. return nullptr;
  257. }
  258. namespace internal {
  259. class CollectMatchesCallback : public MatchFinder::MatchCallback {
  260. public:
  261. void run(const MatchFinder::MatchResult &Result) override {
  262. Nodes.push_back(Result.Nodes);
  263. }
  264. std::optional<TraversalKind> getCheckTraversalKind() const override {
  265. return std::nullopt;
  266. }
  267. SmallVector<BoundNodes, 1> Nodes;
  268. };
  269. }
  270. template <typename MatcherT>
  271. SmallVector<BoundNodes, 1> match(MatcherT Matcher, const DynTypedNode &Node,
  272. ASTContext &Context) {
  273. internal::CollectMatchesCallback Callback;
  274. MatchFinder Finder;
  275. Finder.addMatcher(Matcher, &Callback);
  276. Finder.match(Node, Context);
  277. return std::move(Callback.Nodes);
  278. }
  279. template <typename MatcherT, typename NodeT>
  280. SmallVector<BoundNodes, 1>
  281. match(MatcherT Matcher, const NodeT &Node, ASTContext &Context) {
  282. return match(Matcher, DynTypedNode::create(Node), Context);
  283. }
  284. template <typename MatcherT>
  285. SmallVector<BoundNodes, 1>
  286. match(MatcherT Matcher, ASTContext &Context) {
  287. internal::CollectMatchesCallback Callback;
  288. MatchFinder Finder;
  289. Finder.addMatcher(Matcher, &Callback);
  290. Finder.matchAST(Context);
  291. return std::move(Callback.Nodes);
  292. }
  293. inline SmallVector<BoundNodes, 1>
  294. matchDynamic(internal::DynTypedMatcher Matcher, const DynTypedNode &Node,
  295. ASTContext &Context) {
  296. internal::CollectMatchesCallback Callback;
  297. MatchFinder Finder;
  298. Finder.addDynamicMatcher(Matcher, &Callback);
  299. Finder.match(Node, Context);
  300. return std::move(Callback.Nodes);
  301. }
  302. template <typename NodeT>
  303. SmallVector<BoundNodes, 1> matchDynamic(internal::DynTypedMatcher Matcher,
  304. const NodeT &Node,
  305. ASTContext &Context) {
  306. return matchDynamic(Matcher, DynTypedNode::create(Node), Context);
  307. }
  308. inline SmallVector<BoundNodes, 1>
  309. matchDynamic(internal::DynTypedMatcher Matcher, ASTContext &Context) {
  310. internal::CollectMatchesCallback Callback;
  311. MatchFinder Finder;
  312. Finder.addDynamicMatcher(Matcher, &Callback);
  313. Finder.matchAST(Context);
  314. return std::move(Callback.Nodes);
  315. }
  316. } // end namespace ast_matchers
  317. } // end namespace clang
  318. #endif
  319. #ifdef __GNUC__
  320. #pragma GCC diagnostic pop
  321. #endif