]> granicus.if.org Git - clang/commitdiff
Implement indexing support for lambdas in libclang (both kinds), as
authorDouglas Gregor <dgregor@apple.com>
Wed, 15 Feb 2012 00:54:55 +0000 (00:54 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 15 Feb 2012 00:54:55 +0000 (00:54 +0000)
well as improving the RecursiveASTVisitor's walk of lambda
expressions.

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

include/clang-c/Index.h
include/clang/AST/RecursiveASTVisitor.h
test/Index/cxx11-lambdas.cpp [new file with mode: 0644]
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

index 0c6d6d1c762552b5758feeaf020e8fe5d2e4308b..018a316c894eae6721cdd5ba15fddb40bde0ee28 100644 (file)
@@ -1500,7 +1500,13 @@ enum CXCursorKind {
    */
   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 @@ enum CXCursorKind {
    */
   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,
index dcfe6bea9888336957226f6696445e57f2f81275..a113a94846fed57bcff64f1a78021f1b4e4accef 100644 (file)
@@ -228,6 +228,11 @@ public:
   /// \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 @@ bool RecursiveASTVisitor<Derived>::TraverseConstructorInitializer(
   return true;
 }
 
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseLambdaCapture(LambdaExpr::Capture C){
+  return true;
+}
 
 // ----------------- Type traversal -----------------
 
@@ -1953,9 +1962,36 @@ DEF_TRAVERSE_STMT(CXXTemporaryObjectExpr, {
     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.
diff --git a/test/Index/cxx11-lambdas.cpp b/test/Index/cxx11-lambdas.cpp
new file mode 100644 (file)
index 0000000..93db022
--- /dev/null
@@ -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@100@S@X@F@f#@localA | lang: C | cursor: VariableRef=localA:6:9 | loc: 7:21
+// CHECK-INDEX: [indexEntityReference]: kind: variable | name: localB | USR: c:cxx11-lambdas.cpp@100@S@X@F@f#@localB | lang: C | cursor: VariableRef=localB:6:17 | loc: 7:29
+// CHECK-INDEX: [indexEntityReference]: kind: typedef | name: Integer | USR: c:cxx11-lambdas.cpp@51@T@Integer | lang: C | cursor: TypeRef=Integer:3:13 | loc: 7:52
+// CHECK-INDEX: [indexEntityReference]: kind: typedef | name: Integer | USR: c:cxx11-lambdas.cpp@51@T@Integer | lang: C | cursor: TypeRef=Integer:3:13 | loc: 7:38
+// CHECK-INDEX: [indexEntityReference]: kind: variable | name: localA | USR: c:cxx11-lambdas.cpp@100@S@X@F@f#@localA | lang: C | cursor: DeclRefExpr=localA:6:9 | loc: 8:14
+// CHECK-INDEX: [indexEntityReference]: kind: variable | name: localB | USR: c:cxx11-lambdas.cpp@100@S@X@F@f#@localB | lang: C | cursor: DeclRefExpr=localB:6:17 | loc: 8:23
+// CHECK-INDEX: [indexEntityReference]: kind: variable | name: x | USR: c:cxx11-lambdas.cpp@157@S@X@F@f#@Ca@F@operator()#I#1@x | lang: C | cursor: DeclRefExpr=x:7:46 | loc: 8:32
index 90bccc55e1d1130a91aafdc73cbfc2227e6eb8a4..beec4d2352f899445aea430bb53424148373e516 100644 (file)
@@ -1615,6 +1615,7 @@ DEF_JOB(OverloadExprParts, OverloadExpr, OverloadExprPartsKind)
 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 @@ public:
   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 @@ void EnqueueVisitor::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
   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 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
         // 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 @@ CXString clang_getCursorSpelling(CXCursor C) {
       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 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
     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 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
       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 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {
       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 @@ static SourceRange getRawCursorExtent(CXCursor C) {
     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 @@ CXCursor clang_getCursorReferenced(CXCursor C) {
 
     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.
index af640bd7ab4dc5867de9024ae76ecb7521c77144..531e70e17ada8e9d11ef16aa1736f90a2b5902e3 100644 (file)
@@ -226,7 +226,6 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
   case Stmt::UnaryExprOrTypeTraitExprClass:
   case Stmt::UnaryTypeTraitExprClass:
   case Stmt::VAArgExprClass:
-  case Stmt::LambdaExprClass:
     K = CXCursor_UnexposedExpr;
     break;
 
@@ -441,6 +440,10 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
     K = CXCursor_CallExpr;
     break;
       
+  case Stmt::LambdaExprClass:
+    K = CXCursor_LambdaExpr;
+    break;
+      
   case Stmt::ObjCMessageExprClass: {
     K = CXCursor_ObjCMessageExpr;
     int SelectorIdIndex = -1;
@@ -573,6 +576,23 @@ cxcursor::getCursorNamespaceRef(CXCursor C) {
                                        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) {
   
index 7423560085c3b2f2af4670be4da3ee1bf93214cd..947b0a3eede6f199d257cd9ee4a5f5cedbbcf9fd 100644 (file)
@@ -41,6 +41,7 @@ class Stmt;
 class TemplateDecl;
 class TemplateName;
 class TypeDecl;
+class VarDecl;
   
 namespace cxcursor {
 
@@ -111,6 +112,14 @@ CXCursor MakeCursorNamespaceRef(const NamedDecl *NS, SourceLocation Loc,
 /// 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);
index eba0405994ebe4b56848c8a96ad747a470cb1e3e..0d4a5195abec7c38bf8a4706e71385d72b442020 100644 (file)
@@ -160,12 +160,17 @@ CXType clang_getCursorType(CXCursor C) {
       
     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;
     }
index f1258cb6666522843b8e787ad99798b8a69c6467..88b70a490eb73a51478452257deac5309643ae46 100644 (file)
@@ -31,7 +31,8 @@ public:
               ExplicitTemplateArgsVisitKind,
               NestedNameSpecifierLocVisitKind,
               DeclarationNameInfoVisitKind,
-              MemberRefVisitKind, SizeOfPackExprPartsKind };
+              MemberRefVisitKind, SizeOfPackExprPartsKind,
+              LambdaExprPartsKind };
 protected:
   void *data[3];
   CXCursor parent;
index 684d5ce3854ea60c39e7e0bd4396f2670fd49836..77ff843525c1a59a9a16bd4b66f1ef43348a1845 100644 (file)
@@ -101,6 +101,17 @@ public:
       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
index 75184dd3b0bfd73107453b49b1939cad40465e67..2963f3b9453863b5a445b1e237705c71cf139a32 100644 (file)
@@ -1035,7 +1035,9 @@ CXCursor IndexingContext::getRefCursor(const NamedDecl *D, SourceLocation Loc) {
     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();
 }