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