From f8ef9f3dc9e8ceadd3772052624a455bbbfb0ffb Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Wed, 26 Nov 2008 20:01:34 +0000 Subject: [PATCH] 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. llvm-svn: 60114 --- clang/include/clang/AST/DeclObjC.h | 5 ++ clang/include/clang/Basic/DiagnosticKinds.def | 6 ++ clang/include/clang/Parse/Action.h | 2 + clang/lib/Parse/ParseObjc.cpp | 6 +- clang/lib/Sema/Sema.h | 1 + clang/lib/Sema/SemaDeclObjC.cpp | 79 +++++++++++++++++-- clang/test/CodeGenObjC/continuation-class.m | 35 ++++++++ clang/test/SemaObjC/property-9-impl-method.m | 1 + 8 files changed, 129 insertions(+), 6 deletions(-) create mode 100644 clang/test/CodeGenObjC/continuation-class.m diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h index b52400ab9f68..eda3e6db7df6 100644 --- a/clang/include/clang/AST/DeclObjC.h +++ b/clang/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/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index 6e7e58e61d28..a9694fa608a9 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/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/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h index 3058ce3aba47..e32dc388fc74 100644 --- a/clang/include/clang/Parse/Action.h +++ b/clang/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/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 9fe4c1ec12e2..f937ef1d9c05 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/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/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index c8352172f9ae..614e4873bacc 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/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/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index 95737af18ac9..9f37e900cdfc 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/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/clang/test/CodeGenObjC/continuation-class.m b/clang/test/CodeGenObjC/continuation-class.m new file mode 100644 index 000000000000..9ac51c70bf0b --- /dev/null +++ b/clang/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/clang/test/SemaObjC/property-9-impl-method.m b/clang/test/SemaObjC/property-9-impl-method.m index bb13d01b74ac..e9e81bd55f5e 100644 --- a/clang/test/SemaObjC/property-9-impl-method.m +++ b/clang/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