diff options
author | Alex Lorenz <arphaman@gmail.com> | 2020-12-04 15:06:13 -0800 |
---|---|---|
committer | Alex Lorenz <arphaman@gmail.com> | 2020-12-04 15:55:34 -0800 |
commit | db226cdf4cf91f350267da1a5b95dda42dd23413 (patch) | |
tree | 25b8ceea34ea0c7345347cc68396676fca851998 /clang/lib/Sema/SemaDeclObjC.cpp | |
parent | eddd1d192bcaf11e449b34a3a569b85eb390e4f2 (diff) | |
download | llvm-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.cpp | 51 |
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()) |