sammccall created this revision.
sammccall added reviewers: bkramer, klimek.
Herald added a subscriber: cfe-commits.

Prior to r351069, lambda classes were traversed or not depending on the
{Function, Class, Namespace, TU} DeclContext containing them.
If it was a function (common case) they were not traversed.
If it was a namespace or TU (top-level lambda) they were traversed as part of
that DeclContext traversal.

r351069 "fixed" RAV to traverse these as part of the LambdaExpr, which is the
right place. But top-level lambdas are now traversed twice.
We fix that as blocks and block captures were apparently fixed in the past.

Maybe it would be nicer to avoid adding the lambda classes to the DeclContext
in the first place, but I can't work out the implications of that.


Repository:
  rC Clang

https://reviews.llvm.org/D56665

Files:
  include/clang/AST/RecursiveASTVisitor.h
  unittests/Tooling/RecursiveASTVisitorTests/LambdaExpr.cpp


Index: unittests/Tooling/RecursiveASTVisitorTests/LambdaExpr.cpp
===================================================================
--- unittests/Tooling/RecursiveASTVisitorTests/LambdaExpr.cpp
+++ unittests/Tooling/RecursiveASTVisitorTests/LambdaExpr.cpp
@@ -65,6 +65,17 @@
   EXPECT_FALSE(Visitor.allClassesHaveBeenTraversed());
 }
 
+TEST(RecursiveASTVisitor, TopLevelLambda) {
+  LambdaExprVisitor Visitor;
+  Visitor.VisitImplicitCode = true;
+  Visitor.ExpectMatch("", 1, 10);
+  Visitor.ExpectMatch("", 1, 14);
+  EXPECT_TRUE(Visitor.runOver("auto x = []{ [] {}; };",
+                              LambdaExprVisitor::Lang_CXX11));
+  EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed());
+  EXPECT_TRUE(Visitor.allClassesHaveBeenTraversed());
+}
+
 TEST(RecursiveASTVisitor, VisitsLambdaExprAndImplicitClass) {
   LambdaExprVisitor Visitor;
   Visitor.VisitImplicitCode = true;
Index: include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- include/clang/AST/RecursiveASTVisitor.h
+++ include/clang/AST/RecursiveASTVisitor.h
@@ -1368,9 +1368,14 @@
 template <typename Derived>
 bool 
RecursiveASTVisitor<Derived>::canIgnoreChildDeclWhileTraversingDeclContext(
     const Decl *Child) {
-  // BlockDecls and CapturedDecls are traversed through BlockExprs and
-  // CapturedStmts respectively.
-  return isa<BlockDecl>(Child) || isa<CapturedDecl>(Child);
+  // BlockDecls are traversed through BlockExprs,
+  // CapturedDecls are traversed through CapturedStmts.
+  if (isa<BlockDecl>(Child) || isa<CapturedDecl>(Child))
+    return true;
+  // Lambda classes are traversed through LambdaExprs.
+  if (const CXXRecordDecl* Cls = dyn_cast<CXXRecordDecl>(Child))
+    return Cls->isLambda();
+  return false;
 }
 
 template <typename Derived>


Index: unittests/Tooling/RecursiveASTVisitorTests/LambdaExpr.cpp
===================================================================
--- unittests/Tooling/RecursiveASTVisitorTests/LambdaExpr.cpp
+++ unittests/Tooling/RecursiveASTVisitorTests/LambdaExpr.cpp
@@ -65,6 +65,17 @@
   EXPECT_FALSE(Visitor.allClassesHaveBeenTraversed());
 }
 
+TEST(RecursiveASTVisitor, TopLevelLambda) {
+  LambdaExprVisitor Visitor;
+  Visitor.VisitImplicitCode = true;
+  Visitor.ExpectMatch("", 1, 10);
+  Visitor.ExpectMatch("", 1, 14);
+  EXPECT_TRUE(Visitor.runOver("auto x = []{ [] {}; };",
+                              LambdaExprVisitor::Lang_CXX11));
+  EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed());
+  EXPECT_TRUE(Visitor.allClassesHaveBeenTraversed());
+}
+
 TEST(RecursiveASTVisitor, VisitsLambdaExprAndImplicitClass) {
   LambdaExprVisitor Visitor;
   Visitor.VisitImplicitCode = true;
Index: include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- include/clang/AST/RecursiveASTVisitor.h
+++ include/clang/AST/RecursiveASTVisitor.h
@@ -1368,9 +1368,14 @@
 template <typename Derived>
 bool RecursiveASTVisitor<Derived>::canIgnoreChildDeclWhileTraversingDeclContext(
     const Decl *Child) {
-  // BlockDecls and CapturedDecls are traversed through BlockExprs and
-  // CapturedStmts respectively.
-  return isa<BlockDecl>(Child) || isa<CapturedDecl>(Child);
+  // BlockDecls are traversed through BlockExprs,
+  // CapturedDecls are traversed through CapturedStmts.
+  if (isa<BlockDecl>(Child) || isa<CapturedDecl>(Child))
+    return true;
+  // Lambda classes are traversed through LambdaExprs.
+  if (const CXXRecordDecl* Cls = dyn_cast<CXXRecordDecl>(Child))
+    return Cls->isLambda();
+  return false;
 }
 
 template <typename Derived>
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to