From: Douglas Gregor Date: Tue, 17 Nov 2009 17:59:40 +0000 (+0000) Subject: Implement code completion for Objective-C message sends to "super". X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=24a069f5ebf441d86eaec7524365101adf6b2aeb;p=clang Implement code completion for Objective-C message sends to "super". git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89112 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index e2aac77507..cb3bd1c06c 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -13,6 +13,7 @@ #include "Sema.h" #include "clang/Sema/CodeCompleteConsumer.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/SmallPtrSet.h" @@ -1555,11 +1556,61 @@ void Sema::CodeCompleteObjCProperty(Scope *S, ObjCDeclSpec &ODS) { void Sema::CodeCompleteObjCFactoryMethod(Scope *S, IdentifierInfo *FName) { typedef CodeCompleteConsumer::Result Result; + ObjCInterfaceDecl *CDecl = 0; + + // FIXME: Pass this in! + SourceLocation NameLoc; + + if (FName->isStr("super")) { + // We're sending a message to "super". + if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) { + // Figure out which interface we're in. + CDecl = CurMethod->getClassInterface(); + if (!CDecl) + return; + + // Find the superclass of this class. + CDecl = CDecl->getSuperClass(); + if (!CDecl) + return; + + if (CurMethod->isInstanceMethod()) { + // We are inside an instance method, which means that the message + // send [super ...] is actually calling an instance method on the + // current object. Build the super expression and handle this like + // an instance method. + QualType SuperTy = Context.getObjCInterfaceType(CDecl); + SuperTy = Context.getObjCObjectPointerType(SuperTy); + OwningExprResult Super + = Owned(new (Context) ObjCSuperExpr(NameLoc, SuperTy)); + return CodeCompleteObjCInstanceMethod(S, (Expr *)Super.get()); + } + + // Okay, we're calling a factory method in our superclass. + } + } + + // If the given name refers to an interface type, retrieve the + // corresponding declaration. + if (!CDecl) + if (TypeTy *Ty = getTypeName(*FName, NameLoc, S, 0, false)) { + QualType T = GetTypeFromParser(Ty, 0); + if (!T.isNull()) + if (const ObjCInterfaceType *Interface = T->getAs()) + CDecl = Interface->getDecl(); + } + + if (!CDecl && FName->isStr("super")) { + // "super" may be the name of a variable, in which case we are + // probably calling an instance method. + OwningExprResult Super = ActOnDeclarationNameExpr(S, NameLoc, FName, + false, 0, false); + return CodeCompleteObjCInstanceMethod(S, (Expr *)Super.get()); + } + ResultBuilder Results(*this); Results.EnterNewScope(); - ObjCInterfaceDecl *CDecl = getObjCInterfaceDecl(FName); - while (CDecl != NULL) { for (ObjCInterfaceDecl::classmeth_iterator I = CDecl->classmeth_begin(), E = CDecl->classmeth_end(); diff --git a/test/Index/complete-objc-message.m b/test/Index/complete-objc-message.m index c495d0b7a6..728d9803c5 100644 --- a/test/Index/complete-objc-message.m +++ b/test/Index/complete-objc-message.m @@ -23,6 +23,57 @@ void func() { Foo *obj = [Foo new]; [obj xx]; } + +@interface MyClass { } ++ (int)MyClassMethod:(id)obj; +- (int)MyInstMethod:(id)x second:(id)y; +@end + +@interface MySubClass : MyClass { } ++ (int)MySubClassMethod; +- (int)MySubInstMethod; +@end + +@implementation MyClass ++ (int)MyClassMethod:(id)obj { + return 0; +} + ++ (int)MyPrivateMethod { + return 1; +} + +- (int)MyInstMethod:(id)x second:(id)y { + return 2; +} + +- (int)MyPrivateInstMethod { + return 3; +} +@end + +@implementation MySubClass ++ (int)MySubClassMethod { + return 2; +} + ++ (int)MySubPrivateMethod { + return [super MyPrivateMethod]; +} + +- (int)MySubInstMethod:(id)obj { + return [super MyInstMethod: obj second:obj]; +} + +- (int)MyInstMethod:(id)x second:(id)y { + return 3; +} +@end + +void test_super_var(MySubClass *super) { + [super MyInstMethod: super second:super]; +} + // RUN: c-index-test -code-completion-at=%s:23:19 %s | FileCheck -check-prefix=CHECK-CC1 %s // CHECK-CC1: {TypedText categoryClassMethod} // CHECK-CC1: {TypedText classMethod2} @@ -33,3 +84,13 @@ void func() { // CHECK-CC2: {TypedText categoryInstanceMethod} // CHECK-CC2: {TypedText instanceMethod1} // CHECK-CC2: {TypedText protocolInstanceMethod:}{Placeholder (int)value} +// RUN: c-index-test -code-completion-at=%s:61:16 %s | FileCheck -check-prefix=CHECK-CC3 %s +// CHECK-CC3: ObjCClassMethodDecl:{TypedText MyClassMethod:}{Placeholder (id)obj} +// FIXME-CC3: ObjCClassMethodDecl:{TypedText MyPrivateMethod} +// RUN: c-index-test -code-completion-at=%s:65:16 %s | FileCheck -check-prefix=CHECK-CC4 %s +// CHECK-CC4: ObjCInstanceMethodDecl:{TypedText MyInstMethod:}{Placeholder (id)x}{Text second:}{Placeholder (id)y} +// FIXME-CC4: ObjCInstanceMethodDecl:{TypedText MyPrivateInstMethod} +// RUN: c-index-test -code-completion-at=%s:74:9 %s | FileCheck -check-prefix=CHECK-CC5 %s +// CHECK-CC5: ObjCInstanceMethodDecl:{TypedText MySubInstMethod} +// CHECK-CC5: ObjCInstanceMethodDecl:{TypedText MyInstMethod:}{Placeholder (id)x}{Text second:}{Placeholder (id)y} +