From e3d67bcc7b89b335dbcd097a299658057ea31097 Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Fri, 12 Mar 2010 02:31:10 +0000 Subject: [PATCH] Split Sema::ActOnProperty() into two recursive functions to clearly separate the handling of class extensions from other cases. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@98326 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/Sema.h | 32 ++++- lib/Sema/SemaObjCProperty.cpp | 258 ++++++++++++++++++++-------------- 2 files changed, 184 insertions(+), 106 deletions(-) diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 0012435124..c5b719b1d8 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1469,7 +1469,7 @@ public: void DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl, ObjCContainerDecl *CDecl, const llvm::DenseSet& InsMap); - + /// CollectImmediateProperties - This routine collects all properties in /// the class and its conforming protocols; but not those it its super class. void CollectImmediateProperties(ObjCContainerDecl *CDecl, @@ -1482,7 +1482,35 @@ public: ObjCIvarDecl *SynthesizeNewPropertyIvar(ObjCInterfaceDecl *IDecl, IdentifierInfo *NameII); - + + /// Called by ActOnProperty to handle @property declarations in + //// class extensions. + DeclPtrTy HandlePropertyInClassExtension(Scope *S, + ObjCCategoryDecl *CDecl, + SourceLocation AtLoc, + FieldDeclarator &FD, + Selector GetterSel, + Selector SetterSel, + const bool isAssign, + const bool isReadWrite, + const unsigned Attributes, + bool *isOverridingProperty, + QualType T, + tok::ObjCKeywordKind MethodImplKind); + + /// Called by ActOnProperty and HandlePropertyInClassExtension to + /// handle creating the ObjcPropertyDecl for a category or @interface. + ObjCPropertyDecl *CreatePropertyDecl(Scope *S, + ObjCContainerDecl *CDecl, + SourceLocation AtLoc, + FieldDeclarator &FD, + Selector GetterSel, + Selector SetterSel, + const bool isAssign, + const bool isReadWrite, + const unsigned Attributes, QualType T, + tok::ObjCKeywordKind MethodImplKind); + /// AtomicPropertySetterGetterRules - This routine enforces the rule (via /// warning) when atomic property has one but not the other user-declared /// setter or getter. diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index 3884e01fe3..02bfbe7e39 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -38,106 +38,163 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, (isReadWrite && !(Attributes & ObjCDeclSpec::DQ_PR_retain) && !(Attributes & ObjCDeclSpec::DQ_PR_copy))); + QualType T = GetTypeForDeclarator(FD.D, S); if (T->isReferenceType()) { Diag(AtLoc, diag::error_reference_property); return DeclPtrTy(); } - Decl *ClassDecl = ClassCategory.getAs(); - ObjCInterfaceDecl *CCPrimary = 0; // continuation class's primary class - // May modify Attributes. + // Validate the attributes on the @property. CheckObjCPropertyAttributes(T, AtLoc, Attributes); + + // Proceed with constructing the ObjCPropertDecls. + ObjCContainerDecl *ClassDecl = + cast(ClassCategory.getAs()); + if (ObjCCategoryDecl *CDecl = dyn_cast(ClassDecl)) - if (CDecl->IsClassExtension()) { - // Diagnose if this property is already in continuation class. - DeclContext *DC = dyn_cast(ClassDecl); - assert(DC && "ClassDecl is not a DeclContext"); - DeclContext::lookup_result Found = DC->lookup(FD.D.getIdentifier()); - if (Found.first != Found.second && isa(*Found.first)) { - Diag(AtLoc, diag::err_duplicate_property); - Diag((*Found.first)->getLocation(), diag::note_property_declare); - return DeclPtrTy(); - } - ObjCPropertyDecl *PDecl = - ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(), - FD.D.getIdentifier(), AtLoc, T); - DC->addDecl(PDecl); - - // This is a continuation class. property requires special - // handling. - if ((CCPrimary = CDecl->getClassInterface())) { - // Find the property in continuation class's primary class only. - IdentifierInfo *PropertyId = FD.D.getIdentifier(); - if (ObjCPropertyDecl *PIDecl = - CCPrimary->FindPropertyVisibleInPrimaryClass(PropertyId)) { - // property 'PIDecl's readonly attribute will be over-ridden - // with continuation class's readwrite property attribute! - unsigned PIkind = PIDecl->getPropertyAttributes(); - if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) { - unsigned retainCopyNonatomic = - (ObjCPropertyDecl::OBJC_PR_retain | - ObjCPropertyDecl::OBJC_PR_copy | - ObjCPropertyDecl::OBJC_PR_nonatomic); - if ((Attributes & retainCopyNonatomic) != - (PIkind & retainCopyNonatomic)) { - Diag(AtLoc, diag::warn_property_attr_mismatch); - Diag(PIDecl->getLocation(), diag::note_property_declare); - } - DeclContext *DC = dyn_cast(CCPrimary); - assert(DC && "ClassDecl is not a DeclContext"); - DeclContext::lookup_result Found = - DC->lookup(PIDecl->getDeclName()); - bool PropertyInPrimaryClass = false; - for (; Found.first != Found.second; ++Found.first) - if (isa(*Found.first)) { - PropertyInPrimaryClass = true; - break; - } - if (!PropertyInPrimaryClass) { - // Protocol is not in the primary class. Must build one for it. - ObjCDeclSpec ProtocolPropertyODS; - // FIXME. Assuming that ObjCDeclSpec::ObjCPropertyAttributeKind - // and ObjCPropertyDecl::PropertyAttributeKind have identical - // values. Should consolidate both into one enum type. - ProtocolPropertyODS. - setPropertyAttributes((ObjCDeclSpec::ObjCPropertyAttributeKind) - PIkind); - - DeclPtrTy ProtocolPtrTy = - ActOnProperty(S, AtLoc, FD, ProtocolPropertyODS, - PIDecl->getGetterName(), - PIDecl->getSetterName(), - DeclPtrTy::make(CCPrimary), isOverridingProperty, - MethodImplKind); - PIDecl = ProtocolPtrTy.getAs(); - } - 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); - } else { - Diag(AtLoc, diag::err_use_continuation_class) - << CCPrimary->getDeclName(); - Diag(PIDecl->getLocation(), diag::note_property_declare); - } - *isOverridingProperty = true; - // Make sure setter decl is synthesized, and added to primary - // class's list. - ProcessPropertyDecl(PIDecl, CCPrimary); - return DeclPtrTy(); - } - - // No matching property found in the primary class. Just fall thru - // and add property to continuation class's primary class. - ClassDecl = CCPrimary; - } else { - Diag(CDecl->getLocation(), diag::err_continuation_class); - *isOverridingProperty = true; - return DeclPtrTy(); + if (CDecl->IsClassExtension()) + return HandlePropertyInClassExtension(S, CDecl, AtLoc, + FD, GetterSel, SetterSel, + isAssign, isReadWrite, + Attributes, + isOverridingProperty, T, + MethodImplKind); + + return DeclPtrTy::make(CreatePropertyDecl(S, ClassDecl, AtLoc, FD, + GetterSel, SetterSel, + isAssign, isReadWrite, + Attributes, T, MethodImplKind)); +} + +Sema::DeclPtrTy +Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, + SourceLocation AtLoc, FieldDeclarator &FD, + Selector GetterSel, Selector SetterSel, + const bool isAssign, + const bool isReadWrite, + const unsigned Attributes, + bool *isOverridingProperty, + QualType T, + tok::ObjCKeywordKind MethodImplKind) { + + // Diagnose if this property is already in continuation class. + DeclContext *DC = cast(CDecl); + + IdentifierInfo *PropertyId = FD.D.getIdentifier(); + DeclContext::lookup_result Found = DC->lookup(PropertyId); + if (Found.first != Found.second && isa(*Found.first)) { + Diag(AtLoc, diag::err_duplicate_property); + Diag((*Found.first)->getLocation(), diag::note_property_declare); + return DeclPtrTy(); + } + + // Create a new ObjCPropertyDecl with the DeclContext being + // the class extension. + ObjCPropertyDecl *PDecl = + ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(), + PropertyId, AtLoc, T); + DC->addDecl(PDecl); + + // We need to look in the @interface to see if the @property was + // already declared. + ObjCInterfaceDecl *CCPrimary = CDecl->getClassInterface(); + if (!CCPrimary) { + Diag(CDecl->getLocation(), diag::err_continuation_class); + *isOverridingProperty = true; + return DeclPtrTy(); + } + + // Find the property in continuation class's primary class only. + ObjCPropertyDecl *PIDecl = + CCPrimary->FindPropertyVisibleInPrimaryClass(PropertyId); + + if (!PIDecl) { + // No matching property found in the primary class. Just fall thru + // and add property to continuation class's primary class. + ObjCPropertyDecl *PDecl = + CreatePropertyDecl(S, CCPrimary, AtLoc, + FD, GetterSel, SetterSel, isAssign, isReadWrite, + Attributes, T, MethodImplKind); + + // A case of continuation class adding a new property in the class. This + // is not what it was meant for. However, gcc supports it and so should we. + // Make sure setter/getters are declared here. + ProcessPropertyDecl(PDecl, CCPrimary); + return DeclPtrTy::make(PDecl); + + } + + // The property 'PIDecl's readonly attribute will be over-ridden + // with continuation class's readwrite property attribute! + unsigned PIkind = PIDecl->getPropertyAttributes(); + if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) { + unsigned retainCopyNonatomic = + (ObjCPropertyDecl::OBJC_PR_retain | + ObjCPropertyDecl::OBJC_PR_copy | + ObjCPropertyDecl::OBJC_PR_nonatomic); + if ((Attributes & retainCopyNonatomic) != + (PIkind & retainCopyNonatomic)) { + Diag(AtLoc, diag::warn_property_attr_mismatch); + Diag(PIDecl->getLocation(), diag::note_property_declare); + } + DeclContext *DC = dyn_cast(CCPrimary); + assert(DC && "ClassDecl is not a DeclContext"); + DeclContext::lookup_result Found = + DC->lookup(PIDecl->getDeclName()); + bool PropertyInPrimaryClass = false; + for (; Found.first != Found.second; ++Found.first) + if (isa(*Found.first)) { + PropertyInPrimaryClass = true; + break; } + if (!PropertyInPrimaryClass) { + // Protocol is not in the primary class. Must build one for it. + ObjCDeclSpec ProtocolPropertyODS; + // FIXME. Assuming that ObjCDeclSpec::ObjCPropertyAttributeKind + // and ObjCPropertyDecl::PropertyAttributeKind have identical + // values. Should consolidate both into one enum type. + ProtocolPropertyODS. + setPropertyAttributes((ObjCDeclSpec::ObjCPropertyAttributeKind) + PIkind); + + DeclPtrTy ProtocolPtrTy = + ActOnProperty(S, AtLoc, FD, ProtocolPropertyODS, + PIDecl->getGetterName(), + PIDecl->getSetterName(), + DeclPtrTy::make(CCPrimary), isOverridingProperty, + MethodImplKind); + PIDecl = ProtocolPtrTy.getAs(); } + 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); + } else { + Diag(AtLoc, diag::err_use_continuation_class) + << CCPrimary->getDeclName(); + Diag(PIDecl->getLocation(), diag::note_property_declare); + } + *isOverridingProperty = true; + // Make sure setter decl is synthesized, and added to primary class's list. + ProcessPropertyDecl(PIDecl, CCPrimary); + return DeclPtrTy(); +} + +ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, + ObjCContainerDecl *CDecl, + SourceLocation AtLoc, + FieldDeclarator &FD, + Selector GetterSel, + Selector SetterSel, + const bool isAssign, + const bool isReadWrite, + const unsigned Attributes, + QualType T, + tok::ObjCKeywordKind MethodImplKind){ + + IdentifierInfo *PropertyId = FD.D.getIdentifier(); // Issue a warning if property is 'assign' as default and its object, which is // gc'able conforms to NSCopying protocol @@ -152,20 +209,18 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, if (ObjCProtocolDecl* PNSCopying = LookupProtocol(&Context.Idents.get("NSCopying"))) if (IDecl->ClassImplementsProtocol(PNSCopying, true)) - Diag(AtLoc, diag::warn_implements_nscopying) - << FD.D.getIdentifier(); + Diag(AtLoc, diag::warn_implements_nscopying) << PropertyId; } } if (T->isObjCInterfaceType()) Diag(FD.D.getIdentifierLoc(), diag::err_statically_allocated_object); - DeclContext *DC = dyn_cast(ClassDecl); - assert(DC && "ClassDecl is not a DeclContext"); + DeclContext *DC = cast(CDecl); ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(), - FD.D.getIdentifier(), - AtLoc, T); - DeclContext::lookup_result Found = DC->lookup(PDecl->getDeclName()); + PropertyId, AtLoc, T); + + DeclContext::lookup_result Found = DC->lookup(PropertyId); if (Found.first != Found.second && isa(*Found.first)) { Diag(PDecl->getLocation(), diag::err_duplicate_property); Diag((*Found.first)->getLocation(), diag::note_property_declare); @@ -214,13 +269,8 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, PDecl->setPropertyImplementation(ObjCPropertyDecl::Required); else if (MethodImplKind == tok::objc_optional) PDecl->setPropertyImplementation(ObjCPropertyDecl::Optional); - // A case of continuation class adding a new property in the class. This - // is not what it was meant for. However, gcc supports it and so should we. - // Make sure setter/getters are declared here. - if (CCPrimary) - ProcessPropertyDecl(PDecl, CCPrimary); - return DeclPtrTy::make(PDecl); + return PDecl; } -- 2.40.0