Implement code completion support for lambda capture lists.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150583 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index 7d38448..e74e70c 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -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())