Use of properties declared in protocols in the category

via the category's protocol list1s, with appropriate
diagnsostics and a test case.

llvm-svn: 60634
This commit is contained in:
Fariborz Jahanian 2008-12-06 23:03:39 +00:00
parent da93063acc
commit d2c2ad515e
5 changed files with 106 additions and 8 deletions

View File

@ -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<ObjCMethodDecl*, 32> &insMethods,

View File

@ -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.

View File

@ -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,

View File

@ -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<ObjCPropertyDecl*, 16> mergeProperties;
ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl);
if (!IDecl) {
// Category
ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(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<Decl *>(MergeItsProtocols);
ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl);
if (!IDecl) {
// Category
ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl);
assert (CatDecl && "MergeProtocolPropertiesIntoClass");
if (ObjCCategoryDecl *MDecl = dyn_cast<ObjCCategoryDecl>(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<ObjCProtocolDecl>(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<ObjCInterfaceDecl>(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()],

View File

@ -0,0 +1,21 @@
@protocol P
@property(readonly) int X;
@end
@protocol P1<P>
@property (copy) id ID;
@end
@interface I
@end
@interface I (Cat) <P>
@property float X; // expected-warning {{property type 'float' does not match property type inherited from 'P'}}
@end
@interface I (Cat2) <P1>
@property (retain) id ID; // expected-warning {{property 'ID' 'copy' attribute does not match the property inherited from 'P1'}}
@end