}
}
+static void DiagnoseCategoryDirectMembersProtocolConformance(
+ Sema &S, ObjCProtocolDecl *PDecl, ObjCCategoryDecl *CDecl);
+
+static void DiagnoseCategoryDirectMembersProtocolConformance(
+ Sema &S, ObjCCategoryDecl *CDecl,
+ const llvm::iterator_range<ObjCProtocolList::iterator> &Protocols) {
+ for (auto *PI : Protocols)
+ DiagnoseCategoryDirectMembersProtocolConformance(S, PI, CDecl);
+}
+
+static void DiagnoseCategoryDirectMembersProtocolConformance(
+ Sema &S, ObjCProtocolDecl *PDecl, ObjCCategoryDecl *CDecl) {
+ if (!PDecl->isThisDeclarationADefinition() && PDecl->getDefinition())
+ PDecl = PDecl->getDefinition();
+
+ llvm::SmallVector<const Decl *, 4> DirectMembers;
+ const auto *IDecl = CDecl->getClassInterface();
+ for (auto *MD : PDecl->methods()) {
+ if (!MD->isPropertyAccessor()) {
+ if (const auto *CMD =
+ IDecl->getMethod(MD->getSelector(), MD->isInstanceMethod())) {
+ if (CMD->isDirectMethod())
+ DirectMembers.push_back(CMD);
+ }
+ }
+ }
+ for (auto *PD : PDecl->properties()) {
+ if (const auto *CPD = IDecl->FindPropertyVisibleInPrimaryClass(
+ PD->getIdentifier(),
+ PD->isClassProperty()
+ ? ObjCPropertyQueryKind::OBJC_PR_query_class
+ : ObjCPropertyQueryKind::OBJC_PR_query_instance)) {
+ if (CPD->isDirectProperty())
+ DirectMembers.push_back(CPD);
+ }
+ }
+ if (!DirectMembers.empty()) {
+ S.Diag(CDecl->getLocation(), diag::err_objc_direct_protocol_conformance)
+ << CDecl->IsClassExtension() << CDecl << PDecl << IDecl;
+ for (const auto *MD : DirectMembers)
+ S.Diag(MD->getLocation(), diag::note_direct_member_here);
+ return;
+ }
+
+ // Check on this protocols's referenced protocols, recursively.
+ DiagnoseCategoryDirectMembersProtocolConformance(S, CDecl,
+ PDecl->protocols());
+}
+
// Note: For class/category implementations, allMethods is always null.
Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods,
ArrayRef<DeclGroupPtrTy> allTUVars) {
ObjCInterfaceDecl *CCPrimary = C->getClassInterface();
DiagnoseClassExtensionDupMethods(C, CCPrimary);
}
+
+ DiagnoseCategoryDirectMembersProtocolConformance(*this, C, C->protocols());
}
if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(ClassDecl)) {
if (CDecl->getIdentifier())
--- /dev/null
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+__attribute__((objc_root_class))
+@interface RootClass
+
+- (void)baseMethod;
+
+@end
+
+__attribute__((objc_direct_members))
+@interface I : RootClass
+
+- (void)direct; // expected-note {{direct member declared here}}
+
+@end
+
+@protocol P
+- (void)direct;
+@end
+
+@interface I (Cat1) <P> // expected-error {{category 'Cat1' cannot conform to protocol 'P' because of direct members declared in interface 'I'}}
+@end
+
+@protocol BaseP
+- (void)baseMethod;
+@end
+
+@interface I (CatBase) <BaseP> // OK
+@end
+
+@protocol P2
+- (void)indirect;
+@end
+
+@interface I (Cat2) <P2> // OK
+- (void)indirect;
+@end
+
+@protocol P3
+- (void)indirect3;
+@end
+
+@interface I (Cat3) <P3> // OK
+@end
+
+@interface ExpDirect : RootClass
+
+- (void)direct __attribute__((objc_direct)); // expected-note {{direct member declared here}}
+
+- (void)directRecursive __attribute__((objc_direct)); // expected-note {{direct member declared here}}
+
+@end
+
+@interface ExpDirect (CatExpDirect) <P> // expected-error {{category 'CatExpDirect' cannot conform to protocol 'P' because of direct members declared in interface 'ExpDirect'}}
+@end
+
+@protocol PRecursive1
+- (void)directRecursive;
+@end
+
+@protocol PRecursiveTop <PRecursive1>
+@end
+
+@interface ExpDirect () <PRecursiveTop> // expected-error {{class extension cannot conform to protocol 'PRecursive1' because of direct members declared in interface 'ExpDirect'}}
+@end
+
+
+@protocol PProp
+
+@property (nonatomic, readonly) I *name;
+
+@end
+
+__attribute__((objc_direct_members))
+@interface IProp1 : RootClass
+
+@property (nonatomic, readonly) I *name; // expected-note {{direct member declared here}}
+
+@end
+
+@interface IProp1 () <PProp> // expected-error {{class extension cannot conform to protocol 'PProp' because of direct members declared in interface 'IProp1'}}
+@end
+
+
+@protocol PProp2
+
+@property (nonatomic, readonly, class) I *name;
+
+@end
+
+@interface IProp2 : RootClass
+
+@property (nonatomic, readonly, class, direct) I *name; // expected-note {{direct member declared here}}
+
+@end
+
+@interface IProp2 () <PProp2> // expected-error {{class extension cannot conform to protocol 'PProp2' because of direct members declared in interface 'IProp2'}}
+@end