From 1ac2bc44781ec8451f880dcf586768a71824d3a6 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Sat, 6 Dec 2008 23:03:39 +0000 Subject: [PATCH] Use of properties declared in protocols in the category via the category's protocol list1s, with appropriate diagnsostics and a test case. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@60634 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/DeclObjC.h | 2 + lib/AST/DeclObjC.cpp | 25 ++++++++++++ lib/Sema/Sema.h | 4 +- lib/Sema/SemaDeclObjC.cpp | 62 ++++++++++++++++++++++++++--- test/SemaObjC/property-category-3.m | 21 ++++++++++ 5 files changed, 106 insertions(+), 8 deletions(-) create mode 100644 test/SemaObjC/property-category-3.m diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index d2c707c955..190c1c3509 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -883,6 +883,8 @@ public: void addProperties(ObjCPropertyDecl **Properties, unsigned NumProperties); + void mergeProperties(ObjCPropertyDecl **Properties, unsigned NumProperties); + void addPropertyMethods(ASTContext &Context, ObjCPropertyDecl* Property, llvm::SmallVector &insMethods, diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 58d0383d1f..0458282fb3 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -513,6 +513,31 @@ void ObjCCategoryDecl::addPropertyMethods( ::addPropertyMethods(this, Context, property, insMethods, InsMap); } +/// mergeProperties - Adds properties to the end of list of current properties +/// for this category. + +void ObjCCategoryDecl::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*)); + delete[] PropertyDecl; + PropertyDecl = newPropertyDecl; + NumPropertyDecl += NumNewProperties; + } + else { + addProperties(Properties, NumNewProperties); + } +} + /// addPropertyMethods - Goes through list of properties declared in this class /// and builds setter/getter method declartions depending on the setter/getter /// attributes of the property. diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index a9ad257e41..ef99aaaa46 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1075,10 +1075,10 @@ public: const IdentifierInfo *Name); void ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl); - void MergeProtocolPropertiesIntoClass(ObjCInterfaceDecl *IDecl, + void MergeProtocolPropertiesIntoClass(Decl *CDecl, DeclTy *MergeProtocols); - void MergeOneProtocolPropertiesIntoClass(ObjCInterfaceDecl *IDecl, + void MergeOneProtocolPropertiesIntoClass(Decl *CDecl, ObjCProtocolDecl *PDecl); virtual void ActOnAtEnd(SourceLocation AtEndLoc, DeclTy *classDecl, diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index a5ffb70905..5493442580 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -311,11 +311,35 @@ Sema::ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl) { /// 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. +/// of properties for current class/category if it is not there already. void -Sema::MergeOneProtocolPropertiesIntoClass(ObjCInterfaceDecl *IDecl, +Sema::MergeOneProtocolPropertiesIntoClass(Decl *CDecl, ObjCProtocolDecl *PDecl) { llvm::SmallVector mergeProperties; + ObjCInterfaceDecl *IDecl = dyn_cast_or_null(CDecl); + if (!IDecl) { + // Category + ObjCCategoryDecl *CatDecl = static_cast(CDecl); + assert (CatDecl && "MergeOneProtocolPropertiesIntoClass"); + for (ObjCProtocolDecl::classprop_iterator P = PDecl->classprop_begin(), + E = PDecl->classprop_end(); P != E; ++P) { + ObjCPropertyDecl *Pr = (*P); + ObjCCategoryDecl::classprop_iterator CP, CE; + // Is this property already in category's list of properties? + for (CP = CatDecl->classprop_begin(), CE = CatDecl->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->getIdentifier()); + } + CatDecl->mergeProperties(&mergeProperties[0], mergeProperties.size()); + return; + } for (ObjCProtocolDecl::classprop_iterator P = PDecl->classprop_begin(), E = PDecl->classprop_end(); P != E; ++P) { ObjCPropertyDecl *Pr = (*P); @@ -337,13 +361,39 @@ Sema::MergeOneProtocolPropertiesIntoClass(ObjCInterfaceDecl *IDecl, /// 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' +/// inherited protocol into the list of properties for class/category 'CDecl' /// void -Sema::MergeProtocolPropertiesIntoClass(ObjCInterfaceDecl *IDecl, +Sema::MergeProtocolPropertiesIntoClass(Decl *CDecl, DeclTy *MergeItsProtocols) { Decl *ClassDecl = static_cast(MergeItsProtocols); + ObjCInterfaceDecl *IDecl = dyn_cast_or_null(CDecl); + + if (!IDecl) { + // Category + ObjCCategoryDecl *CatDecl = static_cast(CDecl); + assert (CatDecl && "MergeProtocolPropertiesIntoClass"); + if (ObjCCategoryDecl *MDecl = dyn_cast(ClassDecl)) { + for (ObjCCategoryDecl::protocol_iterator P = MDecl->protocol_begin(), + E = MDecl->protocol_end(); P != E; ++P) + // Merge properties of category (*P) into IDECL's + MergeOneProtocolPropertiesIntoClass(CatDecl, *P); + + // Go thru the list of protocols for this category and recursively merge + // their properties into this class as well. + for (ObjCCategoryDecl::protocol_iterator P = CatDecl->protocol_begin(), + E = CatDecl->protocol_end(); P != E; ++P) + MergeProtocolPropertiesIntoClass(CatDecl, *P); + } else { + ObjCProtocolDecl *MD = cast(ClassDecl); + for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(), + E = MD->protocol_end(); P != E; ++P) + MergeOneProtocolPropertiesIntoClass(CatDecl, (*P)); + } + return; + } + if (ObjCInterfaceDecl *MDecl = dyn_cast(ClassDecl)) { for (ObjCInterfaceDecl::protocol_iterator P = MDecl->protocol_begin(), E = MDecl->protocol_end(); P != E; ++P) @@ -1063,8 +1113,8 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclTy *classDecl, // By the same token, they are also used to add new properties. No // need to compare the added property to those in the class. - // FIXME: If we merge properties into class we should probably - // merge them into category as well? + // Merge protocol properties into category + MergeProtocolPropertiesIntoClass(C, C); for (ObjCCategoryDecl::classprop_iterator i = C->classprop_begin(), e = C->classprop_end(); i != e; ++i) { diagnosePropertySetterGetterMismatch((*i), InsMap[(*i)->getGetterName()], diff --git a/test/SemaObjC/property-category-3.m b/test/SemaObjC/property-category-3.m new file mode 100644 index 0000000000..d651b855bf --- /dev/null +++ b/test/SemaObjC/property-category-3.m @@ -0,0 +1,21 @@ +@protocol P + @property(readonly) int X; +@end + +@protocol P1

+ @property (copy) id ID; +@end + +@interface I +@end + +@interface I (Cat)

+@property float X; // expected-warning {{property type 'float' does not match property type inherited from 'P'}} +@end + +@interface I (Cat2) +@property (retain) id ID; // expected-warning {{property 'ID' 'copy' attribute does not match the property inherited from 'P1'}} +@end + + + -- 2.40.0