[cfe-dev] [AST Matcher API] How to match against a subtree?

Gábor Márton via cfe-dev cfe-dev at lists.llvm.org
Wed Jul 25 08:50:59 PDT 2018


Hi,

I'd like to do a traversal on a subtree rooted on a specific node, but
not on the whole tree rooted at the TranslataionUnitDecl. My
understanding is this is not possible today, or is it? I wonder why
this was not missing for anybody.

We can match **one** node against a matcher, but we will not traverse
into the children (this is MatchFinder::match).
Or we can traverse through the whole tree rooted at the TUDecl (this
is MatchFinder::matchAST).

Below, the short draft of my idea how could we support this, what do you think?

Thanks,
Gabor

diff --git a/include/clang/ASTMatchers/ASTMatchFinder.h
b/include/clang/ASTMatchers/ASTMatchFinder.h
index 389af1b..7610074 100644
--- a/include/clang/ASTMatchers/ASTMatchFinder.h
+++ b/include/clang/ASTMatchers/ASTMatchFinder.h
@@ -189,6 +189,15 @@ public:
              ASTContext &Context);
   /// @}

+  /// \brief Finds all matches in the given subtree rooted at \p Node
+  /// @{
+  template <typename T> void matchSubtree(const T &Node, ASTContext &Context) {
+    matchSubtree(clang::ast_type_traits::DynTypedNode::create(Node), Context);
+  }
+  void matchSubtree(const clang::ast_type_traits::DynTypedNode &Node,
+                            ASTContext &Context);
+  /// @}
+
   /// \brief Finds all matches in the given AST.
   void matchAST(ASTContext &Context);

diff --git a/lib/ASTMatchers/ASTMatchFinder.cpp
b/lib/ASTMatchers/ASTMatchFinder.cpp
index 02aee4b..ec37e95 100644
--- a/lib/ASTMatchers/ASTMatchFinder.cpp
+++ b/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -1018,6 +1018,31 @@ void MatchFinder::matchAST(ASTContext &Context) {
   Visitor.onEndOfTranslationUnit();
 }

+void MatchFinder::matchSubtree(const
clang::ast_type_traits::DynTypedNode &Node,
+                            ASTContext &Context) {
+  internal::MatchASTVisitor Visitor(&Matchers, Options);
+  Visitor.set_active_ast_context(&Context);
+  Visitor.onStartOfTranslationUnit(); // Is it needed ???
+  Visitor.TraverseDecl(Context.getTranslationUnitDecl());
+    // FIXME: Improve this with a switch or a visitor pattern.
+    if (auto *N = Node.get<Decl>()) {
+      Visitor.TraverseDecl(const_cast<Decl*>(N));
+    } else if (auto *N = Node.get<Stmt>()) {
+      Visitor.TraverseStmt(const_cast<Stmt*>(N));
+    } else if (auto *N = Node.get<QualType>()) {
+      Visitor.TraverseType(*N);
+    } else if (auto *N = Node.get<TypeLoc>()) {
+      Visitor.TraverseTypeLoc(*N);
+    } else if (auto *N = Node.get<NestedNameSpecifier>()) {
+      Visitor.TraverseNestedNameSpecifier(const_cast<NestedNameSpecifier*>(N));
+    } else if (auto *N = Node.get<NestedNameSpecifierLoc>()) {
+      Visitor.TraverseNestedNameSpecifierLoc(*N);
+    } else if (auto *N = Node.get<CXXCtorInitializer>()) {
+      Visitor.TraverseConstructorInitializer(const_cast<CXXCtorInitializer*>(N));
+    }
+  Visitor.onEndOfTranslationUnit(); // Is it needed ???
+}
+


More information about the cfe-dev mailing list