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