From b2ab73d93cf5f73e5e49496c36e7bc58622c7f01 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Fri, 8 May 2009 19:36:34 +0000 Subject: [PATCH] More type checking for properties, accessors and use of dot-syntax expression. This is to match gcc's. llvm-svn: 71243 --- .../clang/Basic/DiagnosticSemaKinds.td | 2 +- clang/lib/Sema/SemaDeclObjC.cpp | 18 +++-- clang/lib/Sema/SemaExpr.cpp | 17 ++++- clang/test/SemaObjC/property-typecheck-1.m | 72 ++++++++++++++++++- 4 files changed, 99 insertions(+), 10 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index f4da72531487..a8d079d720a7 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -174,7 +174,7 @@ def warn_conflicting_param_types : Warning< "conflicting parameter types in implementation of %0: %1 vs %2">; def warn_multiple_method_decl : Warning<"multiple methods named %0 found">; -def err_accessor_property_type_mismatch : Error< +def warn_accessor_property_type_mismatch : Warning< "type of property %0 does not match type of accessor %1">; def note_declared_at : Note<"declared at">; def err_setter_type_void : Error<"type of setter must be void">; diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index e35b7a919b49..34afdedba7da 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -1315,11 +1315,17 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, if (GetterMethod && GetterMethod->getResultType() != property->getType()) { - Diag(property->getLocation(), - diag::err_accessor_property_type_mismatch) - << property->getDeclName() - << GetterMethod->getSelector(); - Diag(GetterMethod->getLocation(), diag::note_declared_at); + AssignConvertType result = Incompatible; + if (Context.isObjCObjectPointerType(property->getType())) + result = CheckAssignmentConstraints(property->getType(), + GetterMethod->getResultType()); + if (result != Compatible) { + Diag(property->getLocation(), + diag::warn_accessor_property_type_mismatch) + << property->getDeclName() + << GetterMethod->getSelector(); + Diag(GetterMethod->getLocation(), diag::note_declared_at); + } } if (SetterMethod) { @@ -1329,7 +1335,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, if (SetterMethod->param_size() != 1 || ((*SetterMethod->param_begin())->getType() != property->getType())) { Diag(property->getLocation(), - diag::err_accessor_property_type_mismatch) + diag::warn_accessor_property_type_mismatch) << property->getDeclName() << SetterMethod->getSelector(); Diag(SetterMethod->getLocation(), diag::note_declared_at); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 79c471a2d485..f698620543fb 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2096,8 +2096,21 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, // Check whether we can reference this property. if (DiagnoseUseOfDecl(PD, MemberLoc)) return ExprError(); - - return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), + QualType ResTy = PD->getType(); + Selector Sel = PP.getSelectorTable().getNullarySelector(&Member); + ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Context, Sel); + if (Getter) { + AssignConvertType result = + CheckAssignmentConstraints(PD->getType(), Getter->getResultType()); + if (result != Compatible) { + Diag(MemberLoc, diag::warn_accessor_property_type_mismatch) + << PD->getDeclName() << Sel; + Diag(Getter->getLocation(), diag::note_declared_at); + ResTy = Getter->getResultType(); + } + } + + return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy, MemberLoc, BaseExpr)); } diff --git a/clang/test/SemaObjC/property-typecheck-1.m b/clang/test/SemaObjC/property-typecheck-1.m index 1795da8599b5..c4d7cd2448d5 100644 --- a/clang/test/SemaObjC/property-typecheck-1.m +++ b/clang/test/SemaObjC/property-typecheck-1.m @@ -2,7 +2,7 @@ @interface A -(float) x; // expected-note {{declared at}} -@property int x; // expected-error {{type of property 'x' does not match type of accessor 'x'}} +@property int x; // expected-warning {{type of property 'x' does not match type of accessor 'x'}} @end @interface A (Cat) @@ -29,3 +29,73 @@ typedef void (F)(void); @end +@class SSyncSet; + +@interface SPeer + @property(nonatomic,readonly,retain) SSyncSet* syncSet; +@end + +@class SSyncSet_iDisk; + +@interface SPeer_iDisk_remote1 : SPeer +- (SSyncSet_iDisk*) syncSet; // expected-note {{declared at}} +@end + +@interface SPeer_iDisk_local +- (SSyncSet_iDisk*) syncSet; +@end + +@interface SSyncSet +@end + +@interface SSyncSet_iDisk +@property(nonatomic,readonly,retain) SPeer_iDisk_local* localPeer; +@end + +@interface SPeer_iDisk_remote1 (protected) +@end + +@implementation SPeer_iDisk_remote1 (protected) +- (id) preferredSource1 +{ + return self.syncSet.localPeer; // expected-warning {{type of property 'syncSet' does not match type of accessor 'syncSet'}} +} +@end + +@interface NSArray @end + +@interface NSMutableArray : NSArray +@end + +@interface Class1 +{ + NSMutableArray* pieces; + NSArray* first; +} + +@property (readonly) NSArray* pieces; +@property (readonly) NSMutableArray* first; // expected-warning {{type of property 'first' does not match type of accessor 'first'}} + +- (NSMutableArray*) pieces; +- (NSArray*) first; // expected-note {{declared at}} // expected-note {{declared at}} +@end + +@interface Class2 { + Class1* container; +} + +@end + +@implementation Class2 + +- (id) lastPiece +{ + return container.pieces; +} + +- (id)firstPeice +{ + return container.first; // expected-warning {{type of property 'first' does not match type of accessor 'first'}} +} +@end +