[CodeCompletion] Ensure that ObjC root class completes instance

methods from protocols and categories as well

Code completion results for class methods already include instance methods
from Objective-C root classes. This commit ensures that the results also include
instance methods from protocols that the root class implements and root class
categories as well.

rdar://28012953

Differential Revision: https://reviews.llvm.org/D27257

llvm-svn: 292932
This commit is contained in:
Alex Lorenz 2017-01-24 14:15:08 +00:00
parent b8ad01559f
commit 638dbc3036
2 changed files with 79 additions and 30 deletions

View File

@ -5230,24 +5230,22 @@ namespace {
/// 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<IdentifierInfo *> 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<ObjCInterfaceDecl>(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))
@ -5273,8 +5271,8 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
for (ObjCList<ObjCProtocolDecl>::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);
}
}
@ -5283,43 +5281,43 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
// 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<ObjCProtocolDecl> &Protocols
= CatDecl->getReferencedProtocols();
for (ObjCList<ObjCProtocolDecl>::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,
AllowSameLength, Results, false);
AddObjCMethods(IFace->getSuperClass(), WantInstanceMethods, WantKind,
SelIdents, CurContext, Selectors, AllowSameLength, Results,
/*IsRootClass=*/false);
// 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);
}

View File

@ -346,3 +346,54 @@ void test_Nullability(Nullability *n, A* a) {
// 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 <SubRootProtocol>
- (void)protocolInstanceMethod;
+ (void)protocolClassMethod;
@end
@interface RootClass <RootProtocol>
- (void)instanceMethod;
+ (void)classMethod;
@end
@protocol RootCategoryProtocol
- (void)categoryProtocolInstanceMethod;
@end
@interface RootClass (Cat) <RootCategoryProtocol>
- (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)