[clang] 494b131 - Customize simplified dumping and matching of LambdaExpr

Stephen Kelly via cfe-commits cfe-commits at lists.llvm.org
Fri Dec 20 13:13:41 PST 2019


Author: Stephen Kelly
Date: 2019-12-20T21:13:23Z
New Revision: 494b1318ca77927e919bbf9a61749a58553d738c

URL: https://github.com/llvm/llvm-project/commit/494b1318ca77927e919bbf9a61749a58553d738c
DIFF: https://github.com/llvm/llvm-project/commit/494b1318ca77927e919bbf9a61749a58553d738c.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..2a43b4c7049f 100644
--- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -145,7 +145,9 @@ class MatchChildASTVisitor
 
     ScopedIncrement ScopedDepth(&CurrentDepth);
     Stmt *StmtToTraverse = StmtNode;
-    if (auto *ExprNode = dyn_cast_or_null<Expr>(StmtNode))
+    if (auto *ExprNode = dyn_cast_or_null<LambdaExpr>(StmtNode))
+      StmtToTraverse = ExprNode;
+    else if (auto *ExprNode = dyn_cast_or_null<Expr>(StmtNode))
       StmtToTraverse = Finder->getASTContext().traverseIgnored(ExprNode);
     if (Traversal ==
         ast_type_traits::TraversalKind::TK_IgnoreImplicitCastsAndParentheses) {
@@ -203,6 +205,38 @@ class MatchChildASTVisitor
     ScopedIncrement ScopedDepth(&CurrentDepth);
     return traverse(*CtorInit);
   }
+  bool TraverseLambdaExpr(LambdaExpr *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