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