From: Douglas Gregor Date: Tue, 21 Sep 2010 00:03:25 +0000 (+0000) Subject: When providing code completions for an argument in an Objective-C X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b9d775734b02e5369bdfa78fa3e479c7281a9761;p=clang When providing code completions for an argument in an Objective-C message send, e.g., [[NSString alloc] initWithCString: look up all of the possible methods and determine the preferred type for the argument expression based on the type of the corresponding parameter. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@114379 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index c3feb3b6a0..ab37b6ccbc 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -216,6 +216,10 @@ namespace { AllowNestedNameSpecifiers = Allow; } + /// \brief Return the semantic analysis object for which we are collecting + /// code completion results. + Sema &getSema() const { return SemaRef; } + /// \brief Determine whether the given declaration is at all interesting /// as a code-completion result. /// @@ -4362,6 +4366,40 @@ void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, /*IsSuper=*/true); } +/// \brief Given a set of code-completion results for the argument of a message +/// send, determine the preferred type (if any) for that argument expression. +static QualType getPreferredArgumentTypeForMessageSend(ResultBuilder &Results, + unsigned NumSelIdents) { + typedef CodeCompletionResult Result; + ASTContext &Context = Results.getSema().Context; + + QualType PreferredType; + unsigned BestPriority = CCP_Unlikely * 2; + Result *ResultsData = Results.data(); + for (unsigned I = 0, N = Results.size(); I != N; ++I) { + Result &R = ResultsData[I]; + if (R.Kind == Result::RK_Declaration && + isa(R.Declaration)) { + if (R.Priority <= BestPriority) { + ObjCMethodDecl *Method = cast(R.Declaration); + if (NumSelIdents <= Method->param_size()) { + QualType MyPreferredType = Method->param_begin()[NumSelIdents - 1] + ->getType(); + if (R.Priority < BestPriority || PreferredType.isNull()) { + BestPriority = R.Priority; + PreferredType = MyPreferredType; + } else if (!Context.hasSameUnqualifiedType(PreferredType, + MyPreferredType)) { + PreferredType = QualType(); + } + } + } + } + } + + return PreferredType; +} + static void AddClassMessageCompletions(Sema &SemaRef, Scope *S, ParsedType Receiver, IdentifierInfo **SelIdents, @@ -4446,12 +4484,25 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, unsigned NumSelIdents, bool AtArgumentExpression, bool IsSuper) { - if (AtArgumentExpression) - return CodeCompleteOrdinaryName(S, PCC_Expression); - ResultBuilder Results(*this); AddClassMessageCompletions(*this, S, Receiver, SelIdents, NumSelIdents, AtArgumentExpression, IsSuper, Results); + + // If we're actually at the argument expression (rather than prior to the + // selector), we're actually performing code completion for an expression. + // Determine whether we have a single, best method. If so, we can + // code-complete the expression using the corresponding parameter type as + // our preferred type, improving completion results. + if (AtArgumentExpression) { + QualType PreferredType = getPreferredArgumentTypeForMessageSend(Results, + NumSelIdents); + if (PreferredType.isNull()) + CodeCompleteOrdinaryName(S, PCC_Expression); + else + CodeCompleteExpression(S, PreferredType); + return; + } + HandleCodeCompleteResults(this, CodeCompleter, CodeCompletionContext::CCC_Other, Results.data(), Results.size()); @@ -4462,9 +4513,6 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, unsigned NumSelIdents, bool AtArgumentExpression, bool IsSuper) { - if (AtArgumentExpression) - return CodeCompleteOrdinaryName(S, PCC_Expression); - typedef CodeCompletionResult Result; Expr *RecExpr = static_cast(Receiver); @@ -4577,8 +4625,24 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, } } } - Results.ExitScope(); + + + // If we're actually at the argument expression (rather than prior to the + // selector), we're actually performing code completion for an expression. + // Determine whether we have a single, best method. If so, we can + // code-complete the expression using the corresponding parameter type as + // our preferred type, improving completion results. + if (AtArgumentExpression) { + QualType PreferredType = getPreferredArgumentTypeForMessageSend(Results, + NumSelIdents); + if (PreferredType.isNull()) + CodeCompleteOrdinaryName(S, PCC_Expression); + else + CodeCompleteExpression(S, PreferredType); + return; + } + HandleCodeCompleteResults(this, CodeCompleter, CodeCompletionContext::CCC_Other, Results.data(),Results.size()); diff --git a/test/Index/complete-type-factors.m b/test/Index/complete-type-factors.m index 96f5874c20..d2dc4a9813 100644 --- a/test/Index/complete-type-factors.m +++ b/test/Index/complete-type-factors.m @@ -22,9 +22,15 @@ enum Priority test1(enum Priority priority, enum Color color, int integer) { c = color; } -// FIXME: It would be great for message sends to have the same -// benefits as function calls, but we don't quite have the -// infrastructure yet. +@interface A ++ (void)method:(enum Color)color priority:(enum Priority)priority; +- (void)method:(enum Color)color priority:(enum Priority)priority; +@end + +void test2(A *a) { + [a method:Red priority:High]; + [A method:Red priority:Low]; +} // RUN: c-index-test -code-completion-at=%s:16:11 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s // CHECK-CC1: EnumConstantDecl:{ResultType enum Color}{TypedText Blue} (32) @@ -105,3 +111,27 @@ enum Priority test1(enum Priority priority, enum Color color, int integer) { // CHECK-CC6: EnumConstantDecl:{ResultType enum Color}{TypedText Red} (16) // CHECK-CC6: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (30) // CHECK-CC6: FunctionDecl:{ResultType enum Priority}{TypedText test1}{LeftParen (}{Placeholder enum Priority priority}{Comma , }{Placeholder enum Color color}{Comma , }{Placeholder int integer}{RightParen )} (50) +// RUN: c-index-test -code-completion-at=%s:31:13 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC7 %s +// RUN: c-index-test -code-completion-at=%s:32:13 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC7 %s +// CHECK-CC7: ParmDecl:{ResultType A *}{TypedText a} (8) +// CHECK-CC7: EnumConstantDecl:{ResultType enum Color}{TypedText Blue} (16) +// CHECK-CC7: FunctionDecl:{ResultType int}{TypedText func1}{LeftParen (}{Placeholder enum Color}{RightParen )} (25) +// CHECK-CC7: FunctionDecl:{ResultType enum Priority}{TypedText func2}{LeftParen (}{Placeholder int}{RightParen )} (50) +// CHECK-CC7: FunctionDecl:{ResultType void}{TypedText func3}{LeftParen (}{Placeholder float}{RightParen )} (50) +// CHECK-CC7: EnumConstantDecl:{ResultType enum Color}{TypedText Green} (16) +// CHECK-CC7: EnumConstantDecl:{ResultType enum Priority}{TypedText High} (65) +// CHECK-CC7: EnumConstantDecl:{ResultType enum Priority}{TypedText Low} (65) +// CHECK-CC7: EnumConstantDecl:{ResultType enum Color}{TypedText Red} (16) +// CHECK-CC7: FunctionDecl:{ResultType enum Priority}{TypedText test1}{LeftParen (}{Placeholder enum Priority priority}{Comma , }{Placeholder enum Color color}{Comma , }{Placeholder int integer}{RightParen )} (50) +// RUN: c-index-test -code-completion-at=%s:31:26 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC8 %s +// RUN: c-index-test -code-completion-at=%s:32:26 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC8 %s +// CHECK-CC8: ParmDecl:{ResultType A *}{TypedText a} (8) +// CHECK-CC8: EnumConstantDecl:{ResultType enum Color}{TypedText Blue} (65) +// CHECK-CC8: FunctionDecl:{ResultType int}{TypedText func1}{LeftParen (}{Placeholder enum Color}{RightParen )} (25) +// CHECK-CC8: FunctionDecl:{ResultType enum Priority}{TypedText func2}{LeftParen (}{Placeholder int}{RightParen )} (12) +// CHECK-CC8: FunctionDecl:{ResultType void}{TypedText func3}{LeftParen (}{Placeholder float}{RightParen )} (50) +// CHECK-CC8: EnumConstantDecl:{ResultType enum Color}{TypedText Green} (65) +// CHECK-CC8: EnumConstantDecl:{ResultType enum Priority}{TypedText High} (16) +// CHECK-CC8: EnumConstantDecl:{ResultType enum Priority}{TypedText Low} (16) +// CHECK-CC8: EnumConstantDecl:{ResultType enum Color}{TypedText Red} (65) +// CHECK-CC8: FunctionDecl:{ResultType enum Priority}{TypedText test1}{LeftParen (}{Placeholder enum Priority priority}{Comma , }{Placeholder enum Color color}{Comma , }{Placeholder int integer}{RightParen )} (12)