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