]> granicus.if.org Git - clang/commitdiff
Implement code completion for @selector expressions
authorDouglas Gregor <dgregor@apple.com>
Thu, 26 Aug 2010 15:07:07 +0000 (15:07 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 26 Aug 2010 15:07:07 +0000 (15:07 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@112186 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Sema/Action.h
include/clang/Sema/CodeCompleteConsumer.h
include/clang/Sema/Sema.h
lib/Frontend/ASTUnit.cpp
lib/Parse/ParseObjc.cpp
lib/Sema/SemaCodeComplete.cpp
test/Index/complete-at-exprstmt.m
tools/libclang/CIndexCodeCompletion.cpp

index 5fb6d1f00f8bb528216e8a7d8633fd26a028afb7..1af23ba77605ea5173a49511c4f36a26eba22a9e 100644 (file)
@@ -3078,6 +3078,16 @@ public:
   virtual void CodeCompleteObjCForCollection(Scope *S, 
                                              DeclGroupPtrTy IterationVar) { }
   
+  /// \brief Code completion for an Objective-C @selector expression, in which
+  /// we may have already parsed parts of the selector.
+  ///
+  /// \param S The scope in which the @selector expression occurs.
+  /// \param SelIdents The identifiers that describe the selector (thus far).
+  /// \param NumSelIdents The number of identifiers in \p SelIdents.
+  virtual void CodeCompleteObjCSelector(Scope *S,
+                                        IdentifierInfo **SelIdents,
+                                        unsigned NumSelIdents) { }
+  
   /// \brief Code completion for a list of protocol references in Objective-C,
   /// such as P1 and P2 in \c id<P1,P2>.
   ///
index d290d39a938cf44864724f14f0ef5de8a476055b..55bd576f9651e31bbd61f063b4fc4e8d84d9790d 100644 (file)
@@ -190,7 +190,9 @@ public:
     ///
     /// This context usually implies that no completions should be added,
     /// unless they come from an appropriate natural-language dictionary.
-    CCC_NaturalLanguage
+    CCC_NaturalLanguage,
+    /// \brief Code completion for a selector, as in an @selector expression.
+    CCC_SelectorName
   };
 
 private:
index 9504f77f19027c9db63e59867bc1a45b5c026971..f23c4a1e93368e9f14a9c75f79f0c52db9f3f33e 100644 (file)
@@ -4202,6 +4202,9 @@ public:
                                                unsigned NumSelIdents);
   virtual void CodeCompleteObjCForCollection(Scope *S, 
                                              DeclGroupPtrTy IterationVar);
+  virtual void CodeCompleteObjCSelector(Scope *S,
+                                        IdentifierInfo **SelIdents,
+                                        unsigned NumSelIdents);
   virtual void CodeCompleteObjCProtocolReferences(IdentifierLocPair *Protocols,
                                                   unsigned NumProtocols);
   virtual void CodeCompleteObjCProtocolDecl(Scope *S);
index 874fd012b3c9ed8695f71609720f568720d9ebd7..851c6669fee0c89a816abecfb851527888da72f3 100644 (file)
@@ -1554,6 +1554,7 @@ void CalculateHiddenNames(const CodeCompletionContext &Context,
   case CodeCompletionContext::CCC_PreprocessorExpression:
   case CodeCompletionContext::CCC_PreprocessorDirective:
   case CodeCompletionContext::CCC_NaturalLanguage:
+  case CodeCompletionContext::CCC_SelectorName:
     // We're looking for nothing, or we're looking for names that cannot
     // be hidden.
     return;
index 1b09b1fe8448cfbde6f818bd5fa093fbea146b46..4b65652011ae97acc34c565a5b9a026c18d9d47a 100644 (file)
@@ -2194,6 +2194,15 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
   llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
   SourceLocation LParenLoc = ConsumeParen();
   SourceLocation sLoc;
+  
+  if (Tok.is(tok::code_completion)) {
+    Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents.data(),
+                                     KeyIdents.size());
+    ConsumeCodeCompletionToken();
+    MatchRHSPunctuation(tok::r_paren, LParenLoc);
+    return ExprError();
+  }
+  
   IdentifierInfo *SelIdent = ParseObjCSelectorPiece(sLoc);
   if (!SelIdent && Tok.isNot(tok::colon)) // missing selector name.
     return ExprError(Diag(Tok, diag::err_expected_ident));
@@ -2209,6 +2218,15 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
       ConsumeToken(); // Eat the ':'.
       if (Tok.is(tok::r_paren))
         break;
+      
+      if (Tok.is(tok::code_completion)) {
+        Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents.data(),
+                                         KeyIdents.size());
+        ConsumeCodeCompletionToken();
+        MatchRHSPunctuation(tok::r_paren, LParenLoc);
+        return ExprError();
+      }
+
       // Check for another keyword selector.
       SourceLocation Loc;
       SelIdent = ParseObjCSelectorPiece(Loc);
index d61ddcdf758a31e259a89c57ee915bd4e82182e0..b75a7d05bba9946a7d7595e267f5086c4d3ef25f 100644 (file)
@@ -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,26 +3402,33 @@ enum ObjCMethodKind {
   MK_OneArgSelector //< One-argument selector.
 };
 
-static bool isAcceptableObjCMethod(ObjCMethodDecl *Method,
-                                   ObjCMethodKind WantKind,
-                                   IdentifierInfo **SelIdents,
-                                   unsigned NumSelIdents) {
-  Selector Sel = Method->getSelector();
+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;
+    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) {
+  return isAcceptableObjCSelector(Method->getSelector(), WantKind, SelIdents,
+                                  NumSelIdents);
+}
                                    
 /// \brief Add all of the Objective-C methods in the given Objective-C 
 /// container to the set of results.
@@ -3979,6 +3987,57 @@ void Sema::CodeCompleteObjCForCollection(Scope *S,
   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,
index 85370989fd83359e8b8b7715de8705ee3497db2c..834b42e4b3007a7da5a1ebf167536b456e1f4a56 100644 (file)
@@ -9,6 +9,16 @@
   @synchronized (@encode(MyClass)) { }
 }
 @end
+
+@interface A
++ (int)add:(int)x to:(int)y;
++ (int)add:(int)x to:(int)y plus:(int)z;
+@end
+
+void f() {
+  @selector(add:to:);
+}
+
 // RUN: c-index-test -code-completion-at=%s:9:4 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s
 // CHECK-CC1: {TypedText encode}{LeftParen (}{Placeholder type-name}{RightParen )}
 // CHECK-CC1: {TypedText protocol}{LeftParen (}{Placeholder protocol-name}{RightParen )}
 // CHECK-CC3: ObjCInterfaceDecl:{TypedText MyClass}
 // CHECK-CC3: TypedefDecl:{TypedText SEL}
 // CHECK-CC3: NotImplemented:{ResultType MyClass *}{TypedText self}
+// RUN: c-index-test -code-completion-at=%s:19:13 %s | FileCheck -check-prefix=CHECK-CC4 %s
+// CHECK-CC4: NotImplemented:{TypedText add:}{Text to:} (30)
+// CHECK-CC4: NotImplemented:{TypedText add:}{Text to:}{Text plus:} (30)
+// CHECK-CC4: NotImplemented:{TypedText myMethod:} (30)
+// RUN: c-index-test -code-completion-at=%s:19:17 %s | FileCheck -check-prefix=CHECK-CC5 %s
+// CHECK-CC5: NotImplemented:{Informative add:}{TypedText to:} (30)
+// CHECK-CC5: NotImplemented:{Informative add:}{TypedText to:}{Text plus:} (30)
+
index 825031bd4b4e730a0950d910d80e522d10132dab..cebfc8478bc8045dd6d40ea804188c5baea8f0a0 100644 (file)
@@ -818,4 +818,4 @@ extern "C" {
                                        unsigned NumResults) {
     std::stable_sort(Results, Results + NumResults, OrderCompletionResults());
   }
-}
\ No newline at end of file
+}