r201911 - [ObjC] Make attribute 'objc_protocol_requires_explicit_implementation' behave correctly with default property synthesis.

Ted Kremenek kremenek at apple.com
Fri Feb 21 16:02:04 PST 2014


Author: kremenek
Date: Fri Feb 21 18:02:03 2014
New Revision: 201911

URL: http://llvm.org/viewvc/llvm-project?rev=201911&view=rev
Log:
[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.

Modified:
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaObjCProperty.cpp
    cfe/trunk/test/SemaObjC/protocols-suppress-conformance.m

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=201911&r1=201910&r2=201911&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Feb 21 18:02:03 2014
@@ -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<IdentifierInfo *, ObjCPropertyDecl*>& PropMap,
-            llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& SuperPropMap);
-  
   /// IvarBacksCurrentMethodAccessor - This routine returns 'true' if 'IV' is
   /// an ivar synthesized for 'Method' and 'Method' is a property accessor
   /// declared in class 'IFace'.

Modified: cfe/trunk/lib/Sema/SemaObjCProperty.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaObjCProperty.cpp?rev=201911&r1=201910&r2=201911&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaObjCProperty.cpp (original)
+++ cfe/trunk/lib/Sema/SemaObjCProperty.cpp Fri Feb 21 18:02:03 2014
@@ -1440,20 +1440,24 @@ bool Sema::DiagnosePropertyAccessorMisma
 
 /// 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<ObjCInterfaceDecl>(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<ObjCCategoryDecl>(CDecl)) {
     if (!CATDecl->IsClassExtension())
@@ -1462,10 +1466,12 @@ void Sema::CollectImmediateProperties(Ob
         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<ObjCProtocolDecl>(CDecl)) {
     for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
@@ -1678,7 +1684,9 @@ void Sema::DiagnoseUnimplementedProperti
   // 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<ObjCContainerDecl::PropertyMap> LazyMap;
+
     for (ObjCInterfaceDecl::all_protocol_iterator
           PI = IDecl->all_referenced_protocol_begin(),
           PE = IDecl->all_referenced_protocol_end();
@@ -1686,15 +1694,31 @@ void Sema::DiagnoseUnimplementedProperti
       ObjCProtocolDecl *PDecl = *PI;
       if (!PDecl->hasAttr<ObjCExplicitProtocolImplAttr>())
         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;

Modified: cfe/trunk/test/SemaObjC/protocols-suppress-conformance.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/protocols-suppress-conformance.m?rev=201911&r1=201910&r2=201911&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/protocols-suppress-conformance.m (original)
+++ cfe/trunk/test/SemaObjC/protocols-suppress-conformance.m Fri Feb 21 18:02:03 2014
@@ -32,6 +32,19 @@ __attribute__((objc_protocol_requires_ex
 @dynamic theWorstOfTimes;
 @end
 
+ at interface ClassB_AlsoGood : ClassA <Protocol>
+ at property (readonly) id theWorstOfTimes;
+ at 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.
+ at implementation ClassB_AlsoGood // no-warning
+- (void) theBestOfTimes {}
+ at end
+
 // Test that inherited protocols do not get the explicit conformance requirement.
 @protocol Inherited
 - (void) fairIsFoul;





More information about the cfe-commits mailing list