Implement code completion for @selector expressions

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@112186 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index d61ddcd..b75a7d0 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -25,6 +25,7 @@
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Twine.h"
 #include <list>
 #include <map>
 #include <vector>
@@ -3401,25 +3402,32 @@
   MK_OneArgSelector //< One-argument selector.
 };
 
+static bool isAcceptableObjCSelector(Selector Sel,
+                                     ObjCMethodKind WantKind,
+                                     IdentifierInfo **SelIdents,
+                                     unsigned NumSelIdents) {
+  if (NumSelIdents > Sel.getNumArgs())
+    return false;
+  
+  switch (WantKind) {
+    case MK_Any:             break;
+    case MK_ZeroArgSelector: return Sel.isUnarySelector();
+    case MK_OneArgSelector:  return Sel.getNumArgs() == 1;
+  }
+  
+  for (unsigned I = 0; I != NumSelIdents; ++I)
+    if (SelIdents[I] != Sel.getIdentifierInfoForSlot(I))
+      return false;
+  
+  return true;
+}
+
 static bool isAcceptableObjCMethod(ObjCMethodDecl *Method,
                                    ObjCMethodKind WantKind,
                                    IdentifierInfo **SelIdents,
                                    unsigned NumSelIdents) {
-  Selector Sel = Method->getSelector();
-  if (NumSelIdents > Sel.getNumArgs())
-    return false;
-      
-  switch (WantKind) {
-  case MK_Any:             break;
-  case MK_ZeroArgSelector: return Sel.isUnarySelector();
-  case MK_OneArgSelector:  return Sel.getNumArgs() == 1;
-  }
-
-  for (unsigned I = 0; I != NumSelIdents; ++I)
-    if (SelIdents[I] != Sel.getIdentifierInfoForSlot(I))
-      return false;
-
-  return true;
+  return isAcceptableObjCSelector(Method->getSelector(), WantKind, SelIdents,
+                                  NumSelIdents);
 }
                                    
 /// \brief Add all of the Objective-C methods in the given Objective-C 
@@ -3979,6 +3987,57 @@
   CodeCompleteExpression(S, Data);
 }
 
+void Sema::CodeCompleteObjCSelector(Scope *S, IdentifierInfo **SelIdents,
+                                    unsigned NumSelIdents) {
+  // If we have an external source, load the entire class method
+  // pool from the AST file.
+  if (ExternalSource) {
+    for (uint32_t I = 0, N = ExternalSource->GetNumExternalSelectors();
+         I != N; ++I) {
+      Selector Sel = ExternalSource->GetExternalSelector(I);
+      if (Sel.isNull() || MethodPool.count(Sel))
+        continue;
+      
+      ReadMethodPool(Sel);
+    }
+  }
+  
+  ResultBuilder Results(*this);
+  Results.EnterNewScope();
+  for (GlobalMethodPool::iterator M = MethodPool.begin(),
+                               MEnd = MethodPool.end();
+       M != MEnd; ++M) {
+    
+    Selector Sel = M->first;
+    if (!isAcceptableObjCSelector(Sel, MK_Any, SelIdents, NumSelIdents))
+      continue;
+
+    CodeCompletionString *Pattern = new CodeCompletionString;
+    if (Sel.isUnarySelector()) {
+      Pattern->AddTypedTextChunk(Sel.getIdentifierInfoForSlot(0)->getName());
+      Results.AddResult(Pattern);
+      continue;
+    }
+    
+    for (unsigned I = 0, N = Sel.getNumArgs(); I != N; ++I) {
+      std::string Piece = Sel.getIdentifierInfoForSlot(I)->getName().str();
+      Piece += ':';
+      if (I < NumSelIdents)
+        Pattern->AddInformativeChunk(Piece);
+      else if (I == NumSelIdents)
+        Pattern->AddTypedTextChunk(Piece);
+      else
+        Pattern->AddTextChunk(Piece);
+    }
+    Results.AddResult(Pattern);
+  }
+  Results.ExitScope();
+  
+  HandleCodeCompleteResults(this, CodeCompleter, 
+                            CodeCompletionContext::CCC_SelectorName,
+                            Results.data(), Results.size());
+}
+
 /// \brief Add all of the protocol declarations that we find in the given
 /// (translation unit) context.
 static void AddProtocolResults(DeclContext *Ctx, DeclContext *CurContext,