[llvm-branch-commits] [clang] db226cd - [objc] diagnose protocol conformance in categories with direct members
Alex Lorenz via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Dec 4 16:00:54 PST 2020
Author: Alex Lorenz
Date: 2020-12-04T15:55:34-08:00
New Revision: db226cdf4cf91f350267da1a5b95dda42dd23413
URL: https://github.com/llvm/llvm-project/commit/db226cdf4cf91f350267da1a5b95dda42dd23413
DIFF: https://github.com/llvm/llvm-project/commit/db226cdf4cf91f350267da1a5b95dda42dd23413.diff
LOG: [objc] diagnose protocol conformance in categories with direct members
in their corresponding class interfaces
Categories that add protocol conformances to classes with direct members should prohibit protocol
conformances when the methods/properties that the protocol expects are actually declared as 'direct' in the class.
Differential Revision: https://reviews.llvm.org/D92602
Added:
clang/test/SemaObjC/category-direct-members-protocol-conformance.m
Modified:
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/Sema/SemaDeclObjC.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 21660965abf7..01a521fc603e 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1062,6 +1062,10 @@ def warn_objc_direct_property_ignored : Warning<
InGroup<IgnoredAttributes>;
def err_objc_direct_dynamic_property : Error<
"direct property cannot be @dynamic">;
+def err_objc_direct_protocol_conformance : Error<
+ "%select{category %1|class extension}0 cannot conform to protocol %2 because "
+ "of direct members declared in interface %3">;
+def note_direct_member_here : Note<"direct member declared here">;
def warn_conflicting_overriding_ret_types : Warning<
"conflicting return type in "
diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp
index a48919685ba2..60253a82e93a 100644
--- a/clang/lib/Sema/SemaDeclObjC.cpp
+++ b/clang/lib/Sema/SemaDeclObjC.cpp
@@ -3912,6 +3912,55 @@ static void DiagnoseVariableSizedIvars(Sema &S, ObjCContainerDecl *OCD) {
}
}
+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) {
@@ -4012,6 +4061,8 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods,
ObjCInterfaceDecl *CCPrimary = C->getClassInterface();
DiagnoseClassExtensionDupMethods(C, CCPrimary);
}
+
+ DiagnoseCategoryDirectMembersProtocolConformance(*this, C, C->protocols());
}
if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(ClassDecl)) {
if (CDecl->getIdentifier())
diff --git a/clang/test/SemaObjC/category-direct-members-protocol-conformance.m b/clang/test/SemaObjC/category-direct-members-protocol-conformance.m
new file mode 100644
index 000000000000..dfee42f58869
--- /dev/null
+++ b/clang/test/SemaObjC/category-direct-members-protocol-conformance.m
@@ -0,0 +1,98 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+__attribute__((objc_root_class))
+ at interface RootClass
+
+- (void)baseMethod;
+
+ at end
+
+__attribute__((objc_direct_members))
+ at interface I : RootClass
+
+- (void)direct; // expected-note {{direct member declared here}}
+
+ at end
+
+ at protocol P
+- (void)direct;
+ at end
+
+ at interface I (Cat1) <P> // expected-error {{category 'Cat1' cannot conform to protocol 'P' because of direct members declared in interface 'I'}}
+ at end
+
+ at protocol BaseP
+- (void)baseMethod;
+ at end
+
+ at interface I (CatBase) <BaseP> // OK
+ at end
+
+ at protocol P2
+- (void)indirect;
+ at end
+
+ at interface I (Cat2) <P2> // OK
+- (void)indirect;
+ at end
+
+ at protocol P3
+- (void)indirect3;
+ at end
+
+ at interface I (Cat3) <P3> // OK
+ at end
+
+ at 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}}
+
+ at end
+
+ at interface ExpDirect (CatExpDirect) <P> // expected-error {{category 'CatExpDirect' cannot conform to protocol 'P' because of direct members declared in interface 'ExpDirect'}}
+ at end
+
+ at protocol PRecursive1
+- (void)directRecursive;
+ at end
+
+ at protocol PRecursiveTop <PRecursive1>
+ at end
+
+ at interface ExpDirect () <PRecursiveTop> // expected-error {{class extension cannot conform to protocol 'PRecursive1' because of direct members declared in interface 'ExpDirect'}}
+ at end
+
+
+ at protocol PProp
+
+ at property (nonatomic, readonly) I *name;
+
+ at end
+
+__attribute__((objc_direct_members))
+ at interface IProp1 : RootClass
+
+ at property (nonatomic, readonly) I *name; // expected-note {{direct member declared here}}
+
+ at end
+
+ at interface IProp1 () <PProp> // expected-error {{class extension cannot conform to protocol 'PProp' because of direct members declared in interface 'IProp1'}}
+ at end
+
+
+ at protocol PProp2
+
+ at property (nonatomic, readonly, class) I *name;
+
+ at end
+
+ at interface IProp2 : RootClass
+
+ at property (nonatomic, readonly, class, direct) I *name; // expected-note {{direct member declared here}}
+
+ at end
+
+ at interface IProp2 () <PProp2> // expected-error {{class extension cannot conform to protocol 'PProp2' because of direct members declared in interface 'IProp2'}}
+ at end
More information about the llvm-branch-commits
mailing list