diff options
author | Fariborz Jahanian <fjahanian@apple.com> | 2012-06-20 22:57:42 +0000 |
---|---|---|
committer | Fariborz Jahanian <fjahanian@apple.com> | 2012-06-20 22:57:42 +0000 |
commit | cea06d26b8f3a2599bba79f7e072b7550de949a7 (patch) | |
tree | 92576a1b30507eecce26f5f5ab38a59a327f3c22 /lib/Sema/SemaObjCProperty.cpp | |
parent | 198129e24b56ffcc85f66e798d52a8614e3a07a4 (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
Diffstat (limited to 'lib/Sema/SemaObjCProperty.cpp')
-rw-r--r-- | lib/Sema/SemaObjCProperty.cpp | 86 |
1 files changed, 80 insertions, 6 deletions
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 | |