From: Fariborz Jahanian Date: Wed, 26 Nov 2008 20:01:34 +0000 (+0000) Subject: Set default property attributes on each property. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8cf0bb3c2a798ce3acacaac2d3178648cd4c65c6;p=clang Set default property attributes on each property. Implemented anonymous category (also know as continuation class) used to override main class's property attribute. This is work in propgress. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@60114 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index b52400ab9f..eda3e6db7d 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -1228,6 +1228,11 @@ public: PropertyAttributes |= PRVal; } + void makeitReadWriteAttribute(void) { + PropertyAttributes &= ~OBJC_PR_readonly; + PropertyAttributes |= OBJC_PR_readwrite; + } + // Helper methods for accessing attributes. /// isReadOnly - Return true iff the property has a setter. diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 6e7e58e61d..a9694fa608 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -563,6 +563,12 @@ DIAG(warn_property_attribute, WARNING, "property %0 '%1' attribute does not match the property inherited from %2") DIAG(warn_property_type, WARNING, "property type %0 does not match property type inherited from %1") +DIAG(err_continuation_class, ERROR, + "continuation class has no primary class") +DIAG(err_use_continuation_class, ERROR, + "use contination class to override 'readonly' property with 'readwrite'") +DIAG(warn_property_attr_mismatch, WARNING, + "property attribute in continuation class does not match the primary class") /// C++ parser diagnostics DIAG(err_expected_unqualified_id, ERROR, diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 3058ce3aba..e32dc388fc 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -963,6 +963,8 @@ public: virtual DeclTy *ActOnProperty (Scope *S, SourceLocation AtLoc, FieldDeclarator &FD, ObjCDeclSpec &ODS, Selector GetterSel, Selector SetterSel, + DeclTy *ClassCategory, + bool *OverridingProperty, tok::ObjCKeywordKind MethodImplKind) { return 0; } diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 9fe4c1ec12..f937ef1d9c 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -332,10 +332,14 @@ void Parser::ParseObjCInterfaceDeclList(DeclTy *interfaceDecl, FD.D.getIdentifier()); Selector SetterSel = PP.getSelectorTable().getUnarySelector(SetterName); + bool isOverridingProperty = false; DeclTy *Property = Actions.ActOnProperty(CurScope, AtLoc, FD, OCDS, GetterSel, SetterSel, + interfaceDecl, + &isOverridingProperty, MethodImplKind); - allProperties.push_back(Property); + if (!isOverridingProperty) + allProperties.push_back(Property); } break; } diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index c8352172f9..614e4873ba 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1051,6 +1051,7 @@ public: virtual DeclTy *ActOnProperty(Scope *S, SourceLocation AtLoc, FieldDeclarator &FD, ObjCDeclSpec &ODS, Selector GetterSel, Selector SetterSel, + DeclTy *ClassCategory, bool *OverridingProperty, tok::ObjCKeywordKind MethodImplKind); virtual DeclTy *ActOnPropertyImplDecl(SourceLocation AtLoc, diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 95737af18a..9f37e900cd 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -1186,12 +1186,81 @@ Sema::DeclTy *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, ObjCDeclSpec &ODS, Selector GetterSel, Selector SetterSel, + DeclTy *ClassCategory, + bool *isOverridingProperty, tok::ObjCKeywordKind MethodImplKind) { - QualType T = GetTypeForDeclarator(FD.D, S); unsigned Attributes = ODS.getPropertyAttributes(); + bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) || + // default is readwrite! + !(Attributes & ObjCDeclSpec::DQ_PR_readonly)); + // property is defaulted to 'assign' if it is readwrite and is + // not retain or copy + bool isAssign = ((Attributes & ObjCDeclSpec::DQ_PR_assign) || + (isReadWrite && + !(Attributes & ObjCDeclSpec::DQ_PR_retain) && + !(Attributes & ObjCDeclSpec::DQ_PR_copy))); + QualType T = GetTypeForDeclarator(FD.D, S); + Decl *ClassDecl = static_cast(ClassCategory); // May modify Attributes. CheckObjCPropertyAttributes(T, AtLoc, Attributes); + + if (ObjCCategoryDecl *CDecl = dyn_cast(ClassDecl)) + if (!CDecl->getIdentifier()) { + // This is an anonymous category. property requires special + // handling. + if (ObjCInterfaceDecl *ICDecl = CDecl->getClassInterface()) { + if (ObjCPropertyDecl *PIDecl = + ICDecl->FindPropertyDeclaration(FD.D.getIdentifier())) { + // property 'PIDecl's readonly attribute will be over-ridden + // with anonymous category's readwrite property attribute! + unsigned PIkind = PIDecl->getPropertyAttributes(); + if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) { + if ((Attributes & ObjCPropertyDecl::OBJC_PR_retain) != + (PIkind & ObjCPropertyDecl::OBJC_PR_retain) || + (Attributes & ObjCPropertyDecl::OBJC_PR_copy) != + (PIkind & ObjCPropertyDecl::OBJC_PR_copy) || + (Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) != + (PIkind & ObjCPropertyDecl::OBJC_PR_nonatomic)) + Diag(AtLoc, diag::warn_property_attr_mismatch); + PIDecl->makeitReadWriteAttribute(); + if (Attributes & ObjCDeclSpec::DQ_PR_retain) + PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain); + if (Attributes & ObjCDeclSpec::DQ_PR_copy) + PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy); + PIDecl->setSetterName(SetterSel); + // FIXME: use a common routine with addPropertyMethods. + ObjCMethodDecl *SetterDecl = + ObjCMethodDecl::Create(Context, AtLoc, AtLoc, SetterSel, + Context.VoidTy, + ICDecl, + true, false, true, + ObjCMethodDecl::Required); + ParmVarDecl *Argument = ParmVarDecl::Create(Context, + SetterDecl, + SourceLocation(), + FD.D.getIdentifier(), + T, + VarDecl::None, + 0, 0); + SetterDecl->setMethodParams(&Argument, 1); + PIDecl->setSetterMethodDecl(SetterDecl); + } + else + Diag(AtLoc, diag::err_use_continuation_class); + *isOverridingProperty = true; + return 0; + } + // else + // FIXME: + // no matching property found in the main class. Must simply + // add this property to the main class's property list. + } else { + Diag(CDecl->getLocation(), diag::err_continuation_class); + *isOverridingProperty = true; + return 0; + } + } ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, AtLoc, FD.D.getIdentifier(), T); @@ -1209,10 +1278,7 @@ Sema::DeclTy *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, if (Attributes & ObjCDeclSpec::DQ_PR_setter) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_setter); - if (Attributes & ObjCDeclSpec::DQ_PR_assign) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign); - - if (Attributes & ObjCDeclSpec::DQ_PR_readwrite) + if (isReadWrite) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite); if (Attributes & ObjCDeclSpec::DQ_PR_retain) @@ -1221,6 +1287,9 @@ Sema::DeclTy *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, if (Attributes & ObjCDeclSpec::DQ_PR_copy) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy); + if (isAssign) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign); + if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic); diff --git a/test/CodeGenObjC/continuation-class.m b/test/CodeGenObjC/continuation-class.m new file mode 100644 index 0000000000..9ac51c70bf --- /dev/null +++ b/test/CodeGenObjC/continuation-class.m @@ -0,0 +1,35 @@ +// RUN: clang -fnext-runtime --emit-llvm -o %t %s + +@interface Object +- (id)new; +@end + +@interface ReadOnly : Object +{ + int _object; + int _Anotherobject; +} +@property(readonly) int object; +@property(readonly) int Anotherobject; +@end + +@interface ReadOnly () +@property(readwrite) int object; +@property(readwrite, setter = myAnotherobjectSetter:) int Anotherobject; +@end + +@implementation ReadOnly +@synthesize object = _object; +@synthesize Anotherobject = _Anotherobject; +- (void) myAnotherobjectSetter : (int)val { + _Anotherobject = val; +} +@end + +int main(int argc, char **argv) { + ReadOnly *test = [ReadOnly new]; + test.object = 12345; + test.Anotherobject = 200; + return test.object - 12345 + test.Anotherobject - 200; +} + diff --git a/test/SemaObjC/property-9-impl-method.m b/test/SemaObjC/property-9-impl-method.m index bb13d01b74..e9e81bd55f 100644 --- a/test/SemaObjC/property-9-impl-method.m +++ b/test/SemaObjC/property-9-impl-method.m @@ -60,4 +60,5 @@ NSSize minimumSize; NSRect dummy, result = {}; NSDivideRect(self.bounds, &result, &dummy, self.tabAreaThickness, self.rectEdgeForTabs); } +@end