r278933 - Visit lambda capture inits from RecursiveASTVisitor::TraverseLambdaCapture().

Martin Bohme via cfe-commits cfe-commits at lists.llvm.org
Wed Aug 17 07:59:53 PDT 2016


Author: mboehme
Date: Wed Aug 17 09:59:53 2016
New Revision: 278933

URL: http://llvm.org/viewvc/llvm-project?rev=278933&view=rev
Log:
Visit lambda capture inits from RecursiveASTVisitor::TraverseLambdaCapture().

Summary:
rL277342 made RecursiveASTVisitor visit lambda capture initialization
expressions (these are the Exprs in LambdaExpr::capture_inits()).

jdennett identified two issues with rL277342 (see comments there for details):

- It visits initialization expressions for implicit lambda captures, even if
  shouldVisitImplicitCode() returns false.

- It visits initialization expressions for init captures twice (because these
  were already traveresed in TraverseLambdaCapture() before rL277342)

This patch fixes these issues and moves the code for traversing initialization
expressions into TraverseLambdaCapture().

This patch also makes two changes required for the tests:

- It adds Lang_CXX14 to the Language enum in TestVisitor.

- It adds a parameter to ExpectedLocationVisitor::ExpectMatch() that specifies
  the number of times a match is expected to be seen.

Reviewers: klimek, jdennett, alexfh

Subscribers: cfe-commits

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

Modified:
    cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
    cfe/trunk/lib/Index/IndexBody.cpp
    cfe/trunk/unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
    cfe/trunk/unittests/Tooling/TestVisitor.h

Modified: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=278933&r1=278932&r2=278933&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original)
+++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Wed Aug 17 09:59:53 2016
@@ -264,10 +264,12 @@ public:
   /// \returns false if the visitation was terminated early, true otherwise.
   bool TraverseConstructorInitializer(CXXCtorInitializer *Init);
 
-  /// \brief Recursively visit a lambda capture.
+  /// \brief Recursively visit a lambda capture. \c Init is the expression that
+  /// will be used to initialize the capture.
   ///
   /// \returns false if the visitation was terminated early, true otherwise.
-  bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C);
+  bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,
+                             Expr *Init);
 
   /// \brief Recursively visit the body of a lambda expression.
   ///
@@ -885,9 +887,12 @@ bool RecursiveASTVisitor<Derived>::Trave
 template <typename Derived>
 bool
 RecursiveASTVisitor<Derived>::TraverseLambdaCapture(LambdaExpr *LE,
-                                                    const LambdaCapture *C) {
+                                                    const LambdaCapture *C,
+                                                    Expr *Init) {
   if (LE->isInitCapture(C))
     TRY_TO(TraverseDecl(C->getCapturedVar()));
+  else
+    TRY_TO(TraverseStmt(Init));
   return true;
 }
 
@@ -2261,13 +2266,11 @@ DEF_TRAVERSE_STMT(CXXTemporaryObjectExpr
 
 // Walk only the visible parts of lambda expressions.
 DEF_TRAVERSE_STMT(LambdaExpr, {
-  for (LambdaExpr::capture_iterator C = S->explicit_capture_begin(),
-                                    CEnd = S->explicit_capture_end();
-       C != CEnd; ++C) {
-    TRY_TO(TraverseLambdaCapture(S, C));
-  }
-  for (Expr *Init : S->capture_inits()) {
-    TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(Init);
+  for (unsigned I = 0, N = S->capture_size(); I != N; ++I) {
+    const LambdaCapture *C = S->capture_begin() + I;
+    if (C->isExplicit() || getDerived().shouldVisitImplicitCode()) {
+      TRY_TO(TraverseLambdaCapture(S, C, S->capture_init_begin()[I]));
+    }
   }
 
   TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc();

Modified: cfe/trunk/lib/Index/IndexBody.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Index/IndexBody.cpp?rev=278933&r1=278932&r2=278933&view=diff
==============================================================================
--- cfe/trunk/lib/Index/IndexBody.cpp (original)
+++ cfe/trunk/lib/Index/IndexBody.cpp Wed Aug 17 09:59:53 2016
@@ -276,7 +276,8 @@ public:
     return true;
   }
 
-  bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C) {
+  bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,
+                             Expr *Init) {
     if (C->capturesThis() || C->capturesVLAType())
       return true;
 

Modified: cfe/trunk/unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp?rev=278933&r1=278932&r2=278933&view=diff
==============================================================================
--- cfe/trunk/unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp (original)
+++ cfe/trunk/unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp Wed Aug 17 09:59:53 2016
@@ -161,10 +161,21 @@ TEST(RecursiveASTVisitor, CanSkipImplici
 
 class DeclRefExprVisitor : public ExpectedLocationVisitor<DeclRefExprVisitor> {
 public:
+  DeclRefExprVisitor() : ShouldVisitImplicitCode(false) {}
+
+  bool shouldVisitImplicitCode() const { return ShouldVisitImplicitCode; }
+
+  void setShouldVisitImplicitCode(bool NewValue) {
+    ShouldVisitImplicitCode = NewValue;
+  }
+
   bool VisitDeclRefExpr(DeclRefExpr *Reference) {
     Match(Reference->getNameInfo().getAsString(), Reference->getLocation());
     return true;
   }
+
+private:
+  bool ShouldVisitImplicitCode;
 };
 
 TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArguments) {
@@ -191,14 +202,43 @@ TEST(RecursiveASTVisitor, VisitsCallExpr
     "void x(); void y() { x(); }"));
 }
 
-TEST(RecursiveASTVisitor, VisitsLambdaCaptureInit) {
+TEST(RecursiveASTVisitor, VisitsExplicitLambdaCaptureInit) {
   DeclRefExprVisitor Visitor;
   Visitor.ExpectMatch("i", 1, 20);
   EXPECT_TRUE(Visitor.runOver(
-    "void f() { int i; [i]{}; };",
+    "void f() { int i; [i]{}; }",
+    DeclRefExprVisitor::Lang_CXX11));
+}
+
+TEST(RecursiveASTVisitor, VisitsUseOfImplicitLambdaCapture) {
+  DeclRefExprVisitor Visitor;
+  Visitor.ExpectMatch("i", 1, 24);
+  EXPECT_TRUE(Visitor.runOver(
+    "void f() { int i; [=]{ i; }; }",
     DeclRefExprVisitor::Lang_CXX11));
 }
 
+TEST(RecursiveASTVisitor, VisitsImplicitLambdaCaptureInit) {
+  DeclRefExprVisitor Visitor;
+  Visitor.setShouldVisitImplicitCode(true);
+  // We're expecting the "i" in the lambda to be visited twice:
+  // - Once for the DeclRefExpr in the lambda capture initialization (whose
+  //   source code location is set to the first use of the variable).
+  // - Once for the DeclRefExpr for the use of "i" inside the lambda.
+  Visitor.ExpectMatch("i", 1, 24, /*Times=*/2);
+  EXPECT_TRUE(Visitor.runOver(
+    "void f() { int i; [=]{ i; }; }",
+    DeclRefExprVisitor::Lang_CXX11));
+}
+
+TEST(RecursiveASTVisitor, VisitsLambdaInitCaptureInit) {
+  DeclRefExprVisitor Visitor;
+  Visitor.ExpectMatch("i", 1, 24);
+  EXPECT_TRUE(Visitor.runOver(
+    "void f() { int i; [a = i + 1]{}; }",
+    DeclRefExprVisitor::Lang_CXX14));
+}
+
 /* FIXME: According to Richard Smith this is a bug in the AST.
 TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArgumentsInInstantiation) {
   DeclRefExprVisitor Visitor;

Modified: cfe/trunk/unittests/Tooling/TestVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Tooling/TestVisitor.h?rev=278933&r1=278932&r2=278933&view=diff
==============================================================================
--- cfe/trunk/unittests/Tooling/TestVisitor.h (original)
+++ cfe/trunk/unittests/Tooling/TestVisitor.h Wed Aug 17 09:59:53 2016
@@ -43,6 +43,7 @@ public:
     Lang_C,
     Lang_CXX98,
     Lang_CXX11,
+    Lang_CXX14,
     Lang_OBJC,
     Lang_OBJCXX11,
     Lang_CXX = Lang_CXX98
@@ -55,6 +56,7 @@ public:
       case Lang_C: Args.push_back("-std=c99"); break;
       case Lang_CXX98: Args.push_back("-std=c++98"); break;
       case Lang_CXX11: Args.push_back("-std=c++11"); break;
+      case Lang_CXX14: Args.push_back("-std=c++14"); break;
       case Lang_OBJC: Args.push_back("-ObjC"); break;
       case Lang_OBJCXX11:
         Args.push_back("-ObjC++");
@@ -127,9 +129,12 @@ public:
   /// \brief Expect 'Match' to occur at the given 'Line' and 'Column'.
   ///
   /// Any number of expected matches can be set by calling this repeatedly.
-  /// Each is expected to be matched exactly once.
-  void ExpectMatch(Twine Match, unsigned Line, unsigned Column) {
-    ExpectedMatches.push_back(ExpectedMatch(Match, Line, Column));
+  /// Each is expected to be matched 'Times' number of times. (This is useful in
+  /// cases in which different AST nodes can match at the same source code
+  /// location.)
+  void ExpectMatch(Twine Match, unsigned Line, unsigned Column,
+                   unsigned Times = 1) {
+    ExpectedMatches.push_back(ExpectedMatch(Match, Line, Column, Times));
   }
 
   /// \brief Checks that all expected matches have been found.
@@ -200,14 +205,17 @@ protected:
   };
 
   struct ExpectedMatch {
-    ExpectedMatch(Twine Name, unsigned LineNumber, unsigned ColumnNumber)
-      : Candidate(Name, LineNumber, ColumnNumber), Found(false) {}
+    ExpectedMatch(Twine Name, unsigned LineNumber, unsigned ColumnNumber,
+                  unsigned Times)
+        : Candidate(Name, LineNumber, ColumnNumber), TimesExpected(Times),
+          TimesSeen(0) {}
 
     void UpdateFor(StringRef Name, FullSourceLoc Location, SourceManager &SM) {
       if (Candidate.Matches(Name, Location)) {
-        EXPECT_TRUE(!Found);
-        Found = true;
-      } else if (!Found && Candidate.PartiallyMatches(Name, Location)) {
+        EXPECT_LT(TimesSeen, TimesExpected);
+        ++TimesSeen;
+      } else if (TimesSeen < TimesExpected &&
+                 Candidate.PartiallyMatches(Name, Location)) {
         llvm::raw_string_ostream Stream(PartialMatches);
         Stream << ", partial match: \"" << Name << "\" at ";
         Location.print(Stream, SM);
@@ -215,7 +223,7 @@ protected:
     }
 
     void ExpectFound() const {
-      EXPECT_TRUE(Found)
+      EXPECT_EQ(TimesExpected, TimesSeen)
           << "Expected \"" << Candidate.ExpectedName
           << "\" at " << Candidate.LineNumber
           << ":" << Candidate.ColumnNumber << PartialMatches;
@@ -223,7 +231,8 @@ protected:
 
     MatchCandidate Candidate;
     std::string PartialMatches;
-    bool Found;
+    unsigned TimesExpected;
+    unsigned TimesSeen;
   };
 
   std::vector<MatchCandidate> DisallowedMatches;




More information about the cfe-commits mailing list