From: Fariborz Jahanian Date: Wed, 20 Jun 2012 22:57:42 +0000 (+0000) Subject: objective-c: Normally, a property cannot be both 'readonly' and having a X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=cea06d26b8f3a2599bba79f7e072b7550de949a7;p=clang objective-c: Normally, a property cannot be both 'readonly' and having a "write" attribute (copy/retain/etc.). But, property declaration in primary class and protcols are tentative as they may be overridden into a 'readwrite' property in class extensions. Postpone diagnosing such warnings until the class implementation is seen. // rdar://11656982 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@158869 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 4be823a8db..6e7f23bd6b 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -6006,7 +6006,8 @@ public: /// be modified to be consistent with \arg PropertyTy. void CheckObjCPropertyAttributes(Decl *PropertyPtrTy, SourceLocation Loc, - unsigned &Attributes); + unsigned &Attributes, + bool propertyInPrimaryClass); /// Process the specified property declaration and create decls for the /// setters and getters as needed. diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index 95fbde39af..32fbb0432a 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -135,7 +135,6 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, // Proceed with constructing the ObjCPropertDecls. ObjCContainerDecl *ClassDecl = cast(CurContext); - if (ObjCCategoryDecl *CDecl = dyn_cast(ClassDecl)) if (CDecl->IsClassExtension()) { Decl *Res = HandlePropertyInClassExtension(S, AtLoc, LParenLoc, @@ -146,7 +145,7 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, isOverridingProperty, TSI, MethodImplKind); if (Res) { - CheckObjCPropertyAttributes(Res, AtLoc, Attributes); + CheckObjCPropertyAttributes(Res, AtLoc, Attributes, false); if (getLangOpts().ObjCAutoRefCount) checkARCPropertyDecl(*this, cast(Res)); } @@ -163,7 +162,9 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, Res->setLexicalDeclContext(lexicalDC); // Validate the attributes on the @property. - CheckObjCPropertyAttributes(Res, AtLoc, Attributes); + CheckObjCPropertyAttributes(Res, AtLoc, Attributes, + (isa(ClassDecl) || + isa(ClassDecl))); if (getLangOpts().ObjCAutoRefCount) checkARCPropertyDecl(*this, Res); @@ -601,6 +602,67 @@ static void setImpliedPropertyAttributeForReadOnlyProperty( return; } +/// DiagnoseClassAndClassExtPropertyMismatch - diagnose inconsistant property +/// attribute declared in primary class and attributes overridden in any of its +/// class extensions. +static void +DiagnoseClassAndClassExtPropertyMismatch(Sema &S, ObjCInterfaceDecl *ClassDecl, + ObjCPropertyDecl *property) { + unsigned Attributes = property->getPropertyAttributesAsWritten(); + bool warn = (Attributes & ObjCDeclSpec::DQ_PR_readonly); + for (const ObjCCategoryDecl *CDecl = ClassDecl->getFirstClassExtension(); + CDecl; CDecl = CDecl->getNextClassExtension()) { + warn = false; + ObjCPropertyDecl *ClassExtProperty = 0; + for (ObjCContainerDecl::prop_iterator P = CDecl->prop_begin(), + E = CDecl->prop_end(); P != E; ++P) { + if ((*P)->getIdentifier() == property->getIdentifier()) { + ClassExtProperty = *P; + break; + } + } + if (ClassExtProperty) { + unsigned classExtPropertyAttr = + ClassExtProperty->getPropertyAttributesAsWritten(); + // We are issuing the warning that we postponed because class extensions + // can override readonly->readwrite and 'setter' attributes originally + // placed on class's property declaration now make sense in the overridden + // property. + if (Attributes & ObjCDeclSpec::DQ_PR_readonly) { + if (!classExtPropertyAttr || + (classExtPropertyAttr & ObjCDeclSpec::DQ_PR_readwrite)) + continue; + warn = true; + break; + } + } + } + if (warn) { + unsigned setterAttrs = (ObjCDeclSpec::DQ_PR_assign | + ObjCDeclSpec::DQ_PR_unsafe_unretained | + ObjCDeclSpec::DQ_PR_copy | + ObjCDeclSpec::DQ_PR_retain | + ObjCDeclSpec::DQ_PR_strong); + if (Attributes & setterAttrs) { + const char * which = + (Attributes & ObjCDeclSpec::DQ_PR_assign) ? + "assign" : + (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) ? + "unsafe_unretained" : + (Attributes & ObjCDeclSpec::DQ_PR_copy) ? + "copy" : + (Attributes & ObjCDeclSpec::DQ_PR_retain) ? + "retain" : "strong"; + + S.Diag(property->getLocation(), + diag::warn_objc_property_attr_mutually_exclusive) + << "readonly" << which; + } + } + + +} + /// ActOnPropertyImplDecl - This routine performs semantic checks and /// builds the AST node for a property implementation declaration; declared /// as \@synthesize or \@dynamic. @@ -681,6 +743,8 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, FixItHint::CreateReplacement(ReadonlySourceRange, "readwrite"); } } + + DiagnoseClassAndClassExtPropertyMismatch(*this, IDecl, property); } else if ((CatImplClass = dyn_cast(ClassImpDecl))) { if (Synthesize) { @@ -1887,7 +1951,8 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, void Sema::CheckObjCPropertyAttributes(Decl *PDecl, SourceLocation Loc, - unsigned &Attributes) { + unsigned &Attributes, + bool propertyInPrimaryClass) { // FIXME: Improve the reported location. if (!PDecl || PDecl->isInvalidDecl()) return; @@ -1910,9 +1975,18 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, return; } + if (propertyInPrimaryClass) { + // we postpone most property diagnosis until class's implementation + // because, its readonly attribute may be overridden in its class + // extensions making other attributes, which make no sense, to make sense. + if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) && + (Attributes & ObjCDeclSpec::DQ_PR_readwrite)) + Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) + << "readonly" << "readwrite"; + } // readonly and readwrite/assign/retain/copy conflict. - if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) && - (Attributes & (ObjCDeclSpec::DQ_PR_readwrite | + else if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) && + (Attributes & (ObjCDeclSpec::DQ_PR_readwrite | ObjCDeclSpec::DQ_PR_assign | ObjCDeclSpec::DQ_PR_unsafe_unretained | ObjCDeclSpec::DQ_PR_copy | diff --git a/test/SemaObjC/property-12.m b/test/SemaObjC/property-12.m index cd0fccf0e3..ee9cb1a843 100644 --- a/test/SemaObjC/property-12.m +++ b/test/SemaObjC/property-12.m @@ -29,4 +29,39 @@ @end +// rdar://11656982 +@interface I0 @end +@implementation I0 +@synthesize X; +@end + +@interface I1 @end +@implementation I1 +@synthesize X; +@end + +@interface I2 @end +@implementation I2 +@synthesize X; +@end + +@interface I3 @end +@implementation I3 +@synthesize X; +@end + +@interface I4 @end +@implementation I4 +@synthesize X; +@end + +@interface I5 @end +@implementation I5 +@synthesize X; +@end + +@interface I6 @end +@implementation I6 +@synthesize X; +@end diff --git a/test/SemaObjC/tentative-property-decl.m b/test/SemaObjC/tentative-property-decl.m new file mode 100644 index 0000000000..4ab2f56a4a --- /dev/null +++ b/test/SemaObjC/tentative-property-decl.m @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 -fsyntax-only -Weverything -verify %s +// rdar://11656982 +/** Normally, a property cannot be both 'readonly' and having a "write" attribute + (copy/retain/etc.). But, property declaration in primary class and protcols + are tentative as they may be overridden into a 'readwrite' property in class + extensions. Postpone diagnosing such warnings until the class implementation + is seen. +*/ + +@interface Super { +} +@end + +@class NSString; + +@interface MyClass : Super +@property(nonatomic, copy, readonly) NSString *prop; +@end + +@interface MyClass () +@property(nonatomic, copy, readwrite) NSString *prop; +@end + +@implementation MyClass +@synthesize prop; +@end + + +@protocol P +@property(nonatomic, copy, readonly) NSString *prop; +@end + +@interface YourClass : Super

+@end + +@interface YourClass () +@property(nonatomic, copy, readwrite) NSString *prop; +@end + +@implementation YourClass +@synthesize prop; +@end +