]> granicus.if.org Git - clang/commitdiff
Diagnose properties which have no implementations;
authorFariborz Jahanian <fjahanian@apple.com>
Tue, 14 Apr 2009 23:15:21 +0000 (23:15 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Tue, 14 Apr 2009 23:15:21 +0000 (23:15 +0000)
either unimplemented setter/getter or no
implementation directive.

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

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaDeclObjC.cpp
test/SemaObjC/property-category-1.m
test/SemaObjC/property.m

index a29ffce41e9868184723dfc4ec8dbba807ac1ec6..a3458bcaf2d7fb3e112369dad2d2a63ebd98ead4 100644 (file)
@@ -1039,6 +1039,11 @@ def err_illegal_qualifiers_on_catch_parm : Error<
   "illegal qualifiers on @catch parameter">;
 def err_illegal_super_cast : Error<
   "cannot cast 'super' (it isn't an expression)">;
+def warn_setter_getter_impl_required : Warning<
+  "property %0 requires method %1 to be defined - "
+  "use @synthesize, @dynamic or provide a method implementation">;
+def note_property_impl_required : Note<
+  "implementation is here">;
 
 
 // C++ casts
index e95b5d3840adf7864397b854fddf00afaaa8181a..464c78a5df10916df90d9cdfdc55c279da16115c 100644 (file)
@@ -903,6 +903,42 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
          E = IMPDecl->instmeth_end(); I != E; ++I)
     InsMap.insert((*I)->getSelector());
   
+  // Check and see if properties declared in the interface have either 1)
+  // an implementation or 2) there is a @synthesize/@dynamic implementation
+  // of the property in the @implementation.
+  if (isa<ObjCInterfaceDecl>(CDecl))
+      for (ObjCContainerDecl::prop_iterator P = CDecl->prop_begin(Context),
+       E = CDecl->prop_end(Context); P != E; ++P) {
+        ObjCPropertyDecl *Prop = (*P);
+        if (Prop->isInvalidDecl())
+          continue;
+        ObjCPropertyImplDecl *PI = 0;
+        // Is there a matching propery synthesize/dynamic?
+        for (ObjCImplDecl::propimpl_iterator I = IMPDecl->propimpl_begin(),
+             EI = IMPDecl->propimpl_end(); I != EI; ++I)
+          if ((*I)->getPropertyDecl() == Prop) {
+            PI = (*I);
+            break;
+          }
+        if (PI)
+          continue;
+        if (!InsMap.count(Prop->getGetterName())) {
+          Diag(Prop->getLocation(), 
+               diag::warn_setter_getter_impl_required) 
+          << Prop->getDeclName() << Prop->getGetterName();
+          Diag(IMPDecl->getLocation(),
+               diag::note_property_impl_required);
+        }
+    
+        if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) {
+          Diag(Prop->getLocation(), 
+               diag::warn_setter_getter_impl_required) 
+          << Prop->getDeclName() << Prop->getSetterName();
+          Diag(IMPDecl->getLocation(),
+               diag::note_property_impl_required);
+        }
+      }
+  
   for (ObjCInterfaceDecl::instmeth_iterator I = CDecl->instmeth_begin(Context),
        E = CDecl->instmeth_end(Context); I != E; ++I) {
     if (!(*I)->isSynthesized() && !InsMap.count((*I)->getSelector())) {
@@ -1798,17 +1834,15 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
     ObjCInterfaceDecl *ClassDeclared;
     Ivar = IDecl->lookupInstanceVariable(Context, PropertyIvar, ClassDeclared);
     if (!Ivar) {
-      if (getLangOptions().ObjCNonFragileABI) {
-        Ivar = ObjCIvarDecl::Create(Context, CurContext, PropertyLoc, 
-                                    PropertyIvar, PropType, 
-                                    ObjCIvarDecl::Public,
-                                    (Expr *)0);
-        property->setPropertyIvarDecl(Ivar);
-      }
-      else {
+      Ivar = ObjCIvarDecl::Create(Context, CurContext, PropertyLoc, 
+                                  PropertyIvar, PropType, 
+                                  ObjCIvarDecl::Public,
+                                  (Expr *)0);
+      property->setPropertyIvarDecl(Ivar);
+      if (!getLangOptions().ObjCNonFragileABI)
         Diag(PropertyLoc, diag::error_missing_property_ivar_decl) << PropertyId;
-        return DeclPtrTy();
-      }
+        // Note! I deliberately want it to fall thru so, we have a 
+        // a property implementation and to avoid future warnings.
     }
     else if (getLangOptions().ObjCNonFragileABI &&
              NoExplicitPropertyIvar && ClassDeclared != IDecl) {
@@ -1826,7 +1860,8 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
       if (CheckAssignmentConstraints(PropType, IvarType) != Compatible) {
         Diag(PropertyLoc, diag::error_property_ivar_type)
           << property->getDeclName() << Ivar->getDeclName();
-        return DeclPtrTy();
+        // Note! I deliberately want it to fall thru so, we have a 
+        // a property implementation and to avoid future warnings.
       }
       
       // FIXME! Rules for properties are somewhat different that those
@@ -1838,28 +1873,26 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
           lhsType->isArithmeticType()) {
         Diag(PropertyLoc, diag::error_property_ivar_type)
         << property->getDeclName() << Ivar->getDeclName();
-        return DeclPtrTy();
+        // Fall thru - see previous comment
       }
       // __weak is explicit. So it works on Canonical type.
       if (PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() &&
           getLangOptions().getGCMode() != LangOptions::NonGC) {
         Diag(PropertyLoc, diag::error_weak_property)
         << property->getDeclName() << Ivar->getDeclName();
-        return DeclPtrTy();
+        // Fall thru - see previous comment
       }
       if ((Context.isObjCObjectPointerType(property->getType()) || 
            PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() &&
            getLangOptions().getGCMode() != LangOptions::NonGC) {
         Diag(PropertyLoc, diag::error_strong_property)
         << property->getDeclName() << Ivar->getDeclName();
-        return DeclPtrTy();
+        // Fall        thru - see previous comment
       }
     }
-  } else if (PropertyIvar) {
-    // @dynamic
-    Diag(PropertyLoc, diag::error_dynamic_property_ivar_decl);
-    return DeclPtrTy();
-  }
+  } else if (PropertyIvar)
+      // @dynamic
+      Diag(PropertyLoc, diag::error_dynamic_property_ivar_decl);
   assert (property && "ActOnPropertyImplDecl - property declaration missing");
   ObjCPropertyImplDecl *PIDecl = 
     ObjCPropertyImplDecl::Create(Context, CurContext, AtLoc, PropertyLoc, 
index c1c5dca11490ab985dfccb336c1d4fb907554d7e..6695239fd3527156455014f167e21687197c4092 100644 (file)
@@ -36,7 +36,7 @@ int main(int argc, char **argv) {
 ///
 
 @interface I0
-@property(readonly) int p0;
+@property(readonly) int p0;    // expected-warning {{property 'p0' requires method 'p0' to be defined}}
 @end 
 
 @interface I0 (Cat0)
@@ -45,7 +45,7 @@ int main(int argc, char **argv) {
 @interface I0 (Cat1)
 @end 
   
-@implementation I0
+@implementation I0     // expected-note {{implementation is here}}
 - (void) foo {
   self.p0 = 0; // expected-error {{assigning to property with 'readonly' attribute not allowed}}
 }
index 5a119c798c90319645ed0869f12506a21c3864ad..cf2624f8204d603de34f5e967596ef669e10971d 100644 (file)
@@ -17,8 +17,8 @@
 @implementation I
 @synthesize d1;                // expected-error {{synthesized property 'd1' must either be named the same as}}
 @dynamic    bad;       // expected-error {{property implementation must have its declaration in interface 'I'}}
-@synthesize prop_id;   // expected-error {{synthesized property 'prop_id' must either be named the same}}
-@synthesize prop_id = IVAR;    // expected-error {{type of property 'prop_id' does not match type of ivar 'IVAR'}}
+@synthesize prop_id;   // expected-error {{synthesized property 'prop_id' must either be named the same}}  // expected-note {{previous declaration is here}}
+@synthesize prop_id = IVAR;    // expected-error {{type of property 'prop_id' does not match type of ivar 'IVAR'}} // expected-error {{property 'prop_id' is already implemented}}
 @synthesize name;      // OK! property with same name as an accessible ivar of same name
 @end