From aebf0cba02c014ac8b19d615c654248e0e93779f Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Fri, 2 May 2008 19:17:30 +0000 Subject: [PATCH] This patch is about merging ObjC2's properties declared in class protocols into class's property list and performing semantics on them for while doing so. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@50587 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/DeclObjC.h | 14 +++++ include/clang/Basic/DiagnosticKinds.def | 7 +-- lib/AST/DeclObjC.cpp | 27 +++++++++ lib/Sema/Sema.h | 8 ++- lib/Sema/SemaDeclObjC.cpp | 81 +++++++++++++++++++++---- test/Sema/objc-property-3.m | 4 +- test/Sema/objc-property-4.m | 30 +++++++++ 7 files changed, 152 insertions(+), 19 deletions(-) create mode 100644 test/Sema/objc-property-4.m diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index 93a3457764..5e92708962 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -285,6 +285,12 @@ public: ObjCCategoryDecl *FindCategoryDeclaration(IdentifierInfo *CategoryId) const; ObjCIvarDecl *FindIvarDeclaration(IdentifierInfo *IvarId) const; + typedef ObjCProtocolDecl * const * protocol_iterator; + protocol_iterator protocol_begin() const { return ReferencedProtocols; } + protocol_iterator protocol_end() const { + return ReferencedProtocols+NumReferencedProtocols; + } + typedef ObjCIvarDecl * const *ivar_iterator; ivar_iterator ivar_begin() const { return Ivars; } ivar_iterator ivar_end() const { return Ivars + ivar_size();} @@ -314,6 +320,8 @@ public: void addProperties(ObjCPropertyDecl **Properties, unsigned NumProperties); + void mergeProperties(ObjCPropertyDecl **Properties, unsigned NumProperties); + typedef ObjCPropertyDecl * const * classprop_iterator; classprop_iterator classprop_begin() const { return PropertyDecl; } classprop_iterator classprop_end() const { @@ -517,6 +525,12 @@ public: return ReferencedProtocols; } unsigned getNumReferencedProtocols() const { return NumReferencedProtocols; } + typedef ObjCProtocolDecl * const * protocol_iterator; + protocol_iterator protocol_begin() const { return ReferencedProtocols; } + protocol_iterator protocol_end() const { + return ReferencedProtocols+NumReferencedProtocols; + } + unsigned getNumInstanceMethods() const { return NumInstanceMethods; } unsigned getNumClassMethods() const { return NumClassMethods; } diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 396bd40ae8..f8583a9019 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -510,12 +510,11 @@ DIAG(error_property_ivar_type, ERROR, "type of property '%0' does not match type of ivar '%1'") DIAG(warn_readonly_property, WARNING, "attribute 'readonly' of property '%0' restricts attribute " - "'readwrite' of '%1' property in super class") + "'readwrite' of property inherited from '%1'") DIAG(warn_property_attribute, WARNING, - "property '%0' '%1' attribute does not match super class '%2' " - "property") + "property '%0' '%1' attribute does not match the property inherited from'%2' ") DIAG(warn_property_type, WARNING, - "property type '%0' does not match super class '%1' property type") + "property type '%0' does not match property type inherited from '%1'") //===----------------------------------------------------------------------===// // Semantic Analysis diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index ef4a6e1c3d..89f6d2c501 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -242,6 +242,33 @@ void ObjCInterfaceDecl::addProperties(ObjCPropertyDecl **Properties, memcpy(PropertyDecl, Properties, NumProperties*sizeof(ObjCPropertyDecl*)); } +/// mergeProperties - Adds properties to the end of list of current properties +/// for this class. + +void ObjCInterfaceDecl::mergeProperties(ObjCPropertyDecl **Properties, + unsigned NumNewProperties) { + if (NumNewProperties == 0) return; + + if (PropertyDecl) { + ObjCPropertyDecl **newPropertyDecl = + new ObjCPropertyDecl*[NumNewProperties + NumPropertyDecl]; + ObjCPropertyDecl **buf = newPropertyDecl; + // put back original properties in buffer. + memcpy(buf, PropertyDecl, NumPropertyDecl*sizeof(ObjCPropertyDecl*)); + // Add new properties to this buffer. + memcpy(buf+NumPropertyDecl, Properties, + NumNewProperties*sizeof(ObjCPropertyDecl*)); + free(PropertyDecl); + PropertyDecl = newPropertyDecl; + NumPropertyDecl += NumNewProperties; + } + else { + PropertyDecl = new ObjCPropertyDecl*[NumNewProperties]; + memcpy(PropertyDecl, Properties, NumNewProperties*sizeof(ObjCPropertyDecl*)); + NumPropertyDecl = NumNewProperties; + } +} + /// addProperties - Insert property declaration AST nodes into /// ObjCProtocolDecl's PropertyDecl field. /// diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 1bed03c1fc..68a834c6b4 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -662,9 +662,15 @@ public: void DiagnosePropertyMismatch(ObjCPropertyDecl *Property, ObjCPropertyDecl *SuperProperty, - ObjCInterfaceDecl*SuperIDecl); + const char *Name); void ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl); + void MergeProtocolPropertiesIntoClass(ObjCInterfaceDecl *IDecl, + DeclTy *MergeProtocols); + + void MergeOneProtocolPropertiesIntoClass(ObjCInterfaceDecl *IDecl, + ObjCProtocolDecl *PDecl); + virtual void ActOnAtEnd(SourceLocation AtEndLoc, DeclTy *classDecl, DeclTy **allMethods = 0, unsigned allNum = 0, DeclTy **allProperties = 0, unsigned pNum = 0); diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index e95ad6469b..afac82ca76 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -247,12 +247,10 @@ Sema::FindProtocolDeclaration(SourceLocation TypeLoc, /// DiagnosePropertyMismatch - Compares two properties for their /// attributes and types and warns on a variety of inconsistancies. /// -// TODO: Incomplete. -// void Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property, ObjCPropertyDecl *SuperProperty, - ObjCInterfaceDecl *SuperIDecl) { + const char *inheritedName) { ObjCPropertyDecl::PropertyAttributeKind CAttr = Property->getPropertyAttributes(); ObjCPropertyDecl::PropertyAttributeKind SAttr = @@ -260,36 +258,36 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property, if ((CAttr & ObjCPropertyDecl::OBJC_PR_readonly) && (SAttr & ObjCPropertyDecl::OBJC_PR_readwrite)) Diag(Property->getLocation(), diag::warn_readonly_property, - Property->getName(), SuperIDecl->getName()); + Property->getName(), inheritedName); if ((CAttr & ObjCPropertyDecl::OBJC_PR_copy) != (SAttr & ObjCPropertyDecl::OBJC_PR_copy)) Diag(Property->getLocation(), diag::warn_property_attribute, - Property->getName(), "copy", SuperIDecl->getName(), + Property->getName(), "copy", inheritedName, SourceRange()); else if ((CAttr & ObjCPropertyDecl::OBJC_PR_retain) != (SAttr & ObjCPropertyDecl::OBJC_PR_retain)) Diag(Property->getLocation(), diag::warn_property_attribute, - Property->getName(), "retain", SuperIDecl->getName(), + Property->getName(), "retain", inheritedName, SourceRange()); if ((CAttr & ObjCPropertyDecl::OBJC_PR_nonatomic) != (SAttr & ObjCPropertyDecl::OBJC_PR_nonatomic)) Diag(Property->getLocation(), diag::warn_property_attribute, - Property->getName(), "atomic", SuperIDecl->getName(), + Property->getName(), "atomic", inheritedName, SourceRange()); if (Property->getSetterName() != SuperProperty->getSetterName()) Diag(Property->getLocation(), diag::warn_property_attribute, - Property->getName(), "setter", SuperIDecl->getName(), + Property->getName(), "setter", inheritedName, SourceRange()); if (Property->getGetterName() != SuperProperty->getGetterName()) Diag(Property->getLocation(), diag::warn_property_attribute, - Property->getName(), "getter", SuperIDecl->getName(), + Property->getName(), "getter", inheritedName, SourceRange()); if (Property->getCanonicalType() != SuperProperty->getCanonicalType()) Diag(Property->getLocation(), diag::warn_property_type, Property->getType().getAsString(), - SuperIDecl->getName()); + inheritedName); } @@ -310,11 +308,69 @@ Sema::ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl) { E = IDecl->classprop_end(); I != E; ++I) { ObjCPropertyDecl *PDecl = (*I); if (SuperPDecl->getIdentifier() == PDecl->getIdentifier()) - DiagnosePropertyMismatch(PDecl, SuperPDecl, SDecl); + DiagnosePropertyMismatch(PDecl, SuperPDecl, SDecl->getName()); } } } +/// MergeOneProtocolPropertiesIntoClass - This routine goes thru the list +/// of properties declared in a protocol and adds them to the list +/// of properties for current class if it is not there already. +void +Sema::MergeOneProtocolPropertiesIntoClass(ObjCInterfaceDecl *IDecl, + ObjCProtocolDecl *PDecl) +{ + llvm::SmallVector mergeProperties; + for (ObjCProtocolDecl::classprop_iterator P = PDecl->classprop_begin(), + E = PDecl->classprop_end(); P != E; ++P) { + ObjCPropertyDecl *Pr = (*P); + ObjCInterfaceDecl::classprop_iterator CP, CE; + // Is this property already in class's list of properties? + for (CP = IDecl->classprop_begin(), CE = IDecl->classprop_end(); + CP != CE; ++CP) + if ((*CP)->getIdentifier() == Pr->getIdentifier()) + break; + if (CP == CE) + // Add this property to list of properties for thie class. + mergeProperties.push_back(Pr); + else + // Property protocol already exist in class. Diagnose any mismatch. + DiagnosePropertyMismatch((*CP), Pr, PDecl->getName()); + } + IDecl->mergeProperties(&mergeProperties[0], mergeProperties.size()); +} + +/// MergeProtocolPropertiesIntoClass - This routine merges properties +/// declared in 'MergeItsProtocols' objects (which can be a class or an +/// inherited protocol into the list of properties for class 'IDecl' +/// + +void +Sema::MergeProtocolPropertiesIntoClass(ObjCInterfaceDecl *IDecl, + DeclTy *MergeItsProtocols) { + Decl *ClassDecl = static_cast(MergeItsProtocols); + if (ObjCInterfaceDecl *MDecl = + dyn_cast(ClassDecl)) { + for (ObjCInterfaceDecl::protocol_iterator P = MDecl->protocol_begin(), + E = MDecl->protocol_end(); P != E; ++P) + MergeOneProtocolPropertiesIntoClass(IDecl, (*P)); + // Merge properties of class (*P) into IDECL's + ; + // Go thru the list of protocols for this class and recursively merge + // their properties into this class as well. + for (ObjCInterfaceDecl::protocol_iterator P = IDecl->protocol_begin(), + E = IDecl->protocol_end(); P != E; ++P) + MergeProtocolPropertiesIntoClass(IDecl, (*P)); + } + else if (ObjCProtocolDecl *MDecl = + dyn_cast(ClassDecl)) + for (ObjCProtocolDecl::protocol_iterator P = MDecl->protocol_begin(), + E = MDecl->protocol_end(); P != E; ++P) + MergeOneProtocolPropertiesIntoClass(IDecl, (*P)); + else + assert(false && "MergeProtocolPropertiesIntoClass - bad object kind"); +} + /// ActOnForwardProtocolDeclaration - Action::DeclTy * Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, @@ -820,7 +876,8 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclTy *classDecl, &clsMethods[0], clsMethods.size(), AtEndLoc); // Compares properties declaraed in this class to those of its // super class. - ComparePropertiesInBaseAndSuper (I); + ComparePropertiesInBaseAndSuper(I); + MergeProtocolPropertiesIntoClass(I, I); } else if (ObjCProtocolDecl *P = dyn_cast(ClassDecl)) { P->addMethods(&insMethods[0], insMethods.size(), &clsMethods[0], clsMethods.size(), AtEndLoc); diff --git a/test/Sema/objc-property-3.m b/test/Sema/objc-property-3.m index 565a006fe4..dd45ab43f4 100644 --- a/test/Sema/objc-property-3.m +++ b/test/Sema/objc-property-3.m @@ -9,7 +9,7 @@ @end @interface NOW : I -@property (readonly, retain) id d1; // expected-warning {{attribute 'readonly' of property 'd1' restricts attribute 'readwrite' of 'I' property in super class}} expected-warning {{property 'd1' 'copy' attribute does not match super class 'I' property}} -@property (readwrite, copy) I* d2; // expected-warning {{property type 'I *' does not match super class 'I' property type}} +@property (readonly, retain) id d1; // expected-warning {{attribute 'readonly' of property 'd1' restricts attribute 'readwrite' of property inherited from 'I'}} expected-warning {{property 'd1' 'copy' attribute does not match the property inherited from'I'}} +@property (readwrite, copy) I* d2; // expected-warning {{property type 'I *' does not match property type inherited from 'I'}} @end diff --git a/test/Sema/objc-property-4.m b/test/Sema/objc-property-4.m new file mode 100644 index 0000000000..b5a8f8b1cc --- /dev/null +++ b/test/Sema/objc-property-4.m @@ -0,0 +1,30 @@ +// RUN: clang -verify %s + +@interface Object +@end + +@protocol ProtocolObject +@property int class; +@property (copy) id MayCauseError; +@end + +@protocol ProtocolDerivedGCObject +@property int Dclass; +@end + +@interface GCObject : Object { + int ifield; + int iOwnClass; + int iDclass; +} +@property int OwnClass; +@end + +@interface ReleaseObject : GCObject { + int newO; + int oldO; +} +@property (retain) id MayCauseError; // expected-warning {{property 'MayCauseError' 'copy' attribute does not match the property inherited from'GCObject'}} \ + expected-warning {{property 'MayCauseError' 'copy' attribute does not match the property inherited from'ProtocolObject'}} +@end + -- 2.40.0