forked from OSchip/llvm-project
Add a super-cool code completion for send-to-super. When we're typing
a message send to "super" from a method that appears to be meant to override a superclass method (same kind, same selector, same argument types), provide a "super" completion that fills in the selector along with forwarding the method's arguments (as placeholders). llvm-svn: 112263
This commit is contained in:
parent
c0b36921c2
commit
6fc0413e59
|
@ -30,6 +30,8 @@ namespace clang {
|
|||
/// \brief Default priority values for code-completion results based
|
||||
/// on their kind.
|
||||
enum {
|
||||
/// \brief Priority for a send-to-super completion.
|
||||
CCP_SuperCompletion = 8,
|
||||
/// \brief Priority for a declaration that is in the local scope.
|
||||
CCP_LocalDeclaration = 8,
|
||||
/// \brief Priority for a member declaration found from the current
|
||||
|
|
|
@ -4367,9 +4367,17 @@ public:
|
|||
virtual void CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver,
|
||||
IdentifierInfo **SelIdents,
|
||||
unsigned NumSelIdents);
|
||||
virtual void CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver,
|
||||
void CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver,
|
||||
IdentifierInfo **SelIdents,
|
||||
unsigned NumSelIdents,
|
||||
bool IsSuper);
|
||||
virtual void CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
|
||||
IdentifierInfo **SelIdents,
|
||||
unsigned NumSelIdents);
|
||||
void CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
|
||||
IdentifierInfo **SelIdents,
|
||||
unsigned NumSelIdents,
|
||||
bool IsSuper);
|
||||
virtual void CodeCompleteObjCForCollection(Scope *S,
|
||||
DeclGroupPtrTy IterationVar);
|
||||
virtual void CodeCompleteObjCSelector(Scope *S,
|
||||
|
|
|
@ -3761,6 +3761,110 @@ static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) {
|
|||
.Default(0);
|
||||
}
|
||||
|
||||
// Add a special completion for a message send to "super", which fills in the
|
||||
// most likely case of forwarding all of our arguments to the superclass
|
||||
// function.
|
||||
///
|
||||
/// \param S The semantic analysis object.
|
||||
///
|
||||
/// \param S NeedSuperKeyword Whether we need to prefix this completion with
|
||||
/// the "super" keyword. Otherwise, we just need to provide the arguments.
|
||||
///
|
||||
/// \param SelIdents The identifiers in the selector that have already been
|
||||
/// provided as arguments for a send to "super".
|
||||
///
|
||||
/// \param NumSelIdents The number of identifiers in \p SelIdents.
|
||||
///
|
||||
/// \param Results The set of results to augment.
|
||||
///
|
||||
/// \returns the Objective-C method declaration that would be invoked by
|
||||
/// this "super" completion. If NULL, no completion was added.
|
||||
static ObjCMethodDecl *AddSuperSendCompletion(Sema &S, bool NeedSuperKeyword,
|
||||
IdentifierInfo **SelIdents,
|
||||
unsigned NumSelIdents,
|
||||
ResultBuilder &Results) {
|
||||
ObjCMethodDecl *CurMethod = S.getCurMethodDecl();
|
||||
if (!CurMethod)
|
||||
return 0;
|
||||
|
||||
ObjCInterfaceDecl *Class = CurMethod->getClassInterface();
|
||||
if (!Class)
|
||||
return 0;
|
||||
|
||||
// Try to find a superclass method with the same selector.
|
||||
ObjCMethodDecl *SuperMethod = 0;
|
||||
while ((Class = Class->getSuperClass()) && !SuperMethod)
|
||||
SuperMethod = Class->getMethod(CurMethod->getSelector(),
|
||||
CurMethod->isInstanceMethod());
|
||||
|
||||
if (!SuperMethod)
|
||||
return 0;
|
||||
|
||||
// Check whether the superclass method has the same signature.
|
||||
if (CurMethod->param_size() != SuperMethod->param_size() ||
|
||||
CurMethod->isVariadic() != SuperMethod->isVariadic())
|
||||
return 0;
|
||||
|
||||
for (ObjCMethodDecl::param_iterator CurP = CurMethod->param_begin(),
|
||||
CurPEnd = CurMethod->param_end(),
|
||||
SuperP = SuperMethod->param_begin();
|
||||
CurP != CurPEnd; ++CurP, ++SuperP) {
|
||||
// Make sure the parameter types are compatible.
|
||||
if (!S.Context.hasSameUnqualifiedType((*CurP)->getType(),
|
||||
(*SuperP)->getType()))
|
||||
return 0;
|
||||
|
||||
// Make sure we have a parameter name to forward!
|
||||
if (!(*CurP)->getIdentifier())
|
||||
return 0;
|
||||
}
|
||||
|
||||
// We have a superclass method. Now, form the send-to-super completion.
|
||||
CodeCompletionString *Pattern = new CodeCompletionString;
|
||||
|
||||
// Give this completion a return type.
|
||||
AddResultTypeChunk(S.Context, SuperMethod, Pattern);
|
||||
|
||||
// If we need the "super" keyword, add it (plus some spacing).
|
||||
if (NeedSuperKeyword) {
|
||||
Pattern->AddTypedTextChunk("super");
|
||||
Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
|
||||
}
|
||||
|
||||
Selector Sel = CurMethod->getSelector();
|
||||
if (Sel.isUnarySelector()) {
|
||||
if (NeedSuperKeyword)
|
||||
Pattern->AddTextChunk(Sel.getIdentifierInfoForSlot(0)->getName());
|
||||
else
|
||||
Pattern->AddTypedTextChunk(Sel.getIdentifierInfoForSlot(0)->getName());
|
||||
} else {
|
||||
ObjCMethodDecl::param_iterator CurP = CurMethod->param_begin();
|
||||
for (unsigned I = 0, N = Sel.getNumArgs(); I != N; ++I, ++CurP) {
|
||||
if (I > NumSelIdents)
|
||||
Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
|
||||
|
||||
if (I < NumSelIdents)
|
||||
Pattern->AddInformativeChunk(
|
||||
Sel.getIdentifierInfoForSlot(I)->getName().str() + ":");
|
||||
else if (NeedSuperKeyword || I > NumSelIdents) {
|
||||
Pattern->AddTextChunk(
|
||||
Sel.getIdentifierInfoForSlot(I)->getName().str() + ":");
|
||||
Pattern->AddPlaceholderChunk((*CurP)->getIdentifier()->getName());
|
||||
} else {
|
||||
Pattern->AddTypedTextChunk(
|
||||
Sel.getIdentifierInfoForSlot(I)->getName().str() + ":");
|
||||
Pattern->AddPlaceholderChunk((*CurP)->getIdentifier()->getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Results.AddResult(CodeCompletionResult(Pattern, CCP_SuperCompletion,
|
||||
SuperMethod->isInstanceMethod()
|
||||
? CXCursor_ObjCInstanceMethodDecl
|
||||
: CXCursor_ObjCClassMethodDecl));
|
||||
return SuperMethod;
|
||||
}
|
||||
|
||||
void Sema::CodeCompleteObjCMessageReceiver(Scope *S) {
|
||||
typedef CodeCompletionResult Result;
|
||||
ResultBuilder Results(*this);
|
||||
|
@ -3776,8 +3880,11 @@ void Sema::CodeCompleteObjCMessageReceiver(Scope *S) {
|
|||
// add "super" as an option.
|
||||
if (ObjCMethodDecl *Method = getCurMethodDecl())
|
||||
if (ObjCInterfaceDecl *Iface = Method->getClassInterface())
|
||||
if (Iface->getSuperClass())
|
||||
if (Iface->getSuperClass()) {
|
||||
Results.AddResult(Result("super"));
|
||||
|
||||
AddSuperSendCompletion(*this, /*NeedSuperKeyword=*/true, 0, 0, Results);
|
||||
}
|
||||
|
||||
Results.ExitScope();
|
||||
|
||||
|
@ -3814,7 +3921,8 @@ void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc,
|
|||
ExprResult Super
|
||||
= Owned(new (Context) ObjCSuperExpr(SuperLoc, SuperTy));
|
||||
return CodeCompleteObjCInstanceMessage(S, (Expr *)Super.get(),
|
||||
SelIdents, NumSelIdents);
|
||||
SelIdents, NumSelIdents,
|
||||
/*IsSuper=*/true);
|
||||
}
|
||||
|
||||
// Fall through to send to the superclass in CDecl.
|
||||
|
@ -3849,12 +3957,19 @@ void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc,
|
|||
if (CDecl)
|
||||
Receiver = ParsedType::make(Context.getObjCInterfaceType(CDecl));
|
||||
return CodeCompleteObjCClassMessage(S, Receiver, SelIdents,
|
||||
NumSelIdents);
|
||||
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,
|
||||
bool IsSuper) {
|
||||
typedef CodeCompletionResult Result;
|
||||
ObjCInterfaceDecl *CDecl = 0;
|
||||
|
||||
|
@ -3872,6 +3987,15 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver,
|
|||
ResultBuilder Results(*this);
|
||||
Results.EnterNewScope();
|
||||
|
||||
// If this is a send-to-super, try to add the special "super" send
|
||||
// completion.
|
||||
if (IsSuper) {
|
||||
if (ObjCMethodDecl *SuperMethod
|
||||
= AddSuperSendCompletion(*this, false, SelIdents, NumSelIdents,
|
||||
Results))
|
||||
Results.Ignore(SuperMethod);
|
||||
}
|
||||
|
||||
if (CDecl)
|
||||
AddObjCMethods(CDecl, false, MK_Any, SelIdents, NumSelIdents, CurContext,
|
||||
Results);
|
||||
|
@ -3912,12 +4036,19 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver,
|
|||
Results.ExitScope();
|
||||
HandleCodeCompleteResults(this, CodeCompleter,
|
||||
CodeCompletionContext::CCC_Other,
|
||||
Results.data(),Results.size());
|
||||
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,
|
||||
bool IsSuper) {
|
||||
typedef CodeCompletionResult Result;
|
||||
|
||||
Expr *RecExpr = static_cast<Expr *>(Receiver);
|
||||
|
@ -3931,6 +4062,15 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
|
|||
ResultBuilder Results(*this);
|
||||
Results.EnterNewScope();
|
||||
|
||||
// If this is a send-to-super, try to add the special "super" send
|
||||
// completion.
|
||||
if (IsSuper) {
|
||||
if (ObjCMethodDecl *SuperMethod
|
||||
= AddSuperSendCompletion(*this, false, SelIdents, NumSelIdents,
|
||||
Results))
|
||||
Results.Ignore(SuperMethod);
|
||||
}
|
||||
|
||||
// If we're messaging an expression with type "id" or "Class", check
|
||||
// whether we know something special about the receiver that allows
|
||||
// us to assume a more-specific receiver type.
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
// Note: the run lines follow their respective tests, since line/column
|
||||
// matter in this test.
|
||||
|
||||
typedef int Bool;
|
||||
|
||||
@interface A
|
||||
- (void)add:(int)x to:(int)y;
|
||||
+ (void)select:(Bool)condition first:(int)x second:(int)y;
|
||||
- (void)last;
|
||||
+ (void)last;
|
||||
@end
|
||||
|
||||
@interface B : A
|
||||
- (void)add:(int)x to:(int)y;
|
||||
+ (void)select:(Bool)condition first:(int)x second:(int)y;
|
||||
@end
|
||||
|
||||
@implementation B
|
||||
- (void)add:(int)a to:(int)b {
|
||||
[super add:a to:b];
|
||||
}
|
||||
|
||||
+ (void)select:(Bool)condition first:(int)a second:(int)b {
|
||||
[super selector:condition first:a second:b];
|
||||
}
|
||||
@end
|
||||
|
||||
// Check "super" completion as a message receiver.
|
||||
// RUN: c-index-test -code-completion-at=%s:20:4 %s | FileCheck -check-prefix=CHECK-ADD-RECEIVER %s
|
||||
// CHECK-ADD-RECEIVER: ObjCInstanceMethodDecl:{ResultType void}{TypedText super}{HorizontalSpace }{Text add:}{Placeholder a}{HorizontalSpace }{Text to:}{Placeholder b} (8)
|
||||
|
||||
// RUN: c-index-test -code-completion-at=%s:24:4 %s | FileCheck -check-prefix=CHECK-SELECT-RECEIVER %s
|
||||
// CHECK-SELECT-RECEIVER: ObjCClassMethodDecl:{ResultType void}{TypedText super}{HorizontalSpace }{Text select:}{Placeholder condition}{HorizontalSpace }{Text first:}{Placeholder a}{HorizontalSpace }{Text second:}{Placeholder b} (8)
|
||||
|
||||
// Check "super" completion at the first identifier
|
||||
// RUN: c-index-test -code-completion-at=%s:20:10 %s | FileCheck -check-prefix=CHECK-ADD-ADD %s
|
||||
// CHECK-ADD-ADD: ObjCInstanceMethodDecl:{ResultType void}{TypedText add:}{Placeholder a}{HorizontalSpace }{Text to:}{Placeholder b} (8)
|
||||
// CHECK-ADD-ADD-NOT: add
|
||||
// CHECK-ADD-ADD: ObjCInstanceMethodDecl:{ResultType void}{TypedText last} (20)
|
||||
|
||||
// RUN: c-index-test -code-completion-at=%s:24:10 %s | FileCheck -check-prefix=CHECK-SELECTOR-SELECTOR %s
|
||||
// CHECK-SELECTOR-SELECTOR-NOT: x
|
||||
// CHECK-SELECTOR-SELECTOR: ObjCClassMethodDecl:{ResultType void}{TypedText last} (20)
|
||||
// CHECK-SELECTOR-SELECTOR: ObjCClassMethodDecl:{ResultType void}{TypedText select:}{Placeholder condition}{HorizontalSpace }{Text first:}{Placeholder a}{HorizontalSpace }{Text second:}{Placeholder b} (8)
|
||||
|
||||
// Check "super" completion at the second identifier
|
||||
// RUN: c-index-test -code-completion-at=%s:20:16 %s | FileCheck -check-prefix=CHECK-ADD-TO %s
|
||||
// CHECK-ADD-TO: ObjCInstanceMethodDecl:{ResultType void}{Informative add:}{TypedText to:}{Placeholder b} (8)
|
||||
|
||||
// RUN: c-index-test -code-completion-at=%s:24:28 %s | FileCheck -check-prefix=CHECK-SELECTOR-FIRST %s
|
||||
// CHECK-SELECTOR-FIRST: ObjCClassMethodDecl:{ResultType void}{Informative select:}{TypedText first:}{Placeholder a}{HorizontalSpace }{Text second:}{Placeholder b} (8)
|
||||
|
||||
// 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)
|
Loading…
Reference in New Issue