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 115 /// Called when parsing is finished. Intended for testing only. 116 class ParsingDoneTestCallback { 117 public: 118 virtual ~ParsingDoneTestCallback(); 119 virtual void run() = 0; 120 }; 121 122 struct MatchFinderOptions { 123 struct Profiling { 124 Profiling(llvm::StringMap<llvm::TimeRecord> &Records) 125 : Records(Records) {} 126 127 /// Per bucket timing information. 128 llvm::StringMap<llvm::TimeRecord> &Records; 129 }; 130 131 /// Enables per-check timers. 132 /// 133 /// It prints a report after match. 134 llvm::Optional<Profiling> CheckProfiling; 135 }; 136 137 MatchFinder(MatchFinderOptions Options = MatchFinderOptions()); 138 ~MatchFinder(); 139 140 /// Adds a matcher to execute when running over the AST. 141 /// 142 /// Calls 'Action' with the BoundNodes on every match. 143 /// Adding more than one 'NodeMatch' allows finding different matches in a 144 /// single pass over the AST. 145 /// 146 /// Does not take ownership of 'Action'. 147 /// @{ 148 void addMatcher(const DeclarationMatcher &NodeMatch, 149 MatchCallback *Action); 150 void addMatcher(const TypeMatcher &NodeMatch, 151 MatchCallback *Action); 152 void addMatcher(const StatementMatcher &NodeMatch, 153 MatchCallback *Action); 154 void addMatcher(const NestedNameSpecifierMatcher &NodeMatch, 155 MatchCallback *Action); 156 void addMatcher(const NestedNameSpecifierLocMatcher &NodeMatch, 157 MatchCallback *Action); 158 void addMatcher(const TypeLocMatcher &NodeMatch, 159 MatchCallback *Action); 160 void addMatcher(const CXXCtorInitializerMatcher &NodeMatch, 161 MatchCallback *Action); 162 void addMatcher(const TemplateArgumentLocMatcher &NodeMatch, 163 MatchCallback *Action); 164 /// @} 165 166 /// Adds a matcher to execute when running over the AST. 167 /// 168 /// This is similar to \c addMatcher(), but it uses the dynamic interface. It 169 /// is more flexible, but the lost type information enables a caller to pass 170 /// a matcher that cannot match anything. 171 /// 172 /// \returns \c true if the matcher is a valid top-level matcher, \c false 173 /// otherwise. 174 bool addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch, 175 MatchCallback *Action); 176 177 /// Creates a clang ASTConsumer that finds all matches. 178 std::unique_ptr<clang::ASTConsumer> newASTConsumer(); 179 180 /// Calls the registered callbacks on all matches on the given \p Node. 181 /// 182 /// Note that there can be multiple matches on a single node, for 183 /// example when using decl(forEachDescendant(stmt())). 184 /// 185 /// @{ 186 template <typename T> void match(const T &Node, ASTContext &Context) { 187 match(clang::DynTypedNode::create(Node), Context); 188 } 189 void match(const clang::DynTypedNode &Node, ASTContext &Context); 190 /// @} 191 192 /// Finds all matches in the given AST. 193 void matchAST(ASTContext &Context); 194 195 /// 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 /// 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 std::vector<std::pair<TemplateArgumentLocMatcher, MatchCallback *>> 215 TemplateArgumentLoc; 216 /// All the callbacks in one container to simplify iteration. 217 llvm::SmallPtrSet<MatchCallback *, 16> AllCallbacks; 218 }; 219 220 private: 221 MatchersByType Matchers; 222 223 MatchFinderOptions Options; 224 225 /// Called when parsing is done. 226 ParsingDoneTestCallback *ParsingDone; 227 }; 228 229 /// Returns the results of matching \p Matcher on \p Node. 230 /// 231 /// Collects the \c BoundNodes of all callback invocations when matching 232 /// \p Matcher on \p Node and returns the collected results. 233 /// 234 /// Multiple results occur when using matchers like \c forEachDescendant, 235 /// which generate a result for each sub-match. 236 /// 237 /// If you want to find all matches on the sub-tree rooted at \c Node (rather 238 /// than only the matches on \c Node itself), surround the \c Matcher with a 239 /// \c findAll(). 240 /// 241 /// \see selectFirst 242 /// @{ 243 template <typename MatcherT, typename NodeT> 244 SmallVector<BoundNodes, 1> 245 match(MatcherT Matcher, const NodeT &Node, ASTContext &Context); 246 247 template <typename MatcherT> 248 SmallVector<BoundNodes, 1> match(MatcherT Matcher, const DynTypedNode &Node, 249 ASTContext &Context); 250 /// @} 251 252 /// Returns the results of matching \p Matcher on the translation unit of 253 /// \p Context and collects the \c BoundNodes of all callback invocations. 254 template <typename MatcherT> 255 SmallVector<BoundNodes, 1> match(MatcherT Matcher, ASTContext &Context); 256 257 /// Returns the first result of type \c NodeT bound to \p BoundTo. 258 /// 259 /// Returns \c NULL if there is no match, or if the matching node cannot be 260 /// casted to \c NodeT. 261 /// 262 /// This is useful in combanation with \c match(): 263 /// \code 264 /// const Decl *D = selectFirst<Decl>("id", match(Matcher.bind("id"), 265 /// Node, Context)); 266 /// \endcode 267 template <typename NodeT> 268 const NodeT * 269 selectFirst(StringRef BoundTo, const SmallVectorImpl<BoundNodes> &Results) { 270 for (const BoundNodes &N : Results) { 271 if (const NodeT *Node = N.getNodeAs<NodeT>(BoundTo)) 272 return Node; 273 } 274 return nullptr; 275 } 276 277 namespace internal { 278 class CollectMatchesCallback : public MatchFinder::MatchCallback { 279 public: 280 void run(const MatchFinder::MatchResult &Result) override { 281 Nodes.push_back(Result.Nodes); 282 } 283 SmallVector<BoundNodes, 1> Nodes; 284 }; 285 } 286 287 template <typename MatcherT> 288 SmallVector<BoundNodes, 1> match(MatcherT Matcher, const 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, 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 inline SmallVector<BoundNodes, 1> 314 matchDynamic(internal::DynTypedMatcher Matcher, const DynTypedNode &Node, 315 ASTContext &Context) { 316 internal::CollectMatchesCallback Callback; 317 MatchFinder Finder; 318 Finder.addDynamicMatcher(Matcher, &Callback); 319 Finder.match(Node, Context); 320 return std::move(Callback.Nodes); 321 } 322 323 template <typename NodeT> 324 SmallVector<BoundNodes, 1> matchDynamic(internal::DynTypedMatcher Matcher, 325 const NodeT &Node, 326 ASTContext &Context) { 327 return matchDynamic(Matcher, DynTypedNode::create(Node), Context); 328 } 329 330 inline SmallVector<BoundNodes, 1> 331 matchDynamic(internal::DynTypedMatcher Matcher, ASTContext &Context) { 332 internal::CollectMatchesCallback Callback; 333 MatchFinder Finder; 334 Finder.addDynamicMatcher(Matcher, &Callback); 335 Finder.matchAST(Context); 336 return std::move(Callback.Nodes); 337 } 338 339 } // end namespace ast_matchers 340 } // end namespace clang 341 342 #endif 343