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