]> granicus.if.org Git - clang/commitdiff
Objective-C: When reporting on missing property accessor implementation in
authorFariborz Jahanian <fjahanian@apple.com>
Wed, 24 Apr 2013 17:06:38 +0000 (17:06 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Wed, 24 Apr 2013 17:06:38 +0000 (17:06 +0000)
categories, do not report when they are declared in primary class,
class's protocol, or one of it super classes. This is because,
its class is going to implement them. // rdar://13713098

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@180198 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/DeclObjC.h
include/clang/Sema/Sema.h
lib/AST/DeclObjC.cpp
lib/Sema/SemaDeclObjC.cpp
lib/Sema/SemaObjCProperty.cpp
test/SemaObjC/property-category-4.m
test/SemaObjC/property.m

index c29492298bfcfa5a468e187734a4ac20469c4db4..86cf7fc5aff95152e92a842384e0b5647c32febb 100644 (file)
@@ -1136,7 +1136,8 @@ public:
   // Lookup a method. First, we search locally. If a method isn't
   // found, we search referenced protocols and class categories.
   ObjCMethodDecl *lookupMethod(Selector Sel, bool isInstance,
-                               bool shallowCategoryLookup= false) const;
+                               bool shallowCategoryLookup= false,
+                               bool CategoryLookup= true) const;
   ObjCMethodDecl *lookupInstanceMethod(Selector Sel,
                             bool shallowCategoryLookup = false) const {
     return lookupMethod(Sel, true/*isInstance*/, shallowCategoryLookup);
@@ -1155,6 +1156,15 @@ public:
     return lookupPrivateMethod(Sel, false);
   }
 
+  /// \brief Lookup a setter or getter in the class hierarchy.
+  /// In this lookup, only class hierarchy and not its categories
+  /// are looked up
+  ObjCMethodDecl *lookupPropertyAccessor(const Selector Sel) const {
+     return lookupMethod(Sel, true/*isInstance*/,
+                         false /*shallowCategoryLookup*/,
+                         false /*CategoryLookup*/);
+  }
+
   SourceLocation getEndOfDefinitionLoc() const { 
     if (!hasDefinition())
       return getLocation();
index 352784e7ef10b2757982ea9fb3121e5d42a4c717..629d775a1bdccda281d9cad8620c7f36792b59e2 100644 (file)
@@ -2475,8 +2475,7 @@ public:
   /// DiagnoseUnimplementedProperties - This routine warns on those properties
   /// which must be implemented by this implementation.
   void DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
-                                       ObjCContainerDecl *CDecl,
-                                       const SelectorSet &InsMap);
+                                       ObjCContainerDecl *CDecl);
 
   /// DefaultSynthesizeProperties - This routine default synthesizes all
   /// properties which must be synthesized in the class's \@implementation.
index 08c59b567d1982cddab3d7ce601be8551a919ce4..43a128137be04fab0d2d258a6308774f6eb4dafa 100644 (file)
@@ -445,7 +445,8 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::lookupInheritedClass(
 /// the class, its categories, and its super classes (using a linear search).
 ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel, 
                                      bool isInstance,
-                                     bool shallowCategoryLookup) const {
+                                     bool shallowCategoryLookup,
+                                     bool CategoryLookup) const {
   // FIXME: Should make sure no callers ever do this.
   if (!hasDefinition())
     return 0;
@@ -468,23 +469,24 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel,
         return MethodDecl;
     
     // Didn't find one yet - now look through categories.
-    for (ObjCInterfaceDecl::visible_categories_iterator
+    if (CategoryLookup)
+      for (ObjCInterfaceDecl::visible_categories_iterator
            Cat = ClassDecl->visible_categories_begin(),
            CatEnd = ClassDecl->visible_categories_end();
-         Cat != CatEnd; ++Cat) {
-      if ((MethodDecl = Cat->getMethod(Sel, isInstance)))
-        return MethodDecl;
-
-      if (!shallowCategoryLookup) {
-        // Didn't find one yet - look through protocols.
-        const ObjCList<ObjCProtocolDecl> &Protocols =
-          Cat->getReferencedProtocols();
-        for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
-             E = Protocols.end(); I != E; ++I)
-          if ((MethodDecl = (*I)->lookupMethod(Sel, isInstance)))
-            return MethodDecl;
+           Cat != CatEnd; ++Cat) {
+        if ((MethodDecl = Cat->getMethod(Sel, isInstance)))
+          return MethodDecl;
+
+        if (!shallowCategoryLookup) {
+          // Didn't find one yet - look through protocols.
+          const ObjCList<ObjCProtocolDecl> &Protocols =
+            Cat->getReferencedProtocols();
+          for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
+               E = Protocols.end(); I != E; ++I)
+            if ((MethodDecl = (*I)->lookupMethod(Sel, isInstance)))
+              return MethodDecl;
+        }
       }
-    }
   
     ClassDecl = ClassDecl->getSuperClass();
   }
index 0e0672c2c30a3511f8eb9ae63f397243683bb208..271c7fcf36e08abf9132b5841c4aa5e7be386e44 100644 (file)
@@ -1836,7 +1836,7 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
     if  (!(LangOpts.ObjCDefaultSynthProperties &&
            LangOpts.ObjCRuntime.isNonFragile()) ||
          IDecl->isObjCRequiresPropertyDefs())
-      DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, InsMap);
+      DiagnoseUnimplementedProperties(S, IMPDecl, CDecl);
       
   SelectorSet ClsMap;
   for (ObjCImplementationDecl::classmeth_iterator
@@ -1883,17 +1883,7 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
            E = C->protocol_end(); PI != E; ++PI)
         CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl,
                                 InsMap, ClsMap, CDecl);
-      // Report unimplemented properties in the category as well.
-      // When reporting on missing setter/getters, do not report when
-      // setter/getter is implemented in category's primary class 
-      // implementation.
-      if (ObjCInterfaceDecl *ID = C->getClassInterface())
-        if (ObjCImplDecl *IMP = ID->getImplementation()) {
-          for (ObjCImplementationDecl::instmeth_iterator
-               I = IMP->instmeth_begin(), E = IMP->instmeth_end(); I!=E; ++I)
-            InsMap.insert((*I)->getSelector());
-        }
-      DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, InsMap);      
+      DiagnoseUnimplementedProperties(S, IMPDecl, CDecl);
     } 
   } else
     llvm_unreachable("invalid ObjCContainerDecl type.");
index c348a9cb76874d9aa70f6c95ca23172a9de15bc6..2efd43ee3104144dbeedd16212303a8699b06e82 100644 (file)
@@ -1660,8 +1660,7 @@ void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) {
 }
 
 void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
-                                      ObjCContainerDecl *CDecl,
-                                      const SelectorSet &InsMap) {
+                                      ObjCContainerDecl *CDecl) {
   ObjCContainerDecl::PropertyMap NoNeedToImplPropMap;
   ObjCInterfaceDecl *IDecl;
   // Gather properties which need not be implemented in this class
@@ -1690,6 +1689,26 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
        EI = IMPDecl->propimpl_end(); I != EI; ++I)
     PropImplMap.insert(I->getPropertyDecl());
 
+  SelectorSet InsMap;
+  // Collect property accessors implemented in current implementation.
+  for (ObjCImplementationDecl::instmeth_iterator
+       I = IMPDecl->instmeth_begin(), E = IMPDecl->instmeth_end(); I!=E; ++I)
+    InsMap.insert((*I)->getSelector());
+  
+  ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl);
+  ObjCInterfaceDecl *PrimaryClass = 0;
+  if (C && !C->IsClassExtension())
+    if ((PrimaryClass = C->getClassInterface()))
+      // Report unimplemented properties in the category as well.
+      if (ObjCImplDecl *IMP = PrimaryClass->getImplementation()) {
+        // When reporting on missing setter/getters, do not report when
+        // setter/getter is implemented in category's primary class
+        // implementation.
+        for (ObjCImplementationDecl::instmeth_iterator
+             I = IMP->instmeth_begin(), E = IMP->instmeth_end(); I!=E; ++I)
+          InsMap.insert((*I)->getSelector());
+      }
+
   for (ObjCContainerDecl::PropertyMap::iterator
        P = PropMap.begin(), E = PropMap.end(); P != E; ++P) {
     ObjCPropertyDecl *Prop = P->second;
@@ -1699,7 +1718,13 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
         PropImplMap.count(Prop) ||
         Prop->getAvailability() == AR_Unavailable)
       continue;
-    if (!InsMap.count(Prop->getGetterName())) {
+    // When reporting on missing property getter implementation in
+    // categories, do not report when they are declared in primary class,
+    // class's protocol, or one of it super classes. This is because,
+    // the class is going to implement them.
+    if (!InsMap.count(Prop->getGetterName()) &&
+        (PrimaryClass == 0 ||
+         !PrimaryClass->lookupPropertyAccessor(Prop->getGetterName()))) {
       Diag(IMPDecl->getLocation(),
            isa<ObjCCategoryDecl>(CDecl) ?
             diag::warn_setter_getter_impl_required_in_category :
@@ -1713,8 +1738,13 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
             Diag(RID->getLocation(), diag::note_suppressed_class_declare);
             
     }
-
-    if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) {
+    // When reporting on missing property setter implementation in
+    // categories, do not report when they are declared in primary class,
+    // class's protocol, or one of it super classes. This is because,
+    // the class is going to implement them.
+    if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName()) &&
+        (PrimaryClass == 0 ||
+         !PrimaryClass->lookupPropertyAccessor(Prop->getSetterName()))) {
       Diag(IMPDecl->getLocation(),
            isa<ObjCCategoryDecl>(CDecl) ?
            diag::warn_setter_getter_impl_required_in_category :
index e7939b32c114126e7c803617b8daf0e7bd0c1aef..f99bd52998c2015fa874aca453b1a78904ea323a 100644 (file)
 @dynamic d_selectedObjects; // expected-error {{property declared in category 'CAT' cannot be implemented in class implementation}}
 @end
 
+
+// rdar://13713098
+// Test1
+@interface NSArray 
+- (int)count;
+@end
+
+@protocol MyCountable
+@property  (readonly) int count;
+@end
+
+
+@interface NSArray(Additions) <MyCountable>
+@end
+
+@implementation NSArray(Additions)
+@end
+
+// Test2
+@protocol NSProtocol
+- (int)count;
+@end
+
+@interface NSArray1 <NSProtocol>
+@end
+
+@interface NSArray1(Additions) <MyCountable>
+@end
+
+@implementation NSArray1(Additions)
+@end
+
+// Test3
+@interface Super <NSProtocol>
+@end
+
+@interface NSArray2 : Super @end
+
+@interface NSArray2(Additions) <MyCountable>
+@end
+
+@implementation NSArray2(Additions)
+@end
+
+// Test3
+@interface Super1 <NSProtocol>
+@property  (readonly) int count;
+@end
+
+@protocol MyCountable1
+@end
+
+@interface NSArray3 : Super1 <MyCountable1>
+@end
+
+@implementation NSArray3
+@end
+
+// Test4
+@interface I
+@property int d1;
+@end
+
+@interface I(CAT)
+@property int d1;
+@end
+
+@implementation I(CAT)
+@end
index 76fdf5b242a225d543b3cf23a093ad9d7a2043f5..748544717386b0c2cd4b7991b2188f9a494d1b17 100644 (file)
@@ -11,7 +11,7 @@
 @end
 
 @interface I(CAT)
-@property int d1;      // expected-note 2 {{property declared here}}
+@property int d1;
 @end
 
 @implementation I
@@ -22,8 +22,7 @@
 @synthesize name;      // OK! property with same name as an accessible ivar of same name
 @end
 
-@implementation I(CAT)  // expected-warning {{property 'd1' requires method 'd1' to be defined }} \
-                        // expected-warning {{property 'd1' requires method 'setD1:' to be defined }}
+@implementation I(CAT) 
 @synthesize d1;                // expected-error {{@synthesize not allowed in a category's implementation}}
 @dynamic bad;          // expected-error {{property implementation must have its declaration in the category 'CAT'}}
 @end