aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFariborz Jahanian <fjahanian@apple.com>2012-06-20 22:57:42 +0000
committerFariborz Jahanian <fjahanian@apple.com>2012-06-20 22:57:42 +0000
commitcea06d26b8f3a2599bba79f7e072b7550de949a7 (patch)
tree92576a1b30507eecce26f5f5ab38a59a327f3c22
parent198129e24b56ffcc85f66e798d52a8614e3a07a4 (diff)
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
-rw-r--r--include/clang/Sema/Sema.h3
-rw-r--r--lib/Sema/SemaObjCProperty.cpp86
-rw-r--r--test/SemaObjC/property-12.m35
-rw-r--r--test/SemaObjC/tentative-property-decl.m43
4 files changed, 160 insertions, 7 deletions
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<ObjCContainerDecl>(CurContext);
-
if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(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<ObjCPropertyDecl>(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<ObjCInterfaceDecl>(ClassDecl) ||
+ isa<ObjCProtocolDecl>(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<ObjCCategoryImplDecl>(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 <P0> @end
+@implementation I0
+@synthesize X;
+@end
+
+@interface I1 <P1> @end
+@implementation I1
+@synthesize X;
+@end
+
+@interface I2 <P2> @end
+@implementation I2
+@synthesize X;
+@end
+
+@interface I3 <P3> @end
+@implementation I3
+@synthesize X;
+@end
+
+@interface I4 <P4> @end
+@implementation I4
+@synthesize X;
+@end
+
+@interface I5 <P5> @end
+@implementation I5
+@synthesize X;
+@end
+
+@interface I6 <P6> @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 <P>
+@end
+
+@interface YourClass ()
+@property(nonatomic, copy, readwrite) NSString *prop;
+@end
+
+@implementation YourClass
+@synthesize prop;
+@end
+