From 13438f9b9c8fdf08998c843dd307d2a9eda05b32 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 6 Apr 2010 16:40:00 +0000 Subject: [PATCH] Implement support for code completion of an Objective-C message send to "id" or an expression of type "id". In these cases, we produce a list of all of the (class or instance) methods, respectively, that we know about. Note that this implementation does not yet work well with precompiled headers; that's coming soon. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@100528 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaCodeComplete.cpp | 58 +++++++++++++++++++++++++----- test/Index/complete-objc-message.m | 39 ++++++++++++++++++++ 2 files changed, 88 insertions(+), 9 deletions(-) diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index df14aa7fc5..d29cab4ca1 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -2970,8 +2970,33 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, IdentifierInfo *FName, // superclasses, categories, implementation, etc. ResultBuilder Results(*this); Results.EnterNewScope(); - AddObjCMethods(CDecl, false, MK_Any, SelIdents, NumSelIdents, CurContext, - Results); + + if (CDecl) + AddObjCMethods(CDecl, false, MK_Any, SelIdents, NumSelIdents, CurContext, + Results); + else if (FName->isStr("id")) { + // We're messaging "id" as a type; provide all class/factory methods. + + // FIXME: Load the entire class method pool from the PCH file + for (llvm::DenseMap::iterator + M = FactoryMethodPool.begin(), + MEnd = FactoryMethodPool.end(); + M != MEnd; + ++M) { + for (ObjCMethodList *MethList = &M->second; MethList; + MethList = MethList->Next) { + if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents, + NumSelIdents)) + continue; + + Result R(MethList->Method, 0); + R.StartParameter = NumSelIdents; + R.AllParametersAreInformative = false; + Results.MaybeAddResult(R, CurContext); + } + } + } + Results.ExitScope(); // This also suppresses remaining diagnostics. @@ -2990,12 +3015,6 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, DefaultFunctionArrayLvalueConversion(RecExpr); QualType ReceiverType = RecExpr->getType(); - if (ReceiverType->isObjCIdType() || ReceiverType->isBlockPointerType()) { - // FIXME: We're messaging 'id'. Do we actually want to look up every method - // in the universe? - return; - } - // Build the set of methods we can see. ResultBuilder Results(*this); Results.EnterNewScope(); @@ -3035,7 +3054,28 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, AddObjCMethods(*I, true, MK_Any, SelIdents, NumSelIdents, CurContext, Results); } - + // Handle messages to "id". + else if (ReceiverType->isObjCIdType()) { + // FIXME: Load the entire instance method pool from the PCH file + for (llvm::DenseMap::iterator + M = InstanceMethodPool.begin(), + MEnd = InstanceMethodPool.end(); + M != MEnd; + ++M) { + for (ObjCMethodList *MethList = &M->second; MethList; + MethList = MethList->Next) { + if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents, + NumSelIdents)) + continue; + + Result R(MethList->Method, 0); + R.StartParameter = NumSelIdents; + R.AllParametersAreInformative = false; + Results.MaybeAddResult(R, CurContext); + } + } + } + Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } diff --git a/test/Index/complete-objc-message.m b/test/Index/complete-objc-message.m index b9e8f08f51..e65a056e36 100644 --- a/test/Index/complete-objc-message.m +++ b/test/Index/complete-objc-message.m @@ -116,6 +116,12 @@ void test_overload2(void) { [Overload2 Method:1 Arg1:1 OtherArg:ovl]; } +void msg_id(id x) { + [x Method:1 Arg1:1 OtherArg:ovl]; + [[x blarg] Method:1 Arg1:1 OtherArg:ovl]; + [id Method:1 Arg1:1 OtherArg:ovl]; +} + // RUN: c-index-test -code-completion-at=%s:23:19 %s | FileCheck -check-prefix=CHECK-CC1 %s // CHECK-CC1: {TypedText categoryClassMethod} // CHECK-CC1: {TypedText classMethod1:}{Placeholder (id)a}{HorizontalSpace }{Text withKeyword:}{Placeholder (int)b} @@ -192,3 +198,36 @@ void test_overload2(void) { // CHECK-CCF: TypedefDecl:{TypedText SEL} // CHECK-CCF: {ResultType Class}{TypedText self} // CHECK-CCF: {TypedText super} +// RUN: c-index-test -code-completion-at=%s:120:6 %s | FileCheck -check-prefix=CHECK-CCG %s +// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType id}{TypedText categoryInstanceMethod} +// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType id}{TypedText instanceMethod1} +// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method} +// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (int)i} +// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (float)f}{HorizontalSpace }{Text Arg1:}{Placeholder (int)i1}{HorizontalSpace }{Text Arg2:}{Placeholder (int)i2} +// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (float)f}{HorizontalSpace }{Text Arg1:}{Placeholder (int)i1}{HorizontalSpace }{Text OtherArg:}{Placeholder (id)obj} +// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (float)f}{HorizontalSpace }{Text SomeArg:}{Placeholder (int)i1}{HorizontalSpace }{Text OtherArg:}{Placeholder (id)obj} +// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText MyInstMethod:}{Placeholder (id)x}{HorizontalSpace }{Text second:}{Placeholder (id)y} +// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText MyPrivateInstMethod} +// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText MySubInstMethod} +// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText MySubInstMethod:}{Placeholder (id)obj} +// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText OtherMethod:}{Placeholder (float)f}{HorizontalSpace }{Text Arg1:}{Placeholder (int)i1}{HorizontalSpace }{Text Arg2:}{Placeholder (int)i2} +// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType id}{TypedText protocolInstanceMethod:}{Placeholder (int)value} +// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText secondProtocolInstanceMethod} +// RUN: c-index-test -code-completion-at=%s:121:14 %s | FileCheck -check-prefix=CHECK-CCG %s +// RUN: c-index-test -code-completion-at=%s:122:7 %s | FileCheck -check-prefix=CHECK-CCH %s +// CHECK-CCH: ObjCClassMethodDecl:{ResultType id}{TypedText categoryClassMethod} +// CHECK-CCH: ObjCClassMethodDecl:{ResultType int}{TypedText classMethod1:}{Placeholder (id)a}{HorizontalSpace }{Text withKeyword:}{Placeholder (int)b} +// CHECK-CCH: ObjCClassMethodDecl:{ResultType void}{TypedText classMethod2} +// CHECK-CCH: ObjCClassMethodDecl:{ResultType int}{TypedText Method} +// CHECK-CCH: ObjCClassMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (int)i} +// CHECK-CCH: ObjCClassMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (float)f}{HorizontalSpace }{Text Arg1:}{Placeholder (int)i1}{HorizontalSpace }{Text Arg2:}{Placeholder (int)i2} +// CHECK-CCH: ObjCClassMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (float)f}{HorizontalSpace }{Text Arg1:}{Placeholder (int)i1}{HorizontalSpace }{Text OtherArg:}{Placeholder (id)obj} +// CHECK-CCH: ObjCClassMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (float)f}{HorizontalSpace }{Text SomeArg:}{Placeholder (int)i1}{HorizontalSpace }{Text OtherArg:}{Placeholder (id)obj} +// CHECK-CCH: ObjCClassMethodDecl:{ResultType int}{TypedText MyClassMethod:}{Placeholder (id)obj} +// CHECK-CCH: ObjCClassMethodDecl:{ResultType int}{TypedText MyPrivateMethod} +// CHECK-CCH: ObjCClassMethodDecl:{ResultType int}{TypedText MySubClassMethod} +// CHECK-CCH: ObjCClassMethodDecl:{ResultType int}{TypedText MySubPrivateMethod} +// CHECK-CCH: ObjCClassMethodDecl:{ResultType id}{TypedText new} +// CHECK-CCH: ObjCClassMethodDecl:{ResultType int}{TypedText OtherMethod:}{Placeholder (float)f}{HorizontalSpace }{Text Arg1:}{Placeholder (int)i1}{HorizontalSpace }{Text Arg2:}{Placeholder (int)i2} +// CHECK-CCH: ObjCClassMethodDecl:{ResultType id}{TypedText protocolClassMethod} +