diff --git a/clang/include/clang/ASTMatchers/ASTMatchFinder.h b/clang/include/clang/ASTMatchers/ASTMatchFinder.h --- a/clang/include/clang/ASTMatchers/ASTMatchFinder.h +++ b/clang/include/clang/ASTMatchers/ASTMatchFinder.h @@ -280,6 +280,24 @@ return nullptr; } +/// Returns the first result of type \c NodeT bound to the root match result. +/// +/// 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 +/// const Decl *D = selectFirst(match(DeclMatcher, Node, Context)); +/// \endcode +template +const NodeT *selectFirst(const SmallVectorImpl &Results) { + for (const BoundNodes &N : Results) { + if (const NodeT *Node = N.getRootAs()) + return Node; + } + return nullptr; +} + namespace internal { class CollectMatchesCallback : public MatchFinder::MatchCallback { public: diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -125,14 +125,21 @@ return MyBoundNodes.getMap(); } + template const T *getRootAs() const { return RootNode.get(); } + + const DynTypedNode &getRoot() const { return RootNode; } + private: friend class internal::BoundNodesTreeBuilder; /// Create BoundNodes from a pre-filled map of bindings. - BoundNodes(internal::BoundNodesMap &MyBoundNodes) - : MyBoundNodes(MyBoundNodes) {} + BoundNodes(internal::BoundNodesMap &MyBoundNodes, + const DynTypedNode &RootNode) + : MyBoundNodes(MyBoundNodes), RootNode(RootNode) {} internal::BoundNodesMap MyBoundNodes; + + DynTypedNode RootNode; }; /// Types of matchers for the top-level classes in the AST class diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h --- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -248,7 +248,7 @@ /// Visits all matches that this BoundNodesTree represents. /// /// The ownership of 'ResultVisitor' remains at the caller. - void visitMatches(Visitor* ResultVisitor); + void visitMatches(Visitor *ResultVisitor, const DynTypedNode &RootNode); template bool removeBindings(const ExcludePredicate &Predicate) { diff --git a/clang/lib/ASTMatchers/ASTMatchFinder.cpp b/clang/lib/ASTMatchers/ASTMatchFinder.cpp --- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/clang/lib/ASTMatchers/ASTMatchFinder.cpp @@ -815,7 +815,7 @@ BoundNodesTreeBuilder Builder; if (MP.first.matches(Node, this, &Builder)) { MatchVisitor Visitor(ActiveASTContext, MP.second); - Builder.visitMatches(&Visitor); + Builder.visitMatches(&Visitor, DynTypedNode::create(Node)); } } } @@ -847,7 +847,7 @@ if (MP.first.matches(DynNode, this, &Builder)) { MatchVisitor Visitor(ActiveASTContext, MP.second); - Builder.visitMatches(&Visitor); + Builder.visitMatches(&Visitor, DynNode); } } } diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -98,11 +98,12 @@ /*LookupInDependent =*/true); } -void BoundNodesTreeBuilder::visitMatches(Visitor *ResultVisitor) { +void BoundNodesTreeBuilder::visitMatches(Visitor *ResultVisitor, + const DynTypedNode &RootNode) { if (Bindings.empty()) Bindings.push_back(BoundNodesMap()); for (BoundNodesMap &Binding : Bindings) { - ResultVisitor->visitMatch(BoundNodes(Binding)); + ResultVisitor->visitMatch(BoundNodes(Binding, RootNode)); } }