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 /// @} 163 164 /// Adds a matcher to execute when running over the AST. 165 /// 166 /// This is similar to \c addMatcher(), but it uses the dynamic interface. It 167 /// is more flexible, but the lost type information enables a caller to pass 168 /// a matcher that cannot match anything. 169 /// 170 /// \returns \c true if the matcher is a valid top-level matcher, \c false 171 /// otherwise. 172 bool addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch, 173 MatchCallback *Action); 174 175 /// Creates a clang ASTConsumer that finds all matches. 176 std::unique_ptr<clang::ASTConsumer> newASTConsumer(); 177 178 /// Calls the registered callbacks on all matches on the given \p Node. 179 /// 180 /// Note that there can be multiple matches on a single node, for 181 /// example when using decl(forEachDescendant(stmt())). 182 /// 183 /// @{ 184 template <typename T> void match(const T &Node, ASTContext &Context) { 185 match(clang::ast_type_traits::DynTypedNode::create(Node), Context); 186 } 187 void match(const clang::ast_type_traits::DynTypedNode &Node, 188 ASTContext &Context); 189 /// @} 190 191 /// Finds all matches in the given AST. 192 void matchAST(ASTContext &Context); 193 194 /// Registers a callback to notify the end of parsing. 195 /// 196 /// The provided closure is called after parsing is done, before the AST is 197 /// traversed. Useful for benchmarking. 198 /// Each call to FindAll(...) will call the closure once. 199 void registerTestCallbackAfterParsing(ParsingDoneTestCallback *ParsingDone); 200 201 /// For each \c Matcher<> a \c MatchCallback that will be called 202 /// when it matches. 203 struct MatchersByType { 204 std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *>> 205 DeclOrStmt; 206 std::vector<std::pair<TypeMatcher, MatchCallback *>> Type; 207 std::vector<std::pair<NestedNameSpecifierMatcher, MatchCallback *>> 208 NestedNameSpecifier; 209 std::vector<std::pair<NestedNameSpecifierLocMatcher, MatchCallback *>> 210 NestedNameSpecifierLoc; 211 std::vector<std::pair<TypeLocMatcher, MatchCallback *>> TypeLoc; 212 std::vector<std::pair<CXXCtorInitializerMatcher, MatchCallback *>> CtorInit; 213 /// All the callbacks in one container to simplify iteration. 214 llvm::SmallPtrSet<MatchCallback *, 16> AllCallbacks; 215 }; 216 217 private: 218 MatchersByType Matchers; 219 220 MatchFinderOptions Options; 221 222 /// Called when parsing is done. 223 ParsingDoneTestCallback *ParsingDone; 224 }; 225 226 /// Returns the results of matching \p Matcher on \p Node. 227 /// 228 /// Collects the \c BoundNodes of all callback invocations when matching 229 /// \p Matcher on \p Node and returns the collected results. 230 /// 231 /// Multiple results occur when using matchers like \c forEachDescendant, 232 /// which generate a result for each sub-match. 233 /// 234 /// If you want to find all matches on the sub-tree rooted at \c Node (rather 235 /// than only the matches on \c Node itself), surround the \c Matcher with a 236 /// \c findAll(). 237 /// 238 /// \see selectFirst 239 /// @{ 240 template <typename MatcherT, typename NodeT> 241 SmallVector<BoundNodes, 1> 242 match(MatcherT Matcher, const NodeT &Node, ASTContext &Context); 243 244 template <typename MatcherT> 245 SmallVector<BoundNodes, 1> 246 match(MatcherT Matcher, const ast_type_traits::DynTypedNode &Node, 247 ASTContext &Context); 248 /// @} 249 250 /// Returns the results of matching \p Matcher on the translation unit of 251 /// \p Context and collects the \c BoundNodes of all callback invocations. 252 template <typename MatcherT> 253 SmallVector<BoundNodes, 1> match(MatcherT Matcher, ASTContext &Context); 254 255 /// Returns the first result of type \c NodeT bound to \p BoundTo. 256 /// 257 /// Returns \c NULL if there is no match, or if the matching node cannot be 258 /// casted to \c NodeT. 259 /// 260 /// This is useful in combanation with \c match(): 261 /// \code 262 /// const Decl *D = selectFirst<Decl>("id", match(Matcher.bind("id"), 263 /// Node, Context)); 264 /// \endcode 265 template <typename NodeT> 266 const NodeT * 267 selectFirst(StringRef BoundTo, const SmallVectorImpl<BoundNodes> &Results) { 268 for (const BoundNodes &N : Results) { 269 if (const NodeT *Node = N.getNodeAs<NodeT>(BoundTo)) 270 return Node; 271 } 272 return nullptr; 273 } 274 275 namespace internal { 276 class CollectMatchesCallback : public MatchFinder::MatchCallback { 277 public: 278 void run(const MatchFinder::MatchResult &Result) override { 279 Nodes.push_back(Result.Nodes); 280 } 281 SmallVector<BoundNodes, 1> Nodes; 282 }; 283 } 284 285 template <typename MatcherT> 286 SmallVector<BoundNodes, 1> 287 match(MatcherT Matcher, const ast_type_traits::DynTypedNode &Node, 288 ASTContext &Context) { 289 internal::CollectMatchesCallback Callback; 290 MatchFinder Finder; 291 Finder.addMatcher(Matcher, &Callback); 292 Finder.match(Node, Context); 293 return std::move(Callback.Nodes); 294 } 295 296 template <typename MatcherT, typename NodeT> 297 SmallVector<BoundNodes, 1> 298 match(MatcherT Matcher, const NodeT &Node, ASTContext &Context) { 299 return match(Matcher, ast_type_traits::DynTypedNode::create(Node), Context); 300 } 301 302 template <typename MatcherT> 303 SmallVector<BoundNodes, 1> 304 match(MatcherT Matcher, ASTContext &Context) { 305 internal::CollectMatchesCallback Callback; 306 MatchFinder Finder; 307 Finder.addMatcher(Matcher, &Callback); 308 Finder.matchAST(Context); 309 return std::move(Callback.Nodes); 310 } 311 312 inline SmallVector<BoundNodes, 1> 313 matchDynamic(internal::DynTypedMatcher Matcher, 314 const ast_type_traits::DynTypedNode &Node, ASTContext &Context) { 315 internal::CollectMatchesCallback Callback; 316 MatchFinder Finder; 317 Finder.addDynamicMatcher(Matcher, &Callback); 318 Finder.match(Node, Context); 319 return std::move(Callback.Nodes); 320 } 321 322 template <typename NodeT> 323 SmallVector<BoundNodes, 1> matchDynamic(internal::DynTypedMatcher Matcher, 324 const NodeT &Node, 325 ASTContext &Context) { 326 return matchDynamic(Matcher, ast_type_traits::DynTypedNode::create(Node), 327 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