[clang] 5a79cfa - Customize simplified dumping and matching of LambdaExpr

Stephen Kelly via cfe-commits cfe-commits at lists.llvm.org
Sat Dec 21 03:03:07 PST 2019


Author: Stephen Kelly
Date: 2019-12-21T11:02:11Z
New Revision: 5a79cfa32d62f018607438a30b7acb49c2ab97f3

URL: https://github.com/llvm/llvm-project/commit/5a79cfa32d62f018607438a30b7acb49c2ab97f3
DIFF: https://github.com/llvm/llvm-project/commit/5a79cfa32d62f018607438a30b7acb49c2ab97f3.diff

LOG: Customize simplified dumping and matching of LambdaExpr

Reviewers: aaron.ballman

Subscribers: cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D71680

Added: 
    

Modified: 
    clang/include/clang/AST/ASTNodeTraverser.h
    clang/lib/ASTMatchers/ASTMatchFinder.cpp
    clang/unittests/AST/ASTTraverserTest.cpp
    clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h
index f097d024c9e8..9dab814b659b 100644
--- a/clang/include/clang/AST/ASTNodeTraverser.h
+++ b/clang/include/clang/AST/ASTNodeTraverser.h
@@ -128,9 +128,12 @@ class ASTNodeTraverser
       ConstStmtVisitor<Derived>::Visit(S);
 
       // Some statements have custom mechanisms for dumping their children.
-      if (isa<DeclStmt>(S) || isa<GenericSelectionExpr>(S)) {
+      if (isa<DeclStmt>(S) || isa<GenericSelectionExpr>(S))
+        return;
+
+      if (isa<LambdaExpr>(S) &&
+          Traversal == ast_type_traits::TK_IgnoreUnlessSpelledInSource)
         return;
-      }
 
       for (const Stmt *SubStmt : S->children())
         Visit(SubStmt);
@@ -646,7 +649,23 @@ class ASTNodeTraverser
   }
 
   void VisitLambdaExpr(const LambdaExpr *Node) {
-    Visit(Node->getLambdaClass());
+    if (Traversal == ast_type_traits::TK_IgnoreUnlessSpelledInSource) {
+      for (unsigned I = 0, N = Node->capture_size(); I != N; ++I) {
+        const auto *C = Node->capture_begin() + I;
+        if (!C->isExplicit())
+          continue;
+        if (Node->isInitCapture(C))
+          Visit(C->getCapturedVar());
+        else
+          Visit(Node->capture_init_begin()[I]);
+      }
+      dumpTemplateParameters(Node->getTemplateParameterList());
+      for (const auto *P : Node->getCallOperator()->parameters())
+        Visit(P);
+      Visit(Node->getBody());
+    } else {
+      return Visit(Node->getLambdaClass());
+    }
   }
 
   void VisitSizeOfPackExpr(const SizeOfPackExpr *Node) {

diff  --git a/clang/lib/ASTMatchers/ASTMatchFinder.cpp b/clang/lib/ASTMatchers/ASTMatchFinder.cpp
index 8ac35d522843..ab90c745791c 100644
--- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -138,20 +138,32 @@ class MatchChildASTVisitor
     ScopedIncrement ScopedDepth(&CurrentDepth);
     return (DeclNode == nullptr) || traverse(*DeclNode);
   }
-  bool TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue = nullptr) {
-    // If we need to keep track of the depth, we can't perform data recursion.
-    if (CurrentDepth == 0 || (CurrentDepth <= MaxDepth && MaxDepth < INT_MAX))
-      Queue = nullptr;
 
-    ScopedIncrement ScopedDepth(&CurrentDepth);
+  Stmt *getStmtToTraverse(Stmt *StmtNode) {
     Stmt *StmtToTraverse = StmtNode;
-    if (auto *ExprNode = dyn_cast_or_null<Expr>(StmtNode))
-      StmtToTraverse = Finder->getASTContext().traverseIgnored(ExprNode);
+    if (auto *ExprNode = dyn_cast_or_null<Expr>(StmtNode)) {
+      auto *LambdaNode = dyn_cast_or_null<LambdaExpr>(StmtNode);
+      if (LambdaNode && Finder->getASTContext().getTraversalKind() ==
+                          ast_type_traits::TK_IgnoreUnlessSpelledInSource)
+        StmtToTraverse = LambdaNode;
+      else
+        StmtToTraverse = Finder->getASTContext().traverseIgnored(ExprNode);
+    }
     if (Traversal ==
         ast_type_traits::TraversalKind::TK_IgnoreImplicitCastsAndParentheses) {
       if (Expr *ExprNode = dyn_cast_or_null<Expr>(StmtNode))
         StmtToTraverse = ExprNode->IgnoreParenImpCasts();
     }
+    return StmtToTraverse;
+  }
+
+  bool TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue = nullptr) {
+    // If we need to keep track of the depth, we can't perform data recursion.
+    if (CurrentDepth == 0 || (CurrentDepth <= MaxDepth && MaxDepth < INT_MAX))
+      Queue = nullptr;
+
+    ScopedIncrement ScopedDepth(&CurrentDepth);
+    Stmt *StmtToTraverse = getStmtToTraverse(StmtNode);
     if (!StmtToTraverse)
       return true;
     if (!match(*StmtToTraverse))
@@ -203,6 +215,41 @@ class MatchChildASTVisitor
     ScopedIncrement ScopedDepth(&CurrentDepth);
     return traverse(*CtorInit);
   }
+  bool TraverseLambdaExpr(LambdaExpr *Node) {
+    if (Finder->getASTContext().getTraversalKind() !=
+        ast_type_traits::TK_IgnoreUnlessSpelledInSource)
+      return VisitorBase::TraverseLambdaExpr(Node);
+    if (!Node)
+      return true;
+    ScopedIncrement ScopedDepth(&CurrentDepth);
+
+    for (unsigned I = 0, N = Node->capture_size(); I != N; ++I) {
+      const auto *C = Node->capture_begin() + I;
+      if (!C->isExplicit())
+        continue;
+      if (Node->isInitCapture(C) && !match(*C->getCapturedVar()))
+        return false;
+      if (!match(*Node->capture_init_begin()[I]))
+        return false;
+    }
+
+    if (const auto *TPL = Node->getTemplateParameterList()) {
+      for (const auto *TP : *TPL) {
+        if (!match(*TP))
+          return false;
+      }
+    }
+
+    for (const auto *P : Node->getCallOperator()->parameters()) {
+      if (!match(*P))
+        return false;
+    }
+
+    if (!match(*Node->getBody()))
+      return false;
+
+    return false;
+  }
 
   bool shouldVisitTemplateInstantiations() const { return true; }
   bool shouldVisitImplicitCode() const { return true; }

diff  --git a/clang/unittests/AST/ASTTraverserTest.cpp b/clang/unittests/AST/ASTTraverserTest.cpp
index c995f55d3c89..4b982431297c 100644
--- a/clang/unittests/AST/ASTTraverserTest.cpp
+++ b/clang/unittests/AST/ASTTraverserTest.cpp
@@ -479,4 +479,123 @@ FunctionDecl 'func12'
 )cpp");
 }
 
+TEST(Traverse, LambdaUnlessSpelledInSource) {
+
+  auto AST =
+      buildASTFromCodeWithArgs(R"cpp(
+
+void captures() {
+  int a = 0;
+  int b = 0;
+  int d = 0;
+  int f = 0;
+
+  [a, &b, c = d, &e = f](int g, int h = 42) {};
+}
+
+void templated() {
+  int a = 0;
+  [a]<typename T>(T t) {};
+}
+
+struct SomeStruct {
+    int a = 0;
+    void capture_this() {
+        [this]() {};
+    }
+    void capture_this_copy() {
+        [self = *this]() {};
+    }
+};
+)cpp",
+                               {"-Wno-unused-value", "-Wno-c++2a-extensions"});
+
+  auto getLambdaNode = [&AST](const std::string &name) {
+    auto BN = ast_matchers::match(
+        lambdaExpr(hasAncestor(functionDecl(hasName(name)))).bind("lambda"),
+        AST->getASTContext());
+    EXPECT_EQ(BN.size(), 1u);
+    return BN[0].getNodeAs<LambdaExpr>("lambda");
+  };
+
+  {
+    auto L = getLambdaNode("captures");
+
+    EXPECT_EQ(dumpASTString(ast_type_traits::TK_IgnoreUnlessSpelledInSource, L),
+              R"cpp(
+LambdaExpr
+|-DeclRefExpr 'a'
+|-DeclRefExpr 'b'
+|-VarDecl 'c'
+| `-DeclRefExpr 'd'
+|-VarDecl 'e'
+| `-DeclRefExpr 'f'
+|-ParmVarDecl 'g'
+|-ParmVarDecl 'h'
+| `-IntegerLiteral
+`-CompoundStmt
+)cpp");
+
+    EXPECT_EQ(dumpASTString(ast_type_traits::TK_AsIs, L),
+              R"cpp(
+LambdaExpr
+|-CXXRecordDecl ''
+| |-CXXMethodDecl 'operator()'
+| | |-ParmVarDecl 'g'
+| | |-ParmVarDecl 'h'
+| | | `-IntegerLiteral
+| | `-CompoundStmt
+| |-FieldDecl ''
+| |-FieldDecl ''
+| |-FieldDecl ''
+| |-FieldDecl ''
+| `-CXXDestructorDecl '~'
+|-ImplicitCastExpr
+| `-DeclRefExpr 'a'
+|-DeclRefExpr 'b'
+|-ImplicitCastExpr
+| `-DeclRefExpr 'd'
+|-DeclRefExpr 'f'
+`-CompoundStmt
+)cpp");
+  }
+
+  {
+    auto L = getLambdaNode("templated");
+
+    EXPECT_EQ(dumpASTString(ast_type_traits::TK_IgnoreUnlessSpelledInSource, L),
+              R"cpp(
+LambdaExpr
+|-DeclRefExpr 'a'
+|-TemplateTypeParmDecl 'T'
+|-ParmVarDecl 't'
+`-CompoundStmt
+)cpp");
+  }
+
+  {
+    auto L = getLambdaNode("capture_this");
+
+    EXPECT_EQ(dumpASTString(ast_type_traits::TK_IgnoreUnlessSpelledInSource, L),
+              R"cpp(
+LambdaExpr
+|-CXXThisExpr
+`-CompoundStmt
+)cpp");
+  }
+
+  {
+    auto L = getLambdaNode("capture_this_copy");
+
+    EXPECT_EQ(dumpASTString(ast_type_traits::TK_IgnoreUnlessSpelledInSource, L),
+              R"cpp(
+LambdaExpr
+|-VarDecl 'self'
+| `-UnaryOperator
+|   `-CXXThisExpr
+`-CompoundStmt
+)cpp");
+  }
+}
+
 } // namespace clang

diff  --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
index a21ed04b32d4..b9075927d745 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -1751,6 +1751,17 @@ B func12() {
   return c;
 }
 
+void func13() {
+  int a = 0;
+  int c = 0;
+
+  [a, b = c](int d) { int e = d; };
+}
+
+void func14() {
+  [] <typename TemplateType> (TemplateType t, TemplateType u) { int e = t + u; };
+}
+
 )cpp";
 
   EXPECT_TRUE(matches(
@@ -1821,6 +1832,23 @@ B func12() {
                      returnStmt(forFunction(functionDecl(hasName("func12"))),
                                 hasReturnValue(
                                     declRefExpr(to(varDecl(hasName("c")))))))));
+
+  EXPECT_TRUE(matches(
+      Code,
+      traverse(
+          ast_type_traits::TK_IgnoreUnlessSpelledInSource,
+          lambdaExpr(forFunction(functionDecl(hasName("func13"))),
+                     has(compoundStmt(hasDescendant(varDecl(hasName("e"))))),
+                     has(declRefExpr(to(varDecl(hasName("a"))))),
+                     has(varDecl(hasName("b"), hasInitializer(declRefExpr(to(
+                                                   varDecl(hasName("c"))))))),
+                     has(parmVarDecl(hasName("d")))))));
+
+  EXPECT_TRUE(matches(
+      Code, traverse(ast_type_traits::TK_IgnoreUnlessSpelledInSource,
+                     lambdaExpr(
+                         forFunction(functionDecl(hasName("func14"))),
+                         has(templateTypeParmDecl(hasName("TemplateType")))))));
 }
 
 TEST(IgnoringImpCasts, MatchesImpCasts) {


        


More information about the cfe-commits mailing list