From 1035a959dafb867fe30eeb70cc59f3cd7f905492 Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Sat, 22 Feb 2014 00:02:03 +0000 Subject: [PATCH] [ObjC] Make attribute 'objc_protocol_requires_explicit_implementation' behave correctly with default property synthesis. In particular, if we see an @property within the @interface of a class conforming to a protocol with this attribute, we treat that as if the implementation were available, per the rules of default property synthesis. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@201911 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Sema.h | 6 --- lib/Sema/SemaObjCProperty.cpp | 50 ++++++++++++++----- .../SemaObjC/protocols-suppress-conformance.m | 13 +++++ 3 files changed, 50 insertions(+), 19 deletions(-) diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 98893d1aed..14eb7ad560 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -2667,12 +2667,6 @@ public: ObjCInterfaceDecl *IDecl); void DefaultSynthesizeProperties(Scope *S, Decl *D); - /// CollectImmediateProperties - This routine collects all properties in - /// the class and its conforming protocols; but not those it its super class. - void CollectImmediateProperties(ObjCContainerDecl *CDecl, - llvm::DenseMap& PropMap, - llvm::DenseMap& SuperPropMap); - /// IvarBacksCurrentMethodAccessor - This routine returns 'true' if 'IV' is /// an ivar synthesized for 'Method' and 'Method' is a property accessor /// declared in class 'IFace'. diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index 9b3643a2ed..08013f7cc1 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -1440,20 +1440,24 @@ bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property, /// CollectImmediateProperties - This routine collects all properties in /// the class and its conforming protocols; but not those in its super class. -void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl, - ObjCContainerDecl::PropertyMap &PropMap, - ObjCContainerDecl::PropertyMap &SuperPropMap) { +static void CollectImmediateProperties(ObjCContainerDecl *CDecl, + ObjCContainerDecl::PropertyMap &PropMap, + ObjCContainerDecl::PropertyMap &SuperPropMap, + bool IncludeProtocols = true) { + if (ObjCInterfaceDecl *IDecl = dyn_cast(CDecl)) { for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(), E = IDecl->prop_end(); P != E; ++P) { ObjCPropertyDecl *Prop = *P; PropMap[Prop->getIdentifier()] = Prop; } - // scan through class's protocols. - for (ObjCInterfaceDecl::all_protocol_iterator - PI = IDecl->all_referenced_protocol_begin(), - E = IDecl->all_referenced_protocol_end(); PI != E; ++PI) - CollectImmediateProperties((*PI), PropMap, SuperPropMap); + if (IncludeProtocols) { + // Scan through class's protocols. + for (ObjCInterfaceDecl::all_protocol_iterator + PI = IDecl->all_referenced_protocol_begin(), + E = IDecl->all_referenced_protocol_end(); PI != E; ++PI) + CollectImmediateProperties((*PI), PropMap, SuperPropMap); + } } if (ObjCCategoryDecl *CATDecl = dyn_cast(CDecl)) { if (!CATDecl->IsClassExtension()) @@ -1462,10 +1466,12 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl, ObjCPropertyDecl *Prop = *P; PropMap[Prop->getIdentifier()] = Prop; } - // scan through class's protocols. - for (ObjCCategoryDecl::protocol_iterator PI = CATDecl->protocol_begin(), - E = CATDecl->protocol_end(); PI != E; ++PI) - CollectImmediateProperties((*PI), PropMap, SuperPropMap); + if (IncludeProtocols) { + // Scan through class's protocols. + for (ObjCCategoryDecl::protocol_iterator PI = CATDecl->protocol_begin(), + E = CATDecl->protocol_end(); PI != E; ++PI) + CollectImmediateProperties((*PI), PropMap, SuperPropMap); + } } else if (ObjCProtocolDecl *PDecl = dyn_cast(CDecl)) { for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), @@ -1678,7 +1684,9 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, // Scan the @interface to see if any of the protocols it adopts // require an explicit implementation, via attribute // 'objc_protocol_requires_explicit_implementation'. - if (IDecl) + if (IDecl) { + OwningPtr LazyMap; + for (ObjCInterfaceDecl::all_protocol_iterator PI = IDecl->all_referenced_protocol_begin(), PE = IDecl->all_referenced_protocol_end(); @@ -1686,15 +1694,31 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, ObjCProtocolDecl *PDecl = *PI; if (!PDecl->hasAttr()) continue; + // Lazily construct a set of all the properties in the @interface + // of the class, without looking at the superclass. We cannot + // use the call to CollectImmediateProperties() above as that + // utilizes information fromt he super class's properties as well + // as scans the adopted protocols. This work only triggers for protocols + // with the attribute, which is very rare, and only occurs when + // analyzing the @implementation. + if (!LazyMap) { + ObjCContainerDecl::PropertyMap NoNeedToImplPropMap; + LazyMap.reset(new ObjCContainerDecl::PropertyMap()); + CollectImmediateProperties(CDecl, *LazyMap, NoNeedToImplPropMap, + /* IncludeProtocols */ false); + } // Add the properties of 'PDecl' to the list of properties that // need to be implemented. for (ObjCProtocolDecl::prop_iterator PRI = PDecl->prop_begin(), PRE = PDecl->prop_end(); PRI != PRE; ++PRI) { ObjCPropertyDecl *PropDecl = *PRI; + if ((*LazyMap)[PRI->getIdentifier()]) + continue; PropMap[PRI->getIdentifier()] = PropDecl; } } + } if (PropMap.empty()) return; diff --git a/test/SemaObjC/protocols-suppress-conformance.m b/test/SemaObjC/protocols-suppress-conformance.m index 406c9132a8..9ec2a1ae8b 100644 --- a/test/SemaObjC/protocols-suppress-conformance.m +++ b/test/SemaObjC/protocols-suppress-conformance.m @@ -32,6 +32,19 @@ __attribute__((objc_protocol_requires_explicit_implementation)) @dynamic theWorstOfTimes; @end +@interface ClassB_AlsoGood : ClassA +@property (readonly) id theWorstOfTimes; +@end + +// Default synthesis acts as if @dynamic +// had been written for 'theWorstOfTimes' because +// it is declared in ClassA. This is okay, since +// the author of ClassB_AlsoGood needs explicitly +// write @property in the @interface. +@implementation ClassB_AlsoGood // no-warning +- (void) theBestOfTimes {} +@end + // Test that inherited protocols do not get the explicit conformance requirement. @protocol Inherited - (void) fairIsFoul; -- 2.49.0