diff options
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 3 | ||||
-rw-r--r-- | lib/Sema/SemaDeclObjC.cpp | 30 | ||||
-rw-r--r-- | test/SemaObjC/property-category-2.m | 5 | ||||
-rw-r--r-- | test/SemaObjC/property-category-impl.m | 31 | ||||
-rw-r--r-- | test/SemaObjC/property.m | 5 |
5 files changed, 68 insertions, 6 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 78173be8b5..353cd0e3db 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1840,6 +1840,9 @@ def err_illegal_super_cast : Error< def warn_setter_getter_impl_required : Warning< "property %0 requires method %1 to be defined - " "use @synthesize, @dynamic or provide a method implementation">; +def warn_setter_getter_impl_required_in_category : Warning< + "property %0 requires method %1 to be defined - " + "use @dynamic or provide a method implementation in category">; def note_property_impl_required : Note< "implementation is here">; diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index a0086ecc4f..3738b9c4fe 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -1101,6 +1101,17 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl, E = IDecl->protocol_end(); PI != E; ++PI) CollectImmediateProperties((*PI), PropMap); } + if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) { + for (ObjCContainerDecl::prop_iterator P = CATDecl->prop_begin(), + E = CATDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = (*P); + PropMap[Prop->getIdentifier()] = Prop; + } + // scan through class's protocols. + for (ObjCInterfaceDecl::protocol_iterator PI = CATDecl->protocol_begin(), + E = CATDecl->protocol_end(); PI != E; ++PI) + CollectImmediateProperties((*PI), PropMap); + } else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) { for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), E = PDecl->prop_end(); P != E; ++P) { @@ -1141,7 +1152,9 @@ void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl, if (!InsMap.count(Prop->getGetterName())) { Diag(Prop->getLocation(), - diag::warn_setter_getter_impl_required) + isa<ObjCCategoryDecl>(CDecl) ? + diag::warn_setter_getter_impl_required_in_category : + diag::warn_setter_getter_impl_required) << Prop->getDeclName() << Prop->getGetterName(); Diag(IMPDecl->getLocation(), diag::note_property_impl_required); @@ -1149,6 +1162,8 @@ void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl, if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) { Diag(Prop->getLocation(), + isa<ObjCCategoryDecl>(CDecl) ? + diag::warn_setter_getter_impl_required_in_category : diag::warn_setter_getter_impl_required) << Prop->getDeclName() << Prop->getSetterName(); Diag(IMPDecl->getLocation(), @@ -1212,7 +1227,18 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, E = C->protocol_end(); PI != E; ++PI) CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl, InsMap, ClsMap, C->getClassInterface()); - } + // 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(IMPDecl, CDecl, InsMap); + } } else assert(false && "invalid ObjCContainerDecl type."); } diff --git a/test/SemaObjC/property-category-2.m b/test/SemaObjC/property-category-2.m index f258b2c250..e63672bb0a 100644 --- a/test/SemaObjC/property-category-2.m +++ b/test/SemaObjC/property-category-2.m @@ -4,7 +4,8 @@ @protocol MyProtocol @property float myFloat; -@property float anotherFloat; +@property float anotherFloat; // expected-warning {{property 'anotherFloat' requires method 'anotherFloat' to be defined - use @dynamic}} \ + // expected-warning {{property 'anotherFloat' requires method 'setAnotherFloat:' to be defined }} @end @interface MyObject { float anotherFloat; } @@ -13,7 +14,7 @@ @interface MyObject (CAT) <MyProtocol> @end -@implementation MyObject (CAT) +@implementation MyObject (CAT) // expected-note 2 {{implementation is here}} @dynamic myFloat; // OK @synthesize anotherFloat; // expected-error {{@synthesize not allowed in a category's implementation}} @end diff --git a/test/SemaObjC/property-category-impl.m b/test/SemaObjC/property-category-impl.m new file mode 100644 index 0000000000..997949778c --- /dev/null +++ b/test/SemaObjC/property-category-impl.m @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +/* This test is for categories which don't implement the accessors but some accessors are + implemented in their base class implementation. In this case,no warning must be issued. +*/ + +@interface MyClass +{ + int _foo; +} +@property(readonly) int foo; +@end + +@implementation MyClass +- (int) foo { return _foo; } +@end + +@interface MyClass (private) +@property(readwrite) int foo; +@end + +@implementation MyClass (private) +- (void) setFoo:(int)foo { _foo = foo; } +@end + +@interface MyClass (public) +@property(readwrite) int foo; // expected-warning {{property 'foo' requires method 'setFoo:' to be defined }} +@end + +@implementation MyClass (public)// expected-note {{implementation is here}} +@end diff --git a/test/SemaObjC/property.m b/test/SemaObjC/property.m index bc2056c979..b7f0fcaa76 100644 --- a/test/SemaObjC/property.m +++ b/test/SemaObjC/property.m @@ -11,7 +11,8 @@ @end @interface I(CAT) -@property int d1; +@property int d1; // expected-warning {{property 'd1' requires method 'd1' to be defined }} \ + // expected-warning {{property 'd1' requires method 'setD1:' to be defined }} @end @implementation I @@ -22,7 +23,7 @@ @synthesize name; // OK! property with same name as an accessible ivar of same name @end -@implementation I(CAT) +@implementation I(CAT) // expected-note 2 {{implementation is here}} @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 |