From: Fariborz Jahanian Date: Tue, 14 Apr 2009 23:15:21 +0000 (+0000) Subject: Diagnose properties which have no implementations; X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=12bac2566e3136d4bd9d42e6aabe27e1038f7793;p=clang Diagnose properties which have no implementations; 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 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index a29ffce41e..a3458bcaf2 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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 diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index e95b5d3840..464c78a5df 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -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(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, diff --git a/test/SemaObjC/property-category-1.m b/test/SemaObjC/property-category-1.m index c1c5dca114..6695239fd3 100644 --- a/test/SemaObjC/property-category-1.m +++ b/test/SemaObjC/property-category-1.m @@ -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}} } diff --git a/test/SemaObjC/property.m b/test/SemaObjC/property.m index 5a119c798c..cf2624f820 100644 --- a/test/SemaObjC/property.m +++ b/test/SemaObjC/property.m @@ -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