Index: lib/Sema/SemaCodeComplete.cpp =================================================================== --- lib/Sema/SemaCodeComplete.cpp +++ lib/Sema/SemaCodeComplete.cpp @@ -5175,24 +5175,22 @@ /// when it has the same number of parameters as we have selector identifiers. /// /// \param Results the structure into which we'll add results. -static void AddObjCMethods(ObjCContainerDecl *Container, - bool WantInstanceMethods, - ObjCMethodKind WantKind, +static void AddObjCMethods(ObjCContainerDecl *Container, + bool WantInstanceMethods, ObjCMethodKind WantKind, ArrayRef SelIdents, DeclContext *CurContext, - VisitedSelectorSet &Selectors, - bool AllowSameLength, - ResultBuilder &Results, - bool InOriginalClass = true) { + VisitedSelectorSet &Selectors, bool AllowSameLength, + ResultBuilder &Results, bool InOriginalClass = true, + bool IsRootClass = false) { typedef CodeCompletionResult Result; Container = getContainerDef(Container); ObjCInterfaceDecl *IFace = dyn_cast(Container); - bool isRootClass = IFace && !IFace->getSuperClass(); + IsRootClass = IsRootClass || (IFace && !IFace->getSuperClass()); for (auto *M : Container->methods()) { // The instance methods on the root class can be messaged via the // metaclass. if (M->isInstanceMethod() == WantInstanceMethods || - (isRootClass && !WantInstanceMethods)) { + (IsRootClass && !WantInstanceMethods)) { // Check whether the selector identifiers we've been given are a // subset of the identifiers for this particular method. if (!isAcceptableObjCMethod(M, WantKind, SelIdents, AllowSameLength)) @@ -5218,8 +5216,8 @@ for (ObjCList::iterator I = Protocols.begin(), E = Protocols.end(); I != E; ++I) - AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, - CurContext, Selectors, AllowSameLength, Results, false); + AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, CurContext, + Selectors, AllowSameLength, Results, false, IsRootClass); } } @@ -5228,33 +5226,33 @@ // Add methods in protocols. for (auto *I : IFace->protocols()) - AddObjCMethods(I, WantInstanceMethods, WantKind, SelIdents, - CurContext, Selectors, AllowSameLength, Results, false); - + AddObjCMethods(I, WantInstanceMethods, WantKind, SelIdents, CurContext, + Selectors, AllowSameLength, Results, false, IsRootClass); + // Add methods in categories. for (auto *CatDecl : IFace->known_categories()) { AddObjCMethods(CatDecl, WantInstanceMethods, WantKind, SelIdents, - CurContext, Selectors, AllowSameLength, - Results, InOriginalClass); - + CurContext, Selectors, AllowSameLength, Results, + InOriginalClass, IsRootClass); + // Add a categories protocol methods. const ObjCList &Protocols = CatDecl->getReferencedProtocols(); for (ObjCList::iterator I = Protocols.begin(), E = Protocols.end(); I != E; ++I) - AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, - CurContext, Selectors, AllowSameLength, - Results, false); - + AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, CurContext, + Selectors, AllowSameLength, Results, false, IsRootClass); + // Add methods in category implementations. if (ObjCCategoryImplDecl *Impl = CatDecl->getImplementation()) - AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents, - CurContext, Selectors, AllowSameLength, - Results, InOriginalClass); + AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents, CurContext, + Selectors, AllowSameLength, Results, InOriginalClass, + IsRootClass); } // Add methods in superclass. + // Avoid passing in IsRootClass since root classes won't have super classes. if (IFace->getSuperClass()) AddObjCMethods(IFace->getSuperClass(), WantInstanceMethods, WantKind, SelIdents, CurContext, Selectors, @@ -5262,9 +5260,9 @@ // Add methods in our implementation, if any. if (ObjCImplementationDecl *Impl = IFace->getImplementation()) - AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents, - CurContext, Selectors, AllowSameLength, - Results, InOriginalClass); + AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents, CurContext, + Selectors, AllowSameLength, Results, InOriginalClass, + IsRootClass); } Index: test/Index/complete-objc-message.m =================================================================== --- test/Index/complete-objc-message.m +++ test/Index/complete-objc-message.m @@ -346,3 +346,54 @@ // RUN: c-index-test -code-completion-at=%s:197:6 %s | FileCheck -check-prefix=CHECK-NULLABLE %s // CHECK-NULLABLE: ObjCInstanceMethodDecl:{ResultType A * _Nonnull}{TypedText method:}{Placeholder (nullable A *)} + +// rdar://28012953 +// Code completion results should include instance methods from RootProtocol and +// RootClass when completing a method invocation for a RootClass object because +// RootClasses metaclass subclasses from RootClass (i.e. RootClass is actually +// an instance of RootClass). + +@protocol SubRootProtocol + +- (void)subProtocolInstanceMethod; + +@end + +@protocol RootProtocol + +- (void)protocolInstanceMethod; ++ (void)protocolClassMethod; + +@end + +@interface RootClass + +- (void)instanceMethod; ++ (void)classMethod; + +@end + +@protocol RootCategoryProtocol + +- (void)categoryProtocolInstanceMethod; + +@end + +@interface RootClass (Cat) + +- (void)categoryInstanceMethod; + +@end + +void completeAllTheRootThings() { + [RootClass classMethod]; +} + +// RUN: c-index-test -code-completion-at=%s:389:14 %s | FileCheck -check-prefix=CHECK-ROOT %s +// CHECK-ROOT: ObjCInstanceMethodDecl:{ResultType void}{TypedText categoryInstanceMethod} (35) +// CHECK-ROOT-NEXT: ObjCInstanceMethodDecl:{ResultType void}{TypedText categoryProtocolInstanceMethod} (37) +// CHECK-ROOT-NEXT: ObjCClassMethodDecl:{ResultType void}{TypedText classMethod} (35) +// CHECK-ROOT-NEXT: ObjCInstanceMethodDecl:{ResultType void}{TypedText instanceMethod} (35) +// CHECK-ROOT-NEXT: ObjCClassMethodDecl:{ResultType void}{TypedText protocolClassMethod} (37) +// CHECK-ROOT-NEXT: ObjCInstanceMethodDecl:{ResultType void}{TypedText protocolInstanceMethod} (37) +// CHECK-ROOT-NEXT: ObjCInstanceMethodDecl:{ResultType void}{TypedText subProtocolInstanceMethod} (37)