When providing code completions for an argument in an Objective-C

message send, e.g.,

  [[NSString alloc] initWithCString:<CC>

look up all of the possible methods and determine the preferred type
for the argument expression based on the type of the corresponding
parameter.

llvm-svn: 114379
This commit is contained in:
Douglas Gregor 2010-09-21 00:03:25 +00:00
parent dba0a0fbef
commit 7466127a4b
2 changed files with 104 additions and 10 deletions

View File

@ -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<ObjCMethodDecl>(R.Declaration)) {
if (R.Priority <= BestPriority) {
ObjCMethodDecl *Method = cast<ObjCMethodDecl>(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<Expr *>(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());

View File

@ -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)