This patch computes composite type of two objective-c expressions

used in a conditional expression by finding the most-derived common
super class of the two and qualifies the resulting type by the
intersection of the protocl qualifier list of the two objective-c
pointer types. ( this is continuation of radar 7334235).

llvm-svn: 85554
This commit is contained in:
Fariborz Jahanian 2009-10-30 01:13:23 +00:00
parent 3f0db2beb1
commit 6c5a8e2555
3 changed files with 131 additions and 4 deletions

View File

@ -837,6 +837,8 @@ public:
llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars);
unsigned CountSynthesizedIvars(const ObjCInterfaceDecl *OI);
unsigned CountProtocolSynthesizedIvars(const ObjCProtocolDecl *PD);
void CollectInheritedProtocols(const Decl *CDecl,
llvm::SmallVectorImpl<ObjCProtocolDecl*> &Protocols);
//===--------------------------------------------------------------------===//
// Type Operators

View File

@ -873,6 +873,55 @@ void ASTContext::CollectSynthesizedIvars(const ObjCInterfaceDecl *OI,
}
}
/// CollectInheritedProtocols - Collect all protocols in current class and
/// those inherited by it.
void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
llvm::SmallVectorImpl<ObjCProtocolDecl*> &Protocols) {
if (const ObjCInterfaceDecl *OI = dyn_cast<ObjCInterfaceDecl>(CDecl)) {
for (ObjCInterfaceDecl::protocol_iterator P = OI->protocol_begin(),
PE = OI->protocol_end(); P != PE; ++P) {
ObjCProtocolDecl *Proto = (*P);
Protocols.push_back(Proto);
for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(),
PE = Proto->protocol_end(); P != PE; ++P)
CollectInheritedProtocols(*P, Protocols);
}
// Categories of this Interface.
for (const ObjCCategoryDecl *CDeclChain = OI->getCategoryList();
CDeclChain; CDeclChain = CDeclChain->getNextClassCategory())
CollectInheritedProtocols(CDeclChain, Protocols);
if (ObjCInterfaceDecl *SD = OI->getSuperClass())
while (SD) {
CollectInheritedProtocols(SD, Protocols);
SD = SD->getSuperClass();
}
return;
}
if (const ObjCCategoryDecl *OC = dyn_cast<ObjCCategoryDecl>(CDecl)) {
for (ObjCInterfaceDecl::protocol_iterator P = OC->protocol_begin(),
PE = OC->protocol_end(); P != PE; ++P) {
ObjCProtocolDecl *Proto = (*P);
Protocols.push_back(Proto);
for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(),
PE = Proto->protocol_end(); P != PE; ++P)
CollectInheritedProtocols(*P, Protocols);
}
return;
}
if (const ObjCProtocolDecl *OP = dyn_cast<ObjCProtocolDecl>(CDecl)) {
for (ObjCProtocolDecl::protocol_iterator P = OP->protocol_begin(),
PE = OP->protocol_end(); P != PE; ++P) {
ObjCProtocolDecl *Proto = (*P);
Protocols.push_back(Proto);
for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(),
PE = Proto->protocol_end(); P != PE; ++P)
CollectInheritedProtocols(*P, Protocols);
}
return;
}
}
unsigned ASTContext::CountProtocolSynthesizedIvars(const ObjCProtocolDecl *PD) {
unsigned count = 0;
for (ObjCContainerDecl::prop_iterator I = PD->prop_begin(),
@ -3859,6 +3908,48 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
return false;
}
/// getIntersectionOfProtocols - This routine finds the intersection of set
/// of protocols inherited from two distinct objective-c pointer objects.
/// It is used to build composite qualifier list of the composite type of
/// the conditional expression involving two objective-c pointer objects.
static
void getIntersectionOfProtocols(ASTContext &Context,
const ObjCObjectPointerType *LHSOPT,
const ObjCObjectPointerType *RHSOPT,
llvm::SmallVectorImpl<ObjCProtocolDecl *> &IntersectionOfProtocols) {
const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType();
const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType();
llvm::SmallPtrSet<ObjCProtocolDecl *, 8> InheritedProtocolSet;
unsigned LHSNumProtocols = LHS->getNumProtocols();
if (LHSNumProtocols > 0)
InheritedProtocolSet.insert(LHS->qual_begin(), LHS->qual_end());
else {
llvm::SmallVector<ObjCProtocolDecl *, 8> LHSInheritedProtocols;
Context.CollectInheritedProtocols(LHS->getDecl(), LHSInheritedProtocols);
InheritedProtocolSet.insert(LHSInheritedProtocols.begin(),
LHSInheritedProtocols.end());
}
unsigned RHSNumProtocols = RHS->getNumProtocols();
if (RHSNumProtocols > 0) {
ObjCProtocolDecl **RHSProtocols = (ObjCProtocolDecl **)RHS->qual_begin();
for (unsigned i = 0; i < RHSNumProtocols; ++i)
if (InheritedProtocolSet.count(RHSProtocols[i]))
IntersectionOfProtocols.push_back(RHSProtocols[i]);
}
else {
llvm::SmallVector<ObjCProtocolDecl *, 8> RHSInheritedProtocols;
Context.CollectInheritedProtocols(RHS->getDecl(), RHSInheritedProtocols);
// FIXME. This may cause duplication of protocols in the list, but should
// be harmless.
for (unsigned i = 0, len = RHSInheritedProtocols.size(); i < len; ++i)
if (InheritedProtocolSet.count(RHSInheritedProtocols[i]))
IntersectionOfProtocols.push_back(RHSInheritedProtocols[i]);
}
}
/// areCommonBaseCompatible - Returns common base class of the two classes if
/// one found. Note that this is O'2 algorithm. But it will be called as the
/// last type comparison in a ?-exp of ObjC pointer types before a
@ -3874,8 +3965,17 @@ QualType ASTContext::areCommonBaseCompatible(
while (const ObjCInterfaceDecl *LHSIDecl = LHS->getDecl()->getSuperClass()) {
QualType LHSTy = getObjCInterfaceType(LHSIDecl);
LHS = LHSTy->getAs<ObjCInterfaceType>();
if (canAssignObjCInterfaces(LHS, RHS))
return getObjCObjectPointerType(LHSTy);
if (canAssignObjCInterfaces(LHS, RHS)) {
llvm::SmallVector<ObjCProtocolDecl *, 8> IntersectionOfProtocols;
getIntersectionOfProtocols(*this,
LHSOPT, RHSOPT, IntersectionOfProtocols);
if (IntersectionOfProtocols.empty())
LHSTy = getObjCObjectPointerType(LHSTy);
else
LHSTy = getObjCObjectPointerType(LHSTy, &IntersectionOfProtocols[0],
IntersectionOfProtocols.size());
return LHSTy;
}
}
return QualType();

View File

@ -1,17 +1,25 @@
// RUN: clang-cc -fsyntax-only -verify %s
@protocol MyProtocol @end
@interface NSObject @end
@interface NSInterm : NSObject
@interface NSInterm : NSObject <MyProtocol>
@end
@interface NSArray : NSInterm
@end
@interface NSSet : NSObject
@interface NSSet : NSObject <MyProtocol>
@end
@interface N1 : NSObject
@end
@interface N1() <MyProtocol>
@end
NSObject* test (int argc) {
NSArray *array = ((void*)0);
NSSet *set = ((void*)0);
@ -22,5 +30,22 @@ NSObject* test (int argc) {
NSObject* test1 (int argc) {
NSArray *array = ((void*)0);
NSSet *set = ((void*)0);
id <MyProtocol> instance = (argc) ? array : set;
id <MyProtocol> instance1 = (argc) ? set : array;
N1 *n1 = ((void*)0);
id <MyProtocol> instance2 = (argc) ? set : n1;
id <MyProtocol> instance3 = (argc) ? n1 : array;
NSArray<MyProtocol> *qual_array = ((void*)0);
id <MyProtocol> instance4 = (argc) ? array : qual_array;
id <MyProtocol> instance5 = (argc) ? qual_array : array;
NSSet<MyProtocol> *qual_set = ((void*)0);
id <MyProtocol> instance6 = (argc) ? qual_set : qual_array;
id <MyProtocol> instance7 = (argc) ? qual_set : array;
id <MyProtocol> instance8 = (argc) ? qual_array : set;
id <MyProtocol> instance9 = (argc) ? qual_array : qual_set;
return (argc) ? array : set;
}