From: Douglas Gregor Date: Wed, 15 Sep 2010 16:23:04 +0000 (+0000) Subject: Improve code completion for Objective-C message sends when the opening X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=78edf515544f0b9dddf69d6c1678fd83e94d8352;p=clang Improve code completion for Objective-C message sends when the opening '[' 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 that we would for [calculator 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 --- diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index abdd083779..8b8f2d82c0 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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, diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 0f9154827e..26563de2b2 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -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 diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 7dc2cb3609..fd6b5518d7 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -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(E); + ObjCMessageExpr *Msg = dyn_cast_or_null(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); diff --git a/test/Index/complete-objc-message.m b/test/Index/complete-objc-message.m index f9d671037b..d6abd4bd83 100644 --- a/test/Index/complete-objc-message.m +++ b/test/Index/complete-objc-message.m @@ -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 diff --git a/test/Index/complete-super.m b/test/Index/complete-super.m index fc60c6c42d..62267fa74f 100644 --- a/test/Index/complete-super.m +++ b/test/Index/complete-super.m @@ -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