From: Douglas Gregor Date: Tue, 12 Jun 2012 13:44:08 +0000 (+0000) Subject: When code completion walks the members of a protocol or interface, X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b92a4089db33ae9d44e015cf2dfd1e82fea88747;p=clang When code completion walks the members of a protocol or interface, make sure that we walk the definition. Fixes . git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@158357 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index f8a9b4c2d1..681190c004 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -3334,7 +3334,25 @@ void Sema::CodeCompletePostfixExpression(Scope *S, ExprResult E) { /// property name. typedef llvm::SmallPtrSet AddedPropertiesSet; -static void AddObjCProperties(ObjCContainerDecl *Container, +/// \brief Retrieve the container definition, if any? +static ObjCContainerDecl *getContainerDef(ObjCContainerDecl *Container) { + if (ObjCInterfaceDecl *Interface = dyn_cast(Container)) { + if (Interface->hasDefinition()) + return Interface->getDefinition(); + + return Interface; + } + + if (ObjCProtocolDecl *Protocol = dyn_cast(Container)) { + if (Protocol->hasDefinition()) + return Protocol->getDefinition(); + + return Protocol; + } + return Container; +} + +static void AddObjCProperties(ObjCContainerDecl *Container, bool AllowCategories, bool AllowNullaryMethods, DeclContext *CurContext, @@ -3342,6 +3360,9 @@ static void AddObjCProperties(ObjCContainerDecl *Container, ResultBuilder &Results) { typedef CodeCompletionResult Result; + // Retrieve the definition. + Container = getContainerDef(Container); + // Add properties in this container. for (ObjCContainerDecl::prop_iterator P = Container->prop_begin(), PEnd = Container->prop_end(); @@ -3617,6 +3638,8 @@ void Sema::CodeCompleteCase(Scope *S) { // Code-complete the cases of a switch statement over an enumeration type // by providing the list of EnumDecl *Enum = type->castAs()->getDecl(); + if (EnumDecl *Def = Enum->getDefinition()) + Enum = Def; // Determine which enumerators we have already seen in the switch statement. // FIXME: Ideally, we would also be able to look *past* the code-completion @@ -4695,6 +4718,7 @@ static void AddObjCMethods(ObjCContainerDecl *Container, ResultBuilder &Results, bool InOriginalClass = true) { typedef CodeCompletionResult Result; + Container = getContainerDef(Container); for (ObjCContainerDecl::method_iterator M = Container->meth_begin(), MEnd = Container->meth_end(); M != MEnd; ++M) { @@ -5826,7 +5850,8 @@ void Sema::CodeCompleteObjCPropertyDefinition(Scope *S) { return; // Ignore any properties that have already been implemented. - for (DeclContext::decl_iterator D = Container->decls_begin(), + Container = getContainerDef(Container); + for (DeclContext::decl_iterator D = Container->decls_begin(), DEnd = Container->decls_end(); D != DEnd; ++D) if (ObjCPropertyImplDecl *PropertyImpl = dyn_cast(*D)) @@ -5959,9 +5984,12 @@ static void FindImplementableMethods(ASTContext &Context, KnownMethodsMap &KnownMethods, bool InOriginalClass = true) { if (ObjCInterfaceDecl *IFace = dyn_cast(Container)) { - // Recurse into protocols. + // Make sure we have a definition; that's what we'll walk. if (!IFace->hasDefinition()) return; + + IFace = IFace->getDefinition(); + Container = IFace; const ObjCList &Protocols = IFace->getReferencedProtocols(); @@ -6003,16 +6031,20 @@ static void FindImplementableMethods(ASTContext &Context, } if (ObjCProtocolDecl *Protocol = dyn_cast(Container)) { - if (Protocol->hasDefinition()) { - // Recurse into protocols. - const ObjCList &Protocols - = Protocol->getReferencedProtocols(); - for (ObjCList::iterator I = Protocols.begin(), - E = Protocols.end(); - I != E; ++I) - FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType, - KnownMethods, false); - } + // Make sure we have a definition; that's what we'll walk. + if (!Protocol->hasDefinition()) + return; + Protocol = Protocol->getDefinition(); + Container = Protocol; + + // Recurse into protocols. + const ObjCList &Protocols + = Protocol->getReferencedProtocols(); + for (ObjCList::iterator I = Protocols.begin(), + E = Protocols.end(); + I != E; ++I) + FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType, + KnownMethods, false); } // Add methods in this container. This operation occurs last because diff --git a/test/Index/complete-method-decls.m b/test/Index/complete-method-decls.m index becb7de6eb..ce48246370 100644 --- a/test/Index/complete-method-decls.m +++ b/test/Index/complete-method-decls.m @@ -8,7 +8,7 @@ - (int)getInt; - (id)getSelf; @end - +@protocol P1; @protocol P2 + (id)alloc; @end diff --git a/test/Index/complete-properties.m b/test/Index/complete-properties.m index ce1870e651..a445056369 100644 --- a/test/Index/complete-properties.m +++ b/test/Index/complete-properties.m @@ -45,6 +45,17 @@ id test(I3 *i3) { @synthesize Prop2 = Prop2_; @end +@protocol P1 +@property int Prop5; +@end + +@class P1; + +@interface I5 +@end +@implementation I5 +@synthesize Prop5; +@end // RUN: c-index-test -code-completion-at=%s:20:13 %s | FileCheck -check-prefix=CHECK-CC1 %s // CHECK-CC1: ObjCPropertyDecl:{ResultType int}{TypedText Prop0} // CHECK-CC1: ObjCPropertyDecl:{ResultType int}{TypedText Prop1} @@ -80,3 +91,6 @@ id test(I3 *i3) { // CHECK-CC7-NOT: ObjCIvarDecl:{ResultType id}{TypedText _Prop2} // CHECK-CC7: ObjCIvarDecl:{ResultType I4 *}{TypedText Prop1} (17) // CHECK-CC7: ObjCIvarDecl:{ResultType id}{TypedText Prop2_} (7) + +// RUN: c-index-test -code-completion-at=%s:57:13 -fobjc-nonfragile-abi %s | FileCheck -check-prefix=CHECK-CC8 %s +// CHECK-CC8: ObjCPropertyDecl:{ResultType int}{TypedText Prop5} (35)