aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema/SemaDeclObjC.cpp
diff options
context:
space:
mode:
authorAlex Lorenz <arphaman@gmail.com>2020-12-04 15:06:13 -0800
committerAlex Lorenz <arphaman@gmail.com>2020-12-04 15:55:34 -0800
commitdb226cdf4cf91f350267da1a5b95dda42dd23413 (patch)
tree25b8ceea34ea0c7345347cc68396676fca851998 /clang/lib/Sema/SemaDeclObjC.cpp
parenteddd1d192bcaf11e449b34a3a569b85eb390e4f2 (diff)
downloadllvm-db226cdf4cf91f350267da1a5b95dda42dd23413.zip
llvm-db226cdf4cf91f350267da1a5b95dda42dd23413.tar.gz
llvm-db226cdf4cf91f350267da1a5b95dda42dd23413.tar.bz2
[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
Diffstat (limited to 'clang/lib/Sema/SemaDeclObjC.cpp')
-rw-r--r--clang/lib/Sema/SemaDeclObjC.cpp51
1 files changed, 51 insertions, 0 deletions
diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp
index a489196..60253a8 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())