[cfe-commits] r150549 - in /cfe/trunk: include/clang-c/Index.h include/clang/AST/RecursiveASTVisitor.h test/Index/cxx11-lambdas.cpp tools/libclang/CIndex.cpp tools/libclang/CXCursor.cpp tools/libclang/CXCursor.h tools/libclang/CXType.cpp tools/libclang/CursorVisitor.h tools/libclang/IndexBody.cpp tools/libclang/IndexingContext.cpp

Douglas Gregor dgregor at apple.com
Tue Feb 14 16:54:55 PST 2012


Author: dgregor
Date: Tue Feb 14 18:54:55 2012
New Revision: 150549

URL: http://llvm.org/viewvc/llvm-project?rev=150549&view=rev
Log:
Implement indexing support for lambdas in libclang (both kinds), as
well as improving the RecursiveASTVisitor's walk of lambda
expressions.

Added:
    cfe/trunk/test/Index/cxx11-lambdas.cpp
Modified:
    cfe/trunk/include/clang-c/Index.h
    cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
    cfe/trunk/tools/libclang/CIndex.cpp
    cfe/trunk/tools/libclang/CXCursor.cpp
    cfe/trunk/tools/libclang/CXCursor.h
    cfe/trunk/tools/libclang/CXType.cpp
    cfe/trunk/tools/libclang/CursorVisitor.h
    cfe/trunk/tools/libclang/IndexBody.cpp
    cfe/trunk/tools/libclang/IndexingContext.cpp

Modified: cfe/trunk/include/clang-c/Index.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang-c/Index.h?rev=150549&r1=150548&r2=150549&view=diff
==============================================================================
--- cfe/trunk/include/clang-c/Index.h (original)
+++ cfe/trunk/include/clang-c/Index.h Tue Feb 14 18:54:55 2012
@@ -1500,7 +1500,13 @@
    */
   CXCursor_OverloadedDeclRef             = 49,
   
-  CXCursor_LastRef                       = CXCursor_OverloadedDeclRef,
+  /**
+   * \brief A reference to a variable that occurs in some non-expression 
+   * context, e.g., a C++ lambda capture list.
+   */
+  CXCursor_VariableRef                   = 50,
+  
+  CXCursor_LastRef                       = CXCursor_VariableRef,
 
   /* Error conditions */
   CXCursor_FirstInvalid                  = 70,
@@ -1746,7 +1752,21 @@
    */
   CXCursor_SizeOfPackExpr                = 143,
 
-  CXCursor_LastExpr                      = CXCursor_SizeOfPackExpr,
+  /* \brief Represents a C++ lambda expression that produces a local function
+   * object.
+   *
+   * \code
+   * void abssort(float *x, unsigned N) {
+   *   std::sort(x, x + N,
+   *             [](float a, float b) {
+   *               return std::abs(a) < std::abs(b);
+   *             });
+   * }
+   * \endcode
+   */
+  CXCursor_LambdaExpr                    = 144,
+  
+  CXCursor_LastExpr                      = CXCursor_LambdaExpr,
 
   /* Statements */
   CXCursor_FirstStmt                     = 200,

Modified: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=150549&r1=150548&r2=150549&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original)
+++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Tue Feb 14 18:54:55 2012
@@ -228,6 +228,11 @@
   /// \returns false if the visitation was terminated early, true otherwise.
   bool TraverseConstructorInitializer(CXXCtorInitializer *Init);
 
+  /// \brief Recursively visit a lambda capture.
+  ///
+  /// \returns false if the visitation was terminated early, true otherwise.
+  bool TraverseLambdaCapture(LambdaExpr::Capture C);
+  
   // ---- Methods on Stmts ----
 
   // Declare Traverse*() for all concrete Stmt classes.
@@ -675,6 +680,10 @@
   return true;
 }
 
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseLambdaCapture(LambdaExpr::Capture C){
+  return true;
+}
 
 // ----------------- Type traversal -----------------
 
@@ -1953,9 +1962,36 @@
     TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc()));
   })
 
-DEF_TRAVERSE_STMT(LambdaExpr, {
-    TRY_TO(TraverseStmt(S->getBody()));
-  })
+// Walk only the visible parts of lambda expressions.  
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) {
+  for (LambdaExpr::capture_iterator C = S->explicit_capture_begin(),
+                                 CEnd = S->explicit_capture_end();
+       C != CEnd; ++C) {
+    TRY_TO(TraverseLambdaCapture(*C));
+  }
+
+  if (S->hasExplicitParameters() || S->hasExplicitResultType()) {
+    TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
+    if (S->hasExplicitParameters() && S->hasExplicitResultType()) {
+      // Visit the whole type.
+      TRY_TO(TraverseTypeLoc(TL));
+    } else if (isa<FunctionProtoTypeLoc>(TL)) {
+      FunctionProtoTypeLoc Proto = cast<FunctionProtoTypeLoc>(TL);
+      if (S->hasExplicitParameters()) {
+        // Visit parameters.
+        for (unsigned I = 0, N = Proto.getNumArgs(); I != N; ++I) {
+          TRY_TO(TraverseDecl(Proto.getArg(I)));
+        }
+      } else {
+        TRY_TO(TraverseTypeLoc(Proto.getResultLoc()));
+      }        
+    }
+  }
+
+  TRY_TO(TraverseStmt(S->getBody()));
+  return true;
+}
 
 DEF_TRAVERSE_STMT(CXXUnresolvedConstructExpr, {
     // This is called for code like 'T()', where T is a template argument.

Added: cfe/trunk/test/Index/cxx11-lambdas.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/cxx11-lambdas.cpp?rev=150549&view=auto
==============================================================================
--- cfe/trunk/test/Index/cxx11-lambdas.cpp (added)
+++ cfe/trunk/test/Index/cxx11-lambdas.cpp Tue Feb 14 18:54:55 2012
@@ -0,0 +1,33 @@
+// Test is line- and column-sensitive; see below.
+
+typedef int Integer;
+struct X {
+  void f() {
+    int localA, localB;
+    auto lambda = [&localA, localB] (Integer x) -> Integer {
+      return localA + localB + x;
+    };
+  }
+};
+
+// RUN: c-index-test -test-load-source all -std=c++11 %s | FileCheck -check-prefix=CHECK-LOAD %s
+// CHECK-LOAD: cxx11-lambdas.cpp:7:19: LambdaExpr= Extent=[7:19 - 9:6]
+// CHECK-LOAD: cxx11-lambdas.cpp:7:21: VariableRef=localA:6:9 Extent=[7:21 - 7:27]
+// CHECK-LOAD: cxx11-lambdas.cpp:7:29: VariableRef=localB:6:17 Extent=[7:29 - 7:35]
+// CHECK-LOAD: cxx11-lambdas.cpp:7:52: TypeRef=Integer:3:13 Extent=[7:52 - 7:59]
+// CHECK-LOAD: cxx11-lambdas.cpp:7:46: ParmDecl=x:7:46 (Definition) Extent=[7:38 - 7:47]
+// CHECK-LOAD: cxx11-lambdas.cpp:7:38: TypeRef=Integer:3:13 Extent=[7:38 - 7:45]
+// CHECK-LOAD: cxx11-lambdas.cpp:7:60: CompoundStmt= Extent=[7:60 - 9:6]
+// CHECK-LOAD: cxx11-lambdas.cpp:8:7: ReturnStmt= Extent=[8:7 - 8:33]
+// CHECK-LOAD: cxx11-lambdas.cpp:8:14: DeclRefExpr=localA:6:9 Extent=[8:14 - 8:20]
+// CHECK-LOAD: cxx11-lambdas.cpp:8:23: DeclRefExpr=localB:6:17 Extent=[8:23 - 8:29]
+// CHECK-LOAD: cxx11-lambdas.cpp:8:32: DeclRefExpr=x:7:46 Extent=[8:32 - 8:33]
+
+// RUN: env CINDEXTEST_INDEXLOCALSYMBOLS=1 c-index-test -index-file -std=c++11 %s | FileCheck -check-prefix=CHECK-INDEX %s
+// CHECK-INDEX: [indexEntityReference]: kind: variable | name: localA | USR: c:cxx11-lambdas.cpp at 100@S at X@F at f#@localA | lang: C | cursor: VariableRef=localA:6:9 | loc: 7:21
+// CHECK-INDEX: [indexEntityReference]: kind: variable | name: localB | USR: c:cxx11-lambdas.cpp at 100@S at X@F at f#@localB | lang: C | cursor: VariableRef=localB:6:17 | loc: 7:29
+// CHECK-INDEX: [indexEntityReference]: kind: typedef | name: Integer | USR: c:cxx11-lambdas.cpp at 51@T at Integer | lang: C | cursor: TypeRef=Integer:3:13 | loc: 7:52
+// CHECK-INDEX: [indexEntityReference]: kind: typedef | name: Integer | USR: c:cxx11-lambdas.cpp at 51@T at Integer | lang: C | cursor: TypeRef=Integer:3:13 | loc: 7:38
+// CHECK-INDEX: [indexEntityReference]: kind: variable | name: localA | USR: c:cxx11-lambdas.cpp at 100@S at X@F at f#@localA | lang: C | cursor: DeclRefExpr=localA:6:9 | loc: 8:14
+// CHECK-INDEX: [indexEntityReference]: kind: variable | name: localB | USR: c:cxx11-lambdas.cpp at 100@S at X@F at f#@localB | lang: C | cursor: DeclRefExpr=localB:6:17 | loc: 8:23
+// CHECK-INDEX: [indexEntityReference]: kind: variable | name: x | USR: c:cxx11-lambdas.cpp at 157@S at X@F at f#@Ca at F@operator()#I#1 at x | lang: C | cursor: DeclRefExpr=x:7:46 | loc: 8:32

Modified: cfe/trunk/tools/libclang/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=150549&r1=150548&r2=150549&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CIndex.cpp (original)
+++ cfe/trunk/tools/libclang/CIndex.cpp Tue Feb 14 18:54:55 2012
@@ -1615,6 +1615,7 @@
 DEF_JOB(ExplicitTemplateArgsVisit, ASTTemplateArgumentListInfo, 
         ExplicitTemplateArgsVisitKind)
 DEF_JOB(SizeOfPackExprParts, SizeOfPackExpr, SizeOfPackExprPartsKind)
+DEF_JOB(LambdaExprParts, LambdaExpr, LambdaExprPartsKind)
 #undef DEF_JOB
 
 class DeclVisit : public VisitorJob {
@@ -1761,6 +1762,7 @@
   void VisitSizeOfPackExpr(SizeOfPackExpr *E);
   void VisitPseudoObjectExpr(PseudoObjectExpr *E);
   void VisitOpaqueValueExpr(OpaqueValueExpr *E);
+  void VisitLambdaExpr(LambdaExpr *E);
   
 private:
   void AddDeclarationNameInfo(Stmt *S);
@@ -2081,6 +2083,10 @@
   if (Expr *SourceExpr = E->getSourceExpr())
     return Visit(SourceExpr);
 }
+void EnqueueVisitor::VisitLambdaExpr(LambdaExpr *E) {
+  AddStmt(E->getBody());
+  WL.push_back(LambdaExprParts(E, Parent));
+}
 void EnqueueVisitor::VisitPseudoObjectExpr(PseudoObjectExpr *E) {
   // Treat the expression like its syntactic form.
   Visit(E->getSyntacticForm());
@@ -2258,6 +2264,45 @@
         // treated like DeclRefExpr cursors.
         continue;
       }
+        
+      case VisitorJob::LambdaExprPartsKind: {
+        // Visit captures.
+        LambdaExpr *E = cast<LambdaExprParts>(&LI)->get();
+        for (LambdaExpr::capture_iterator C = E->explicit_capture_begin(),
+                                       CEnd = E->explicit_capture_end();
+             C != CEnd; ++C) {
+          if (C->capturesThis())
+            continue;
+          
+          if (Visit(MakeCursorVariableRef(C->getCapturedVar(),
+                                          C->getLocation(),
+                                          TU)))
+            return true;
+        }
+        
+        // Visit parameters and return type, if present.
+        if (E->hasExplicitParameters() || E->hasExplicitResultType()) {
+          TypeLoc TL = E->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
+          if (E->hasExplicitParameters() && E->hasExplicitResultType()) {
+            // Visit the whole type.
+            if (Visit(TL))
+              return true;
+          } else if (isa<FunctionProtoTypeLoc>(TL)) {
+            FunctionProtoTypeLoc Proto = cast<FunctionProtoTypeLoc>(TL);
+            if (E->hasExplicitParameters()) {
+              // Visit parameters.
+              for (unsigned I = 0, N = Proto.getNumArgs(); I != N; ++I)
+                if (Visit(MakeCXCursor(Proto.getArg(I), TU)))
+                  return true;
+            } else {
+              // Visit result type.
+              if (Visit(Proto.getResultLoc()))
+                return true;
+            }
+          }
+        }
+        break;
+      }
     }
   }
   return false;
@@ -2980,6 +3025,13 @@
       return createCXString((*Ovl->begin())->getNameAsString());
     }
         
+    case CXCursor_VariableRef: {
+      VarDecl *Var = getCursorVariableRef(C).first;
+      assert(Var && "Missing variable decl");
+      
+      return createCXString(Var->getNameAsString());
+    }
+        
     default:
       return createCXString("<not implemented>");
     }
@@ -3173,6 +3225,8 @@
     return createCXString("LabelRef");
   case CXCursor_OverloadedDeclRef:
     return createCXString("OverloadedDeclRef");
+  case CXCursor_VariableRef:
+    return createCXString("VariableRef");
   case CXCursor_IntegerLiteral:
       return createCXString("IntegerLiteral");
   case CXCursor_FloatingLiteral:
@@ -3251,6 +3305,8 @@
       return createCXString("PackExpansionExpr");
   case CXCursor_SizeOfPackExpr:
       return createCXString("SizeOfPackExpr");
+  case CXCursor_LambdaExpr:
+    return createCXString("LambdaExpr");
   case CXCursor_UnexposedExpr:
       return createCXString("UnexposedExpr");
   case CXCursor_DeclRefExpr:
@@ -3626,6 +3682,11 @@
       return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
     }
 
+    case CXCursor_VariableRef: {
+      std::pair<VarDecl *, SourceLocation> P = getCursorVariableRef(C);
+      return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
+    }
+
     case CXCursor_CXXBaseSpecifier: {
       CXXBaseSpecifier *BaseSpec = getCursorCXXBaseSpecifier(C);
       if (!BaseSpec)
@@ -3768,6 +3829,9 @@
     case CXCursor_OverloadedDeclRef:
       return getCursorOverloadedDeclRef(C).second;
 
+    case CXCursor_VariableRef:
+      return getCursorVariableRef(C).second;
+        
     default:
       // FIXME: Need a way to enumerate all non-reference cases.
       llvm_unreachable("Missed a reference kind");
@@ -3975,6 +4039,9 @@
 
     case CXCursor_OverloadedDeclRef:
       return C;
+      
+    case CXCursor_VariableRef:
+      return MakeCXCursor(getCursorVariableRef(C).first, tu);
 
     default:
       // We would prefer to enumerate all non-reference cursor kinds here.

Modified: cfe/trunk/tools/libclang/CXCursor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXCursor.cpp?rev=150549&r1=150548&r2=150549&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CXCursor.cpp (original)
+++ cfe/trunk/tools/libclang/CXCursor.cpp Tue Feb 14 18:54:55 2012
@@ -226,7 +226,6 @@
   case Stmt::UnaryExprOrTypeTraitExprClass:
   case Stmt::UnaryTypeTraitExprClass:
   case Stmt::VAArgExprClass:
-  case Stmt::LambdaExprClass:
     K = CXCursor_UnexposedExpr;
     break;
 
@@ -441,6 +440,10 @@
     K = CXCursor_CallExpr;
     break;
       
+  case Stmt::LambdaExprClass:
+    K = CXCursor_LambdaExpr;
+    break;
+      
   case Stmt::ObjCMessageExprClass: {
     K = CXCursor_ObjCMessageExpr;
     int SelectorIdIndex = -1;
@@ -573,6 +576,23 @@
                                        reinterpret_cast<uintptr_t>(C.data[1])));  
 }
 
+CXCursor cxcursor::MakeCursorVariableRef(const VarDecl *Var, SourceLocation Loc, 
+                                         CXTranslationUnit TU) {
+  
+  assert(Var && TU && "Invalid arguments!");
+  void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
+  CXCursor C = { CXCursor_VariableRef, 0, { (void*)Var, RawLoc, TU } };
+  return C;
+}
+
+std::pair<VarDecl *, SourceLocation> 
+cxcursor::getCursorVariableRef(CXCursor C) {
+  assert(C.kind == CXCursor_VariableRef);
+  return std::make_pair(static_cast<VarDecl *>(C.data[0]),
+                        SourceLocation::getFromRawEncoding(
+                          reinterpret_cast<uintptr_t>(C.data[1])));
+}
+
 CXCursor cxcursor::MakeCursorMemberRef(const FieldDecl *Field, SourceLocation Loc, 
                                        CXTranslationUnit TU) {
   

Modified: cfe/trunk/tools/libclang/CXCursor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXCursor.h?rev=150549&r1=150548&r2=150549&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CXCursor.h (original)
+++ cfe/trunk/tools/libclang/CXCursor.h Tue Feb 14 18:54:55 2012
@@ -41,6 +41,7 @@
 class TemplateDecl;
 class TemplateName;
 class TypeDecl;
+class VarDecl;
   
 namespace cxcursor {
 
@@ -111,6 +112,14 @@
 /// it references and the location where the reference occurred.
 std::pair<NamedDecl *, SourceLocation> getCursorNamespaceRef(CXCursor C);
 
+/// \brief Create a reference to a variable at the given location.
+CXCursor MakeCursorVariableRef(const VarDecl *Var, SourceLocation Loc, 
+                               CXTranslationUnit TU);
+
+/// \brief Unpack a VariableRef cursor into the variable it references and the
+/// location where the where the reference occurred.
+std::pair<VarDecl *, SourceLocation> getCursorVariableRef(CXCursor C); 
+
 /// \brief Create a reference to a field at the given location.
 CXCursor MakeCursorMemberRef(const FieldDecl *Field, SourceLocation Loc, 
                              CXTranslationUnit TU);

Modified: cfe/trunk/tools/libclang/CXType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXType.cpp?rev=150549&r1=150548&r2=150549&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CXType.cpp (original)
+++ cfe/trunk/tools/libclang/CXType.cpp Tue Feb 14 18:54:55 2012
@@ -160,12 +160,17 @@
       
     case CXCursor_CXXBaseSpecifier:
       return cxtype::MakeCXType(getCursorCXXBaseSpecifier(C)->getType(), TU);
-      
-    case CXCursor_ObjCProtocolRef:        
+
+    case CXCursor_MemberRef:
+      return cxtype::MakeCXType(getCursorMemberRef(C).first->getType(), TU);
+
+    case CXCursor_VariableRef:
+      return cxtype::MakeCXType(getCursorVariableRef(C).first->getType(), TU);
+
+    case CXCursor_ObjCProtocolRef:
     case CXCursor_TemplateRef:
     case CXCursor_NamespaceRef:
-    case CXCursor_MemberRef:
-    case CXCursor_OverloadedDeclRef:      
+    case CXCursor_OverloadedDeclRef:
     default:
       break;
     }

Modified: cfe/trunk/tools/libclang/CursorVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CursorVisitor.h?rev=150549&r1=150548&r2=150549&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CursorVisitor.h (original)
+++ cfe/trunk/tools/libclang/CursorVisitor.h Tue Feb 14 18:54:55 2012
@@ -31,7 +31,8 @@
               ExplicitTemplateArgsVisitKind,
               NestedNameSpecifierLocVisitKind,
               DeclarationNameInfoVisitKind,
-              MemberRefVisitKind, SizeOfPackExprPartsKind };
+              MemberRefVisitKind, SizeOfPackExprPartsKind,
+              LambdaExprPartsKind };
 protected:
   void *data[3];
   CXCursor parent;

Modified: cfe/trunk/tools/libclang/IndexBody.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/IndexBody.cpp?rev=150549&r1=150548&r2=150549&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/IndexBody.cpp (original)
+++ cfe/trunk/tools/libclang/IndexBody.cpp Tue Feb 14 18:54:55 2012
@@ -101,6 +101,17 @@
       IndexCtx.indexDeclGroupRef(S->getDeclGroup());
     return true;
   }
+  
+  bool TraverseLambdaCapture(LambdaExpr::Capture C) {
+    if (C.capturesThis())
+      return true;
+    
+    if (IndexCtx.indexFunctionLocalSymbols())
+      IndexCtx.handleReference(C.getCapturedVar(), C.getLocation(),
+                               Parent, ParentDC);
+    return true;
+  }
+
 };
 
 } // anonymous namespace

Modified: cfe/trunk/tools/libclang/IndexingContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/IndexingContext.cpp?rev=150549&r1=150548&r2=150549&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/IndexingContext.cpp (original)
+++ cfe/trunk/tools/libclang/IndexingContext.cpp Tue Feb 14 18:54:55 2012
@@ -1035,7 +1035,9 @@
     return MakeCursorNamespaceRef(Namespace, Loc, CXTU);
   if (const FieldDecl *Field = dyn_cast<FieldDecl>(D))
     return MakeCursorMemberRef(Field, Loc, CXTU);
-
+  if (const VarDecl *Var = dyn_cast<VarDecl>(D))
+    return MakeCursorVariableRef(Var, Loc, CXTU);
+  
   return clang_getNullCursor();
 }
 





More information about the cfe-commits mailing list