Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

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