Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:36:48

0001 //===--- ASTMatchFinder.h - Structural query framework ----------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 //  Provides a way to construct an ASTConsumer that runs given matchers
0010 //  over the AST and invokes a given callback on every match.
0011 //
0012 //  The general idea is to construct a matcher expression that describes a
0013 //  subtree match on the AST. Next, a callback that is executed every time the
0014 //  expression matches is registered, and the matcher is run over the AST of
0015 //  some code. Matched subexpressions can be bound to string IDs and easily
0016 //  be accessed from the registered callback. The callback can than use the
0017 //  AST nodes that the subexpressions matched on to output information about
0018 //  the match or construct changes that can be applied to the code.
0019 //
0020 //  Example:
0021 //  class HandleMatch : public MatchFinder::MatchCallback {
0022 //  public:
0023 //    virtual void Run(const MatchFinder::MatchResult &Result) {
0024 //      const CXXRecordDecl *Class =
0025 //          Result.Nodes.GetDeclAs<CXXRecordDecl>("id");
0026 //      ...
0027 //    }
0028 //  };
0029 //
0030 //  int main(int argc, char **argv) {
0031 //    ClangTool Tool(argc, argv);
0032 //    MatchFinder finder;
0033 //    finder.AddMatcher(Id("id", record(hasName("::a_namespace::AClass"))),
0034 //                      new HandleMatch);
0035 //    return Tool.Run(newFrontendActionFactory(&finder));
0036 //  }
0037 //
0038 //===----------------------------------------------------------------------===//
0039 
0040 #ifndef LLVM_CLANG_ASTMATCHERS_ASTMATCHFINDER_H
0041 #define LLVM_CLANG_ASTMATCHERS_ASTMATCHFINDER_H
0042 
0043 #include "clang/ASTMatchers/ASTMatchers.h"
0044 #include "llvm/ADT/SmallPtrSet.h"
0045 #include "llvm/ADT/StringMap.h"
0046 #include "llvm/Support/Timer.h"
0047 #include <optional>
0048 
0049 namespace clang {
0050 
0051 namespace ast_matchers {
0052 
0053 /// A class to allow finding matches over the Clang AST.
0054 ///
0055 /// After creation, you can add multiple matchers to the MatchFinder via
0056 /// calls to addMatcher(...).
0057 ///
0058 /// Once all matchers are added, newASTConsumer() returns an ASTConsumer
0059 /// that will trigger the callbacks specified via addMatcher(...) when a match
0060 /// is found.
0061 ///
0062 /// The order of matches is guaranteed to be equivalent to doing a pre-order
0063 /// traversal on the AST, and applying the matchers in the order in which they
0064 /// were added to the MatchFinder.
0065 ///
0066 /// See ASTMatchers.h for more information about how to create matchers.
0067 ///
0068 /// Not intended to be subclassed.
0069 class MatchFinder {
0070 public:
0071   /// Contains all information for a given match.
0072   ///
0073   /// Every time a match is found, the MatchFinder will invoke the registered
0074   /// MatchCallback with a MatchResult containing information about the match.
0075   struct MatchResult {
0076     MatchResult(const BoundNodes &Nodes, clang::ASTContext *Context);
0077 
0078     /// Contains the nodes bound on the current match.
0079     ///
0080     /// This allows user code to easily extract matched AST nodes.
0081     const BoundNodes Nodes;
0082 
0083     /// Utilities for interpreting the matched AST structures.
0084     /// @{
0085     clang::ASTContext * const Context;
0086     clang::SourceManager * const SourceManager;
0087     /// @}
0088   };
0089 
0090   /// Called when the Match registered for it was successfully found
0091   /// in the AST.
0092   class MatchCallback {
0093   public:
0094     virtual ~MatchCallback();
0095 
0096     /// Called on every match by the \c MatchFinder.
0097     virtual void run(const MatchResult &Result) = 0;
0098 
0099     /// Called at the start of each translation unit.
0100     ///
0101     /// Optionally override to do per translation unit tasks.
0102     virtual void onStartOfTranslationUnit() {}
0103 
0104     /// Called at the end of each translation unit.
0105     ///
0106     /// Optionally override to do per translation unit tasks.
0107     virtual void onEndOfTranslationUnit() {}
0108 
0109     /// An id used to group the matchers.
0110     ///
0111     /// This id is used, for example, for the profiling output.
0112     /// It defaults to "<unknown>".
0113     virtual StringRef getID() const;
0114 
0115     /// TraversalKind to use while matching and processing
0116     /// the result nodes. This API is temporary to facilitate
0117     /// third parties porting existing code to the default
0118     /// behavior of clang-tidy.
0119     virtual std::optional<TraversalKind> getCheckTraversalKind() const;
0120   };
0121 
0122   /// Called when parsing is finished. Intended for testing only.
0123   class ParsingDoneTestCallback {
0124   public:
0125     virtual ~ParsingDoneTestCallback();
0126     virtual void run() = 0;
0127   };
0128 
0129   struct MatchFinderOptions {
0130     struct Profiling {
0131       Profiling(llvm::StringMap<llvm::TimeRecord> &Records)
0132           : Records(Records) {}
0133 
0134       /// Per bucket timing information.
0135       llvm::StringMap<llvm::TimeRecord> &Records;
0136     };
0137 
0138     /// Enables per-check timers.
0139     ///
0140     /// It prints a report after match.
0141     std::optional<Profiling> CheckProfiling;
0142   };
0143 
0144   MatchFinder(MatchFinderOptions Options = MatchFinderOptions());
0145   ~MatchFinder();
0146 
0147   /// Adds a matcher to execute when running over the AST.
0148   ///
0149   /// Calls 'Action' with the BoundNodes on every match.
0150   /// Adding more than one 'NodeMatch' allows finding different matches in a
0151   /// single pass over the AST.
0152   ///
0153   /// Does not take ownership of 'Action'.
0154   /// @{
0155   void addMatcher(const DeclarationMatcher &NodeMatch,
0156                   MatchCallback *Action);
0157   void addMatcher(const TypeMatcher &NodeMatch,
0158                   MatchCallback *Action);
0159   void addMatcher(const StatementMatcher &NodeMatch,
0160                   MatchCallback *Action);
0161   void addMatcher(const NestedNameSpecifierMatcher &NodeMatch,
0162                   MatchCallback *Action);
0163   void addMatcher(const NestedNameSpecifierLocMatcher &NodeMatch,
0164                   MatchCallback *Action);
0165   void addMatcher(const TypeLocMatcher &NodeMatch,
0166                   MatchCallback *Action);
0167   void addMatcher(const CXXCtorInitializerMatcher &NodeMatch,
0168                   MatchCallback *Action);
0169   void addMatcher(const TemplateArgumentLocMatcher &NodeMatch,
0170                   MatchCallback *Action);
0171   void addMatcher(const AttrMatcher &NodeMatch, MatchCallback *Action);
0172   /// @}
0173 
0174   /// Adds a matcher to execute when running over the AST.
0175   ///
0176   /// This is similar to \c addMatcher(), but it uses the dynamic interface. It
0177   /// is more flexible, but the lost type information enables a caller to pass
0178   /// a matcher that cannot match anything.
0179   ///
0180   /// \returns \c true if the matcher is a valid top-level matcher, \c false
0181   ///   otherwise.
0182   bool addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
0183                          MatchCallback *Action);
0184 
0185   /// Creates a clang ASTConsumer that finds all matches.
0186   std::unique_ptr<clang::ASTConsumer> newASTConsumer();
0187 
0188   /// Calls the registered callbacks on all matches on the given \p Node.
0189   ///
0190   /// Note that there can be multiple matches on a single node, for
0191   /// example when using decl(forEachDescendant(stmt())).
0192   ///
0193   /// @{
0194   template <typename T> void match(const T &Node, ASTContext &Context) {
0195     match(clang::DynTypedNode::create(Node), Context);
0196   }
0197   void match(const clang::DynTypedNode &Node, ASTContext &Context);
0198   /// @}
0199 
0200   /// Finds all matches in the given AST.
0201   void matchAST(ASTContext &Context);
0202 
0203   /// Registers a callback to notify the end of parsing.
0204   ///
0205   /// The provided closure is called after parsing is done, before the AST is
0206   /// traversed. Useful for benchmarking.
0207   /// Each call to FindAll(...) will call the closure once.
0208   void registerTestCallbackAfterParsing(ParsingDoneTestCallback *ParsingDone);
0209 
0210   /// For each \c Matcher<> a \c MatchCallback that will be called
0211   /// when it matches.
0212   struct MatchersByType {
0213     std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *>>
0214         DeclOrStmt;
0215     std::vector<std::pair<TypeMatcher, MatchCallback *>> Type;
0216     std::vector<std::pair<NestedNameSpecifierMatcher, MatchCallback *>>
0217         NestedNameSpecifier;
0218     std::vector<std::pair<NestedNameSpecifierLocMatcher, MatchCallback *>>
0219         NestedNameSpecifierLoc;
0220     std::vector<std::pair<TypeLocMatcher, MatchCallback *>> TypeLoc;
0221     std::vector<std::pair<CXXCtorInitializerMatcher, MatchCallback *>> CtorInit;
0222     std::vector<std::pair<TemplateArgumentLocMatcher, MatchCallback *>>
0223         TemplateArgumentLoc;
0224     std::vector<std::pair<AttrMatcher, MatchCallback *>> Attr;
0225     /// All the callbacks in one container to simplify iteration.
0226     llvm::SmallPtrSet<MatchCallback *, 16> AllCallbacks;
0227   };
0228 
0229 private:
0230   MatchersByType Matchers;
0231 
0232   MatchFinderOptions Options;
0233 
0234   /// Called when parsing is done.
0235   ParsingDoneTestCallback *ParsingDone;
0236 };
0237 
0238 /// Returns the results of matching \p Matcher on \p Node.
0239 ///
0240 /// Collects the \c BoundNodes of all callback invocations when matching
0241 /// \p Matcher on \p Node and returns the collected results.
0242 ///
0243 /// Multiple results occur when using matchers like \c forEachDescendant,
0244 /// which generate a result for each sub-match.
0245 ///
0246 /// If you want to find all matches on the sub-tree rooted at \c Node (rather
0247 /// than only the matches on \c Node itself), surround the \c Matcher with a
0248 /// \c findAll().
0249 ///
0250 /// \see selectFirst
0251 /// @{
0252 template <typename MatcherT, typename NodeT>
0253 SmallVector<BoundNodes, 1>
0254 match(MatcherT Matcher, const NodeT &Node, ASTContext &Context);
0255 
0256 template <typename MatcherT>
0257 SmallVector<BoundNodes, 1> match(MatcherT Matcher, const DynTypedNode &Node,
0258                                  ASTContext &Context);
0259 /// @}
0260 
0261 /// Returns the results of matching \p Matcher on the translation unit of
0262 /// \p Context and collects the \c BoundNodes of all callback invocations.
0263 template <typename MatcherT>
0264 SmallVector<BoundNodes, 1> match(MatcherT Matcher, ASTContext &Context);
0265 
0266 /// Returns the first result of type \c NodeT bound to \p BoundTo.
0267 ///
0268 /// Returns \c NULL if there is no match, or if the matching node cannot be
0269 /// casted to \c NodeT.
0270 ///
0271 /// This is useful in combanation with \c match():
0272 /// \code
0273 ///   const Decl *D = selectFirst<Decl>("id", match(Matcher.bind("id"),
0274 ///                                                 Node, Context));
0275 /// \endcode
0276 template <typename NodeT>
0277 const NodeT *
0278 selectFirst(StringRef BoundTo, const SmallVectorImpl<BoundNodes> &Results) {
0279   for (const BoundNodes &N : Results) {
0280     if (const NodeT *Node = N.getNodeAs<NodeT>(BoundTo))
0281       return Node;
0282   }
0283   return nullptr;
0284 }
0285 
0286 namespace internal {
0287 class CollectMatchesCallback : public MatchFinder::MatchCallback {
0288 public:
0289   void run(const MatchFinder::MatchResult &Result) override {
0290     Nodes.push_back(Result.Nodes);
0291   }
0292 
0293   std::optional<TraversalKind> getCheckTraversalKind() const override {
0294     return std::nullopt;
0295   }
0296 
0297   SmallVector<BoundNodes, 1> Nodes;
0298 };
0299 }
0300 
0301 template <typename MatcherT>
0302 SmallVector<BoundNodes, 1> match(MatcherT Matcher, const DynTypedNode &Node,
0303                                  ASTContext &Context) {
0304   internal::CollectMatchesCallback Callback;
0305   MatchFinder Finder;
0306   Finder.addMatcher(Matcher, &Callback);
0307   Finder.match(Node, Context);
0308   return std::move(Callback.Nodes);
0309 }
0310 
0311 template <typename MatcherT, typename NodeT>
0312 SmallVector<BoundNodes, 1>
0313 match(MatcherT Matcher, const NodeT &Node, ASTContext &Context) {
0314   return match(Matcher, DynTypedNode::create(Node), Context);
0315 }
0316 
0317 template <typename MatcherT>
0318 SmallVector<BoundNodes, 1>
0319 match(MatcherT Matcher, ASTContext &Context) {
0320   internal::CollectMatchesCallback Callback;
0321   MatchFinder Finder;
0322   Finder.addMatcher(Matcher, &Callback);
0323   Finder.matchAST(Context);
0324   return std::move(Callback.Nodes);
0325 }
0326 
0327 inline SmallVector<BoundNodes, 1>
0328 matchDynamic(internal::DynTypedMatcher Matcher, const DynTypedNode &Node,
0329              ASTContext &Context) {
0330   internal::CollectMatchesCallback Callback;
0331   MatchFinder Finder;
0332   Finder.addDynamicMatcher(Matcher, &Callback);
0333   Finder.match(Node, Context);
0334   return std::move(Callback.Nodes);
0335 }
0336 
0337 template <typename NodeT>
0338 SmallVector<BoundNodes, 1> matchDynamic(internal::DynTypedMatcher Matcher,
0339                                         const NodeT &Node,
0340                                         ASTContext &Context) {
0341   return matchDynamic(Matcher, DynTypedNode::create(Node), Context);
0342 }
0343 
0344 inline SmallVector<BoundNodes, 1>
0345 matchDynamic(internal::DynTypedMatcher Matcher, ASTContext &Context) {
0346   internal::CollectMatchesCallback Callback;
0347   MatchFinder Finder;
0348   Finder.addDynamicMatcher(Matcher, &Callback);
0349   Finder.matchAST(Context);
0350   return std::move(Callback.Nodes);
0351 }
0352 
0353 } // end namespace ast_matchers
0354 } // end namespace clang
0355 
0356 #endif