diff options
Diffstat (limited to 'include/clang/ASTMatchers/ASTMatchFinder.h')
-rw-r--r-- | include/clang/ASTMatchers/ASTMatchFinder.h | 85 |
1 files changed, 82 insertions, 3 deletions
diff --git a/include/clang/ASTMatchers/ASTMatchFinder.h b/include/clang/ASTMatchers/ASTMatchFinder.h index 30b4050e1c81..870a39b39111 100644 --- a/include/clang/ASTMatchers/ASTMatchFinder.h +++ b/include/clang/ASTMatchers/ASTMatchFinder.h @@ -56,6 +56,10 @@ namespace ast_matchers { /// that will trigger the callbacks specified via addMatcher(...) when a match /// is found. /// +/// The order of matches is guaranteed to be equivalent to doing a pre-order +/// traversal on the AST, and applying the matchers in the order in which they +/// were added to the MatchFinder. +/// /// See ASTMatchers.h for more information about how to create matchers. /// /// Not intended to be subclassed. @@ -130,11 +134,17 @@ public: /// \brief Creates a clang ASTConsumer that finds all matches. clang::ASTConsumer *newASTConsumer(); - /// \brief Finds all matches on the given \c Node. + /// \brief Calls the registered callbacks on all matches on the given \p Node. + /// + /// Note that there can be multiple matches on a single node, for + /// example when using decl(forEachDescendant(stmt())). /// /// @{ - void findAll(const Decl &Node, ASTContext &Context); - void findAll(const Stmt &Node, ASTContext &Context); + template <typename T> void match(const T &Node, ASTContext &Context) { + match(clang::ast_type_traits::DynTypedNode::create(Node), Context); + } + void match(const clang::ast_type_traits::DynTypedNode &Node, + ASTContext &Context); /// @} /// \brief Registers a callback to notify the end of parsing. @@ -154,6 +164,75 @@ private: ParsingDoneTestCallback *ParsingDone; }; +/// \brief Returns the results of matching \p Matcher on \p Node. +/// +/// Collects the \c BoundNodes of all callback invocations when matching +/// \p Matcher on \p Node and returns the collected results. +/// +/// Multiple results occur when using matchers like \c forEachDescendant, +/// which generate a result for each sub-match. +/// +/// \see selectFirst +/// @{ +template <typename MatcherT, typename NodeT> +SmallVector<BoundNodes, 1> +match(MatcherT Matcher, const NodeT &Node, ASTContext &Context); + +template <typename MatcherT> +SmallVector<BoundNodes, 1> +match(MatcherT Matcher, const ast_type_traits::DynTypedNode &Node, + ASTContext &Context); +/// @} + +/// \brief Returns the first result of type \c NodeT bound to \p BoundTo. +/// +/// Returns \c NULL if there is no match, or if the matching node cannot be +/// casted to \c NodeT. +/// +/// This is useful in combanation with \c match(): +/// \code +/// Decl *D = selectFirst<Decl>("id", match(Matcher.bind("id"), +/// Node, Context)); +/// \endcode +template <typename NodeT> +NodeT * +selectFirst(StringRef BoundTo, const SmallVectorImpl<BoundNodes> &Results) { + for (SmallVectorImpl<BoundNodes>::const_iterator I = Results.begin(), + E = Results.end(); + I != E; ++I) { + if (NodeT *Node = I->getNodeAs<NodeT>(BoundTo)) + return Node; + } + return NULL; +} + +namespace internal { +class CollectMatchesCallback : public MatchFinder::MatchCallback { +public: + virtual void run(const MatchFinder::MatchResult &Result) { + Nodes.push_back(Result.Nodes); + } + SmallVector<BoundNodes, 1> Nodes; +}; +} + +template <typename MatcherT> +SmallVector<BoundNodes, 1> +match(MatcherT Matcher, const ast_type_traits::DynTypedNode &Node, + ASTContext &Context) { + internal::CollectMatchesCallback Callback; + MatchFinder Finder; + Finder.addMatcher(Matcher, &Callback); + Finder.match(Node, Context); + return Callback.Nodes; +} + +template <typename MatcherT, typename NodeT> +SmallVector<BoundNodes, 1> +match(MatcherT Matcher, const NodeT &Node, ASTContext &Context) { + return match(Matcher, ast_type_traits::DynTypedNode::create(Node), Context); +} + } // end namespace ast_matchers } // end namespace clang |