njames93 created this revision. njames93 added reviewers: klimek, aaron.ballman, steveire. njames93 published this revision for review. Herald added a project: clang. Herald added a subscriber: cfe-commits.
Most often when using matchers, there is a need to get the root node that the matcher matched on. Currently the only way to do this is to manually create a binding the the root matcher, however this has some drawbacks. It can be prone to typos and there is no universal agreed name to give the root node, so an API that accepts a DynTypedMatcher wont be able to figure out what the root actually is. By altering the infrastructure to always provide access to the node being matched on, that isn't dependent on names, it can simplify workflow a lot. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D97784 Files: clang/include/clang/ASTMatchers/ASTMatchFinder.h clang/include/clang/ASTMatchers/ASTMatchers.h clang/include/clang/ASTMatchers/ASTMatchersInternal.h clang/lib/ASTMatchers/ASTMatchFinder.cpp clang/lib/ASTMatchers/ASTMatchersInternal.cpp
Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp =================================================================== --- clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ 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)); } } Index: clang/lib/ASTMatchers/ASTMatchFinder.cpp =================================================================== --- clang/lib/ASTMatchers/ASTMatchFinder.cpp +++ 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); } } } Index: clang/include/clang/ASTMatchers/ASTMatchersInternal.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ 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 <typename ExcludePredicate> bool removeBindings(const ExcludePredicate &Predicate) { Index: clang/include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchers.h +++ clang/include/clang/ASTMatchers/ASTMatchers.h @@ -125,14 +125,21 @@ return MyBoundNodes.getMap(); } + template <typename T> const T *getRootAs() const { return RootNode.get<T>(); } + + 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 Index: clang/include/clang/ASTMatchers/ASTMatchFinder.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchFinder.h +++ 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<Decl>(match(DeclMatcher, Node, Context)); +/// \endcode +template <typename NodeT> +const NodeT *selectFirst(const SmallVectorImpl<BoundNodes> &Results) { + for (const BoundNodes &N : Results) { + if (const NodeT *Node = N.getRootAs<NodeT>()) + return Node; + } + return nullptr; +} + namespace internal { class CollectMatchesCallback : public MatchFinder::MatchCallback { public:
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits