aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFariborz Jahanian <fjahanian@apple.com>2009-04-14 23:15:21 +0000
committerFariborz Jahanian <fjahanian@apple.com>2009-04-14 23:15:21 +0000
commit12bac2566e3136d4bd9d42e6aabe27e1038f7793 (patch)
tree98708e06f188f9f3fe85e92ff123c91a2b38950c
parentb90bb0099e9c8914ba18ddb2d30f9369b6de74d5 (diff)
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
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td5
-rw-r--r--lib/Sema/SemaDeclObjC.cpp71
-rw-r--r--test/SemaObjC/property-category-1.m4
-rw-r--r--test/SemaObjC/property.m4
4 files changed, 61 insertions, 23 deletions
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<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,
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