]> granicus.if.org Git - clang/commitdiff
Improve code completion for Objective-C message sends when the opening
authorDouglas Gregor <dgregor@apple.com>
Wed, 15 Sep 2010 16:23:04 +0000 (16:23 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 15 Sep 2010 16:23:04 +0000 (16:23 +0000)
'[' is missing. Prior commits improving recovery also improved code
completion beyond the first selector, e.g., at or after the "to" in

  calculator add:x to:y

but not after "calculator". We now provide the same completions for

  calculator <CC>

that we would for

  [calculator <CC>

if "calculator" is an expression whose type is something that can
receive Objective-C messages.

This code completion works for instance and super message sends, but not
class message sends.

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

include/clang/Sema/Sema.h
lib/Parse/ParseExpr.cpp
lib/Sema/SemaCodeComplete.cpp
test/Index/complete-objc-message.m
test/Index/complete-super.m

index abdd083779f157af901328539a378346f3be3432..8b8f2d82c002452f49ed994546abf3ce9baec481 100644 (file)
@@ -4313,6 +4313,7 @@ public:
   void CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
                                        SourceLocation OpLoc,
                                        bool IsArrow);
+  void CodeCompletePostfixExpression(Scope *S, Expr *LHS);
   void CodeCompleteTag(Scope *S, unsigned TagSpec);
   void CodeCompleteTypeQualifiers(DeclSpec &DS);
   void CodeCompleteCase(Scope *S);
@@ -4349,20 +4350,14 @@ public:
   void CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc,
                                     IdentifierInfo **SelIdents,
                                     unsigned NumSelIdents);
-  void CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver,
-                                    IdentifierInfo **SelIdents,
-                                    unsigned NumSelIdents);
   void CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver,
                                     IdentifierInfo **SelIdents,
                                     unsigned NumSelIdents,
-                                    bool IsSuper);
+                                    bool IsSuper = false);
   void CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
                                        IdentifierInfo **SelIdents,
-                                       unsigned NumSelIdents);
-  void CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
-                                     IdentifierInfo **SelIdents,
-                                     unsigned NumSelIdents,
-                                     bool IsSuper);
+                                       unsigned NumSelIdents,
+                                       bool IsSuper = false);
   void CodeCompleteObjCForCollection(Scope *S, 
                                      DeclGroupPtrTy IterationVar);
   void CodeCompleteObjCSelector(Scope *S,
index 0f9154827e944f50a9da9716e3bfa844d0025f5e..26563de2b258e9ff3c6843ab4298ea61ca8da546 100644 (file)
@@ -664,12 +664,14 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
     }
 
     // In an Objective-C method, if we have "super" followed by an identifier,
-    // the token sequence is ill-fomed. However, if there's a ':' or ']' after
+    // the token sequence is ill-formed. However, if there's a ':' or ']' after
     // that identifier, this is probably a message send with a missing open
-    // bracket. Treat it as such.
-    if (getLang().ObjC1 && &II == Ident_super && Tok.is(tok::identifier) &&
+    // bracket. Treat it as such. 
+    if (getLang().ObjC1 && &II == Ident_super && !InMessageExpression &&
         getCurScope()->isInObjcMethodScope() &&
-        (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) {
+        ((Tok.is(tok::identifier) &&
+         (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) ||
+         Tok.is(tok::code_completion))) {
       Res = ParseObjCMessageExpressionBody(SourceLocation(), ILoc, ParsedType(), 
                                            0);
       break;
@@ -991,6 +993,15 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
   SourceLocation Loc;
   while (1) {
     switch (Tok.getKind()) {
+    case tok::code_completion:
+      if (InMessageExpression)
+        return move(LHS);
+        
+      Actions.CodeCompletePostfixExpression(getCurScope(), LHS.take());
+      ConsumeCodeCompletionToken();
+      LHS = ExprError();
+      break;
+        
     case tok::identifier:
       // If we see identifier: after an expression, and we're not already in a
       // message send, then this is probably a message send with a missing
index 7dc2cb3609d1c24b28161a21d6096cd2c15f516e..fd6b5518d7023d69ed4a091bf1ddb480bbeadbbf 100644 (file)
@@ -2728,6 +2728,10 @@ void Sema::CodeCompleteExpression(Scope *S,
                             Results.data(),Results.size());
 }
 
+void Sema::CodeCompletePostfixExpression(Scope *S, Expr *E) {
+  if (getLangOptions().ObjC1)
+    CodeCompleteObjCInstanceMessage(S, E, 0, 0, false);
+}
 
 static void AddObjCProperties(ObjCContainerDecl *Container, 
                               bool AllowCategories,
@@ -4014,7 +4018,7 @@ void Sema::CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS) {
 /// common uses of Objective-C. This routine returns that class type,
 /// or NULL if no better result could be determined.
 static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) {
-  ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E);
+  ObjCMessageExpr *Msg = dyn_cast_or_null<ObjCMessageExpr>(E);
   if (!Msg)
     return 0;
 
@@ -4278,12 +4282,6 @@ void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc,
                                       NumSelIdents, /*IsSuper=*/true);
 }
 
-void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver,
-                                        IdentifierInfo **SelIdents,
-                                        unsigned NumSelIdents) {
-  CodeCompleteObjCClassMessage(S, Receiver, SelIdents, NumSelIdents, false);
-}
-
 void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver,
                                         IdentifierInfo **SelIdents,
                                         unsigned NumSelIdents,
@@ -4362,12 +4360,6 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver,
                             Results.data(), Results.size());
 }
 
-void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
-                                           IdentifierInfo **SelIdents,
-                                           unsigned NumSelIdents) {
-  CodeCompleteObjCInstanceMessage(S, Receiver, SelIdents, NumSelIdents, false);
-}
-
 void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
                                            IdentifierInfo **SelIdents,
                                            unsigned NumSelIdents,
@@ -4378,8 +4370,9 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
   
   // If necessary, apply function/array conversion to the receiver.
   // C99 6.7.5.3p[7,8].
-  DefaultFunctionArrayLvalueConversion(RecExpr);
-  QualType ReceiverType = RecExpr->getType();
+  if (RecExpr)
+    DefaultFunctionArrayLvalueConversion(RecExpr);
+  QualType ReceiverType = RecExpr? RecExpr->getType() : Context.getObjCIdType();
   
   // Build the set of methods we can see.
   ResultBuilder Results(*this);
index f9d671037ba5a1c35a7c5e2ebb1abb825132a43d..d6abd4bd83fd5517d5b952939c373238bbdfed32 100644 (file)
@@ -132,6 +132,11 @@ void msg_id(id x) {
 
 void test_ranking(B *b) {
   [b method1];
+  b method1];
+}
+
+void test_overload_2(Overload *ovl) {
+  ovl Method:1 Arg1:1 OtherArg:ovl];
 }
 
 // RUN: c-index-test -code-completion-at=%s:23:19 %s | FileCheck -check-prefix=CHECK-CC1 %s
@@ -234,3 +239,9 @@ void test_ranking(B *b) {
 // RUN: c-index-test -code-completion-at=%s:134:6 %s | FileCheck -check-prefix=CHECK-CCI %s
 // CHECK-CCI: ObjCInstanceMethodDecl:{ResultType void}{TypedText method1} (22)
 // CHECK-CCI: ObjCInstanceMethodDecl:{ResultType void}{TypedText method2} (20)
+
+// Test code completion with a missing opening bracket:
+// RUN: c-index-test -code-completion-at=%s:135:5 %s | FileCheck -check-prefix=CHECK-CCI %s
+// RUN: c-index-test -code-completion-at=%s:139:7 %s | FileCheck -check-prefix=CHECK-CC7 %s
+// RUN: c-index-test -code-completion-at=%s:139:16 %s | FileCheck -check-prefix=CHECK-CC8 %s
+// RUN: c-index-test -code-completion-at=%s:139:23 %s | FileCheck -check-prefix=CHECK-CC9 %s
index fc60c6c42d6a43b7b365e9948ce9f1ed2b4592d1..62267fa74fd086215733baf9163bf69f2d1eb0c8 100644 (file)
@@ -22,6 +22,7 @@ typedef int Bool;
 
 + (void)select:(Bool)condition first:(int)a second:(int)b {
   [super selector:condition first:a second:b];
+   super selector:condition first:a second:b];
 }
 @end
 
@@ -53,3 +54,8 @@ typedef int Bool;
 // Check "super" completion at the third identifier
 // RUN: c-index-test -code-completion-at=%s:24:37 %s | FileCheck -check-prefix=CHECK-SELECTOR-SECOND %s
 // CHECK-SELECTOR-SECOND: ObjCClassMethodDecl:{ResultType void}{Informative select:}{Informative first:}{TypedText second:}{Placeholder b} (8)
+
+// Check "super" completion with missing '['.
+// RUN: c-index-test -code-completion-at=%s:25:10 %s | FileCheck -check-prefix=CHECK-SELECTOR-SELECTOR %s
+// RUN: c-index-test -code-completion-at=%s:25:28 %s | FileCheck -check-prefix=CHECK-SELECTOR-FIRST %s
+// RUN: c-index-test -code-completion-at=%s:25:37 %s | FileCheck -check-prefix=CHECK-SELECTOR-SECOND %s