]> granicus.if.org Git - clang/commitdiff
[AST] Fix double-traversal of code in top-level lambdas in RAV(implicit = yes).
authorSam McCall <sam.mccall@gmail.com>
Mon, 14 Jan 2019 17:16:00 +0000 (17:16 +0000)
committerSam McCall <sam.mccall@gmail.com>
Mon, 14 Jan 2019 17:16:00 +0000 (17:16 +0000)
Summary:
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.

Reviewers: bkramer, klimek

Subscribers: cfe-commits

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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@351075 91177308-0d34-0410-b5e6-96231b3b80d8

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

index 96f3d24c6db8ec2600f9ff3b48bb0332a33c61d1..44aba63557585b6097ec8c635ad0e9d776b798af 100644 (file)
@@ -1368,9 +1368,14 @@ DEF_TRAVERSE_TYPELOC(PipeType, { TRY_TO(TraverseTypeLoc(TL.getValueLoc())); })
 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 a965632153fae6ac87e1cbfbab771738c8a256f5..d3a3eba15d166e9e94d566b81d653e2f9f8f4a7a 100644 (file)
@@ -65,6 +65,17 @@ TEST(RecursiveASTVisitor, LambdaInLambda) {
   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;