From de8db16a7daa4b216fe90bd256b47220ed24ea1c Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Mon, 2 Nov 2009 22:45:15 +0000 Subject: [PATCH] Property declared in continuation class can only be used to change a readonly property declared in the class (and its inherited protocols) to writable property. (Fixes radar 7350645). llvm-svn: 85836 --- clang/include/clang/AST/DeclObjC.h | 2 ++ .../clang/Basic/DiagnosticSemaKinds.td | 5 ++-- clang/lib/AST/DeclObjC.cpp | 21 ++++++++++++++ clang/lib/Sema/SemaDeclObjC.cpp | 18 ++++-------- clang/test/SemaObjC/continuation-class-err.m | 29 +++++++++++++++++-- 5 files changed, 59 insertions(+), 16 deletions(-) diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h index abe4de463e61..bcd28eab039f 100644 --- a/clang/include/clang/AST/DeclObjC.h +++ b/clang/include/clang/AST/DeclObjC.h @@ -347,6 +347,8 @@ public: ObjCIvarDecl *getIvarDecl(IdentifierInfo *Id) const; ObjCPropertyDecl *FindPropertyDeclaration(IdentifierInfo *PropertyId) const; + ObjCPropertyDecl *FindPropertyVisibleInPrimaryClass( + IdentifierInfo *PropertyId) const; // Marks the end of the container. SourceLocation getAtEndLoc() const { return AtEndLoc; } diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 8c7c0cbbe99d..3b39fa964fc6 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -264,7 +264,8 @@ def warn_objc_property_copy_missing_on_block : Warning< "'copy' attribute must be specified for the block property " "when -fobjc-gc-only is specified">; def err_use_continuation_class : Error< - "attribute of property in continuation class of %0 can only be 'readwrite'">; + "property declaration in continuation class of %0 is to change a 'readonly' " + "property to 'readwrite'">; def err_continuation_class : Error<"continuation class has no primary class">; def err_property_type : Error<"property cannot have array or function type %0">; def error_missing_property_context : Error< @@ -274,7 +275,7 @@ def error_bad_property_decl : Error< def error_category_property : Error< "property declared in category %0 cannot be implemented in " "class implementation">; -def note_category_property : Note< +def note_property_declare : Note< "property declared here">; def error_synthesize_category_decl : Error< "@synthesize not allowed in a category's implementation">; diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp index 49a566878ff0..7b48b724c0eb 100644 --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/lib/AST/DeclObjC.cpp @@ -118,6 +118,27 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const { return 0; } +/// FindPropertyVisibleInPrimaryClass - Finds declaration of the property +/// with name 'PropertyId' in the primary class; including those in protocols +/// (direct or indirect) used by the promary class. +/// FIXME: Convert to DeclContext lookup... +/// +ObjCPropertyDecl * +ObjCContainerDecl::FindPropertyVisibleInPrimaryClass( + IdentifierInfo *PropertyId) const { + assert(isa(this) && "FindPropertyVisibleInPrimaryClass"); + for (prop_iterator I = prop_begin(), E = prop_end(); I != E; ++I) + if ((*I)->getIdentifier() == PropertyId) + return *I; + const ObjCInterfaceDecl *OID = dyn_cast(this); + // Look through protocols. + for (ObjCInterfaceDecl::protocol_iterator I = OID->protocol_begin(), + E = OID->protocol_end(); I != E; ++I) + if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId)) + return P; + return 0; +} + void ObjCInterfaceDecl::mergeClassExtensionProtocolList( ObjCProtocolDecl *const* ExtList, unsigned ExtNum, ASTContext &C) diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index 881652f7aaa4..f9f01681b93d 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -1893,17 +1893,9 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, // handling. if ((CCPrimary = CDecl->getClassInterface())) { // Find the property in continuation class's primary class only. - ObjCPropertyDecl *PIDecl = 0; IdentifierInfo *PropertyId = FD.D.getIdentifier(); - for (ObjCInterfaceDecl::prop_iterator - I = CCPrimary->prop_begin(), E = CCPrimary->prop_end(); - I != E; ++I) - if ((*I)->getIdentifier() == PropertyId) { - PIDecl = *I; - break; - } - - if (PIDecl) { + if (ObjCPropertyDecl *PIDecl = + CCPrimary->FindPropertyVisibleInPrimaryClass(PropertyId)) { // property 'PIDecl's readonly attribute will be over-ridden // with continuation class's readwrite property attribute! unsigned PIkind = PIDecl->getPropertyAttributes(); @@ -1917,9 +1909,11 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, if (Attributes & ObjCDeclSpec::DQ_PR_copy) PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy); PIDecl->setSetterName(SetterSel); - } else + } else { Diag(AtLoc, diag::err_use_continuation_class) << CCPrimary->getDeclName(); + Diag(PIDecl->getLocation(), diag::note_property_declare); + } *isOverridingProperty = true; // Make sure setter decl is synthesized, and added to primary // class's list. @@ -2051,7 +2045,7 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, dyn_cast(property->getDeclContext())) { if (CD->getIdentifier()) { Diag(PropertyLoc, diag::error_category_property) << CD->getDeclName(); - Diag(property->getLocation(), diag::note_category_property); + Diag(property->getLocation(), diag::note_property_declare); return DeclPtrTy(); } } diff --git a/clang/test/SemaObjC/continuation-class-err.m b/clang/test/SemaObjC/continuation-class-err.m index f516a9326a95..e1ae39bd2942 100644 --- a/clang/test/SemaObjC/continuation-class-err.m +++ b/clang/test/SemaObjC/continuation-class-err.m @@ -6,10 +6,35 @@ id _object1; } @property(readonly) id object; -@property(readwrite, assign) id object1; +@property(readwrite, assign) id object1; // expected-note {{property declared here}} @end @interface ReadOnly () @property(readwrite, copy) id object; -@property(readonly) id object1; // expected-error {{attribute of property in continuation class of 'ReadOnly' can only be 'readwrite'}} +@property(readonly) id object1; // expected-error {{property declaration in continuation class of 'ReadOnly' is to change a 'readonly' property to 'readwrite'}} @end + +@protocol Proto + @property (copy) id fee; // expected-note {{property declared here}} +@end + +@protocol Foo + @property (copy) id foo; // expected-note {{property declared here}} +@end + +@interface Bar { + id _foo; + id _fee; +} +@end + +@interface Bar () +@property (copy) id foo; // expected-error {{property declaration in continuation class of 'Bar' is to change a 'readonly' property to 'readwrite'}} +@property (copy) id fee; // expected-error {{property declaration in continuation class of 'Bar' is to change a 'readonly' property to 'readwrite'}} +@end + +@implementation Bar +@synthesize foo = _foo; +@synthesize fee = _fee; +@end +