[cfe-commits] r150583 - in /cfe/trunk: include/clang/Sema/Sema.h lib/Parse/ParseExprCXX.cpp lib/Sema/SemaCodeComplete.cpp test/Index/complete-lambdas.cpp

Douglas Gregor dgregor at apple.com
Wed Feb 15 07:34:24 PST 2012


Author: dgregor
Date: Wed Feb 15 09:34:24 2012
New Revision: 150583

URL: http://llvm.org/viewvc/llvm-project?rev=150583&view=rev
Log:
Implement code completion support for lambda capture lists.

Added:
    cfe/trunk/test/Index/complete-lambdas.cpp   (with props)
Modified:
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/lib/Sema/SemaCodeComplete.cpp

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=150583&r1=150582&r2=150583&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Feb 15 09:34:24 2012
@@ -6304,6 +6304,8 @@
   void CodeCompleteConstructorInitializer(Decl *Constructor,
                                           CXXCtorInitializer** Initializers,
                                           unsigned NumInitializers);
+  void CodeCompleteLambdaIntroducer(Scope *S, LambdaIntroducer &Intro,
+                                    bool AfterAmpersand);
 
   void CodeCompleteObjCAtDirective(Scope *S);
   void CodeCompleteObjCAtVisibility(Scope *S);

Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=150583&r1=150582&r2=150583&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Wed Feb 15 09:34:24 2012
@@ -615,7 +615,7 @@
 /// ParseLambdaExpression - Parse a lambda introducer.
 ///
 /// Returns a DiagnosticID if it hit something unexpected.
-llvm::Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro) {
+llvm::Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro){
   typedef llvm::Optional<unsigned> DiagResult;
 
   assert(Tok.is(tok::l_square) && "Lambda expressions begin with '['.");
@@ -640,13 +640,33 @@
 
   while (Tok.isNot(tok::r_square)) {
     if (!first) {
-      if (Tok.isNot(tok::comma))
+      if (Tok.isNot(tok::comma)) {
+        if (Tok.is(tok::code_completion)) {
+          Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro, 
+                                               /*AfterAmpersand=*/false);
+          ConsumeCodeCompletionToken();
+          break;
+        }
+
         return DiagResult(diag::err_expected_comma_or_rsquare);
+      }
       ConsumeToken();
     }
 
-    first = false;
+    if (Tok.is(tok::code_completion)) {
+      // If we're in Objective-C++ and we have a bare '[', then this is more
+      // likely to be a message receiver.
+      if (getLang().ObjC1 && first)
+        Actions.CodeCompleteObjCMessageReceiver(getCurScope());
+      else
+        Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro, 
+                                             /*AfterAmpersand=*/false);
+      ConsumeCodeCompletionToken();
+      break;
+    }
 
+    first = false;
+    
     // Parse capture.
     LambdaCaptureKind Kind = LCK_ByCopy;
     SourceLocation Loc;
@@ -660,6 +680,13 @@
       if (Tok.is(tok::amp)) {
         Kind = LCK_ByRef;
         ConsumeToken();
+
+        if (Tok.is(tok::code_completion)) {
+          Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro, 
+                                               /*AfterAmpersand=*/true);
+          ConsumeCodeCompletionToken();
+          break;
+        }
       }
 
       if (Tok.is(tok::identifier)) {
@@ -687,7 +714,7 @@
   return DiagResult();
 }
 
-/// TryParseLambdaExpression - Tentatively parse a lambda introducer.
+/// TryParseLambdaIntroducer - Tentatively parse a lambda introducer.
 ///
 /// Returns true if it hit something unexpected.
 bool Parser::TryParseLambdaIntroducer(LambdaIntroducer &Intro) {

Modified: cfe/trunk/lib/Sema/SemaCodeComplete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCodeComplete.cpp?rev=150583&r1=150582&r2=150583&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCodeComplete.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCodeComplete.cpp Wed Feb 15 09:34:24 2012
@@ -274,9 +274,9 @@
     /// of the shadow maps), or replace an existing result (for, e.g., a 
     /// redeclaration).
     ///
-    /// \param CurContext the result to add (if it is unique).
+    /// \param R the result to add (if it is unique).
     ///
-    /// \param R the context in which this result will be named.
+    /// \param CurContext the context in which this result will be named.
     void MaybeAddResult(Result R, DeclContext *CurContext = 0);
     
     /// \brief Add a new result to this result set, where we already know
@@ -325,6 +325,7 @@
     bool IsMember(NamedDecl *ND) const;
     bool IsObjCIvar(NamedDecl *ND) const;
     bool IsObjCMessageReceiver(NamedDecl *ND) const;
+    bool IsObjCMessageReceiverOrLambdaCapture(NamedDecl *ND) const;
     bool IsObjCCollection(NamedDecl *ND) const;
     bool IsImpossibleToSatisfy(NamedDecl *ND) const;
     //@}    
@@ -1152,6 +1153,17 @@
   return isObjCReceiverType(SemaRef.Context, T);
 }
 
+bool ResultBuilder::IsObjCMessageReceiverOrLambdaCapture(NamedDecl *ND) const {
+  if (IsObjCMessageReceiver(ND))
+    return true;
+  
+  VarDecl *Var = dyn_cast<VarDecl>(ND);
+  if (!Var)
+    return false;
+  
+  return Var->hasLocalStorage() && !Var->hasAttr<BlocksAttr>();
+}
+
 bool ResultBuilder::IsObjCCollection(NamedDecl *ND) const {
   if ((SemaRef.getLangOptions().CPlusPlus && !IsOrdinaryName(ND)) ||
       (!SemaRef.getLangOptions().CPlusPlus && !IsOrdinaryNonTypeName(ND)))
@@ -1423,6 +1435,23 @@
   return Allocator.CopyString(Result);
 }
 
+/// \brief Add a completion for "this", if we're in a member function.
+static void addThisCompletion(Sema &S, ResultBuilder &Results) {
+  QualType ThisTy = S.getCurrentThisType();
+  if (ThisTy.isNull())
+    return;
+  
+  CodeCompletionAllocator &Allocator = Results.getAllocator();
+  CodeCompletionBuilder Builder(Allocator);
+  PrintingPolicy Policy = getCompletionPrintingPolicy(S);
+  Builder.AddResultTypeChunk(GetCompletionTypeString(ThisTy, 
+                                                     S.Context, 
+                                                     Policy,
+                                                     Allocator));
+  Builder.AddTypedTextChunk("this");
+  Results.AddResult(CodeCompletionResult(Builder.TakeString()));            
+}
+
 /// \brief Add language constructs that show up for "ordinary" names.
 static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
                                    Scope *S,
@@ -1758,15 +1787,7 @@
   case Sema::PCC_Expression: {
     if (SemaRef.getLangOptions().CPlusPlus) {
       // 'this', if we're in a non-static member function.
-      QualType ThisTy = SemaRef.getCurrentThisType();
-      if (!ThisTy.isNull()) {
-        Builder.AddResultTypeChunk(GetCompletionTypeString(ThisTy, 
-                                                           SemaRef.Context, 
-                                                           Policy,
-                                                           Allocator));
-        Builder.AddTypedTextChunk("this");
-        Results.AddResult(Result(Builder.TakeString()));      
-      }
+      addThisCompletion(SemaRef, Results);
       
       // true
       Builder.AddResultTypeChunk("bool");
@@ -3665,7 +3686,6 @@
     kind = CodeCompletionContext::CCC_OtherWithMacros;
   }
   
-  
   HandleCodeCompleteResults(this, CodeCompleter, 
                             kind,
                             Results.data(),Results.size());
@@ -4181,6 +4201,60 @@
                             Results.data(), Results.size());
 }
 
+/// \brief Determine whether this scope denotes a namespace.
+static bool isNamespaceScope(Scope *S) {
+  DeclContext *DC = static_cast<DeclContext *>(S->getEntity());
+  if (!DC)
+    return false;
+
+  return DC->isFileContext();
+}
+
+void Sema::CodeCompleteLambdaIntroducer(Scope *S, LambdaIntroducer &Intro,
+                                        bool AfterAmpersand) {
+  ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+                        CodeCompletionContext::CCC_Other);
+  Results.EnterNewScope();
+
+  // Note what has already been captured.
+  llvm::SmallPtrSet<IdentifierInfo *, 4> Known;
+  bool IncludedThis = false;
+  for (SmallVectorImpl<LambdaCapture>::iterator C = Intro.Captures.begin(),
+                                             CEnd = Intro.Captures.end();
+       C != CEnd; ++C) {
+    if (C->Kind == LCK_This) {
+      IncludedThis = true;
+      continue;
+    }
+    
+    Known.insert(C->Id);
+  }
+  
+  // Look for other capturable variables.
+  for (; S && !isNamespaceScope(S); S = S->getParent()) {
+    for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
+         D != DEnd; ++D) {
+      VarDecl *Var = dyn_cast<VarDecl>(*D);
+      if (!Var ||
+          !Var->hasLocalStorage() ||
+          Var->hasAttr<BlocksAttr>())
+        continue;
+      
+      if (Known.insert(Var->getIdentifier()))
+        Results.AddResult(CodeCompletionResult(Var), CurContext, 0, false);
+    }
+  }
+
+  // Add 'this', if it would be valid.
+  if (!IncludedThis && !AfterAmpersand && Intro.Default != LCD_ByCopy)
+    addThisCompletion(*this, Results);
+  
+  Results.ExitScope();
+  
+  HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(),
+                            Results.data(), Results.size());
+}
+
 // Macro that expands to @Keyword or Keyword, depending on whether NeedAt is
 // true or false.
 #define OBJC_AT_KEYWORD_NAME(NeedAt,Keyword) NeedAt? "@" #Keyword : #Keyword
@@ -4980,7 +5054,9 @@
   typedef CodeCompletionResult Result;
   ResultBuilder Results(*this, CodeCompleter->getAllocator(),
                         CodeCompletionContext::CCC_ObjCMessageReceiver,
-                        &ResultBuilder::IsObjCMessageReceiver);
+                        getLangOptions().CPlusPlus0x
+                          ? &ResultBuilder::IsObjCMessageReceiverOrLambdaCapture
+                          : &ResultBuilder::IsObjCMessageReceiver);
   
   CodeCompletionDeclConsumer Consumer(Results, CurContext);
   Results.EnterNewScope();
@@ -4997,6 +5073,9 @@
         AddSuperSendCompletion(*this, /*NeedSuperKeyword=*/true, 0, 0, Results);
       }
   
+  if (getLangOptions().CPlusPlus0x)
+    addThisCompletion(*this, Results);
+  
   Results.ExitScope();
   
   if (CodeCompleter->includeMacros())

Added: cfe/trunk/test/Index/complete-lambdas.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/complete-lambdas.cpp?rev=150583&view=auto
==============================================================================
--- cfe/trunk/test/Index/complete-lambdas.cpp (added)
+++ cfe/trunk/test/Index/complete-lambdas.cpp Wed Feb 15 09:34:24 2012
@@ -0,0 +1,43 @@
+// This test is line- and column-sensitive. See below for run lines.
+
+int global;
+
+struct X {
+  static int member;
+  void f(int zed) {
+    int local;
+    static int local_static;
+    [=] {
+      int inner_local;
+      [local, this, inner_local] {
+      }
+    }();
+  }
+};
+
+
+// RUN: c-index-test -code-completion-at=%s:12:8 -std=c++11 %s | FileCheck -check-prefix=CHECK-CC1 %s
+// CHECK-CC1: VarDecl:{ResultType int}{TypedText inner_local} (34)
+// CHECK-CC1-NEXT: VarDecl:{ResultType int}{TypedText local} (34)
+// CHECK-CC1-NEXT: NotImplemented:{ResultType X *}{TypedText this} (40)
+// CHECK-CC1-NEXT: ParmDecl:{ResultType int}{TypedText zed} (34)
+
+// RUN: c-index-test -code-completion-at=%s:12:15 -std=c++11 %s | FileCheck -check-prefix=CHECK-CC2 %s
+// CHECK-CC2: VarDecl:{ResultType int}{TypedText inner_local} (34)
+// CHECK-CC2-NEXT: NotImplemented:{ResultType X *}{TypedText this} (40)
+// CHECK-CC2-NEXT: ParmDecl:{ResultType int}{TypedText zed} (34)
+
+// RUN: c-index-test -code-completion-at=%s:12:21 -std=c++11 %s | FileCheck -check-prefix=CHECK-CC3 %s
+// CHECK-CC3: VarDecl:{ResultType int}{TypedText inner_local} (34)
+// CHECK-CC3-NEXT: ParmDecl:{ResultType int}{TypedText zed} (34)
+
+// RUN: c-index-test -code-completion-at=%s:12:8 -x objective-c++ -std=c++11 %s | FileCheck -check-prefix=CHECK-CC4 %s
+// CHECK-CC4: TypedefDecl:{TypedText Class} (50)
+// CHECK-CC4: TypedefDecl:{TypedText id} (50)
+// CHECK-CC4: VarDecl:{ResultType int}{TypedText inner_local} (34)
+// CHECK-CC4: VarDecl:{ResultType int}{TypedText local} (34)
+// CHECK-CC4: NotImplemented:{ResultType X *}{TypedText this} (40)
+// CHECK-CC4: ParmDecl:{ResultType int}{TypedText zed} (34)
+
+// RUN: c-index-test -code-completion-at=%s:12:15 -x objective-c++ -std=c++11 %s | FileCheck -check-prefix=CHECK-CC2 %s
+// RUN: c-index-test -code-completion-at=%s:12:21 -x objective-c++ -std=c++11 %s | FileCheck -check-prefix=CHECK-CC3 %s

Propchange: cfe/trunk/test/Index/complete-lambdas.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/Index/complete-lambdas.cpp
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/Index/complete-lambdas.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain





More information about the cfe-commits mailing list