From e23fa2d0e84d1b878e012442a726c664216a9adf Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Fri, 30 Oct 2009 01:13:23 +0000 Subject: [PATCH] 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). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@85554 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTContext.h | 2 + lib/AST/ASTContext.cpp | 104 ++++++++++++++++++++++++++++- test/SemaObjC/conditional-expr-6.m | 29 +++++++- 3 files changed, 131 insertions(+), 4 deletions(-) diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index c70b3640f9..dca55b6d3f 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -837,6 +837,8 @@ public: llvm::SmallVectorImpl &Ivars); unsigned CountSynthesizedIvars(const ObjCInterfaceDecl *OI); unsigned CountProtocolSynthesizedIvars(const ObjCProtocolDecl *PD); + void CollectInheritedProtocols(const Decl *CDecl, + llvm::SmallVectorImpl &Protocols); //===--------------------------------------------------------------------===// // Type Operators diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index d60a8204c7..f29f56e278 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -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 &Protocols) { + if (const ObjCInterfaceDecl *OI = dyn_cast(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(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(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 &IntersectionOfProtocols) { + + const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType(); + const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType(); + + llvm::SmallPtrSet InheritedProtocolSet; + unsigned LHSNumProtocols = LHS->getNumProtocols(); + if (LHSNumProtocols > 0) + InheritedProtocolSet.insert(LHS->qual_begin(), LHS->qual_end()); + else { + llvm::SmallVector 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 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(); - if (canAssignObjCInterfaces(LHS, RHS)) - return getObjCObjectPointerType(LHSTy); + if (canAssignObjCInterfaces(LHS, RHS)) { + llvm::SmallVector IntersectionOfProtocols; + getIntersectionOfProtocols(*this, + LHSOPT, RHSOPT, IntersectionOfProtocols); + if (IntersectionOfProtocols.empty()) + LHSTy = getObjCObjectPointerType(LHSTy); + else + LHSTy = getObjCObjectPointerType(LHSTy, &IntersectionOfProtocols[0], + IntersectionOfProtocols.size()); + return LHSTy; + } } return QualType(); diff --git a/test/SemaObjC/conditional-expr-6.m b/test/SemaObjC/conditional-expr-6.m index 88e943f3c6..bba51bb817 100644 --- a/test/SemaObjC/conditional-expr-6.m +++ b/test/SemaObjC/conditional-expr-6.m @@ -1,17 +1,25 @@ // RUN: clang-cc -fsyntax-only -verify %s +@protocol MyProtocol @end + @interface NSObject @end -@interface NSInterm : NSObject +@interface NSInterm : NSObject @end @interface NSArray : NSInterm @end -@interface NSSet : NSObject +@interface NSSet : NSObject @end +@interface N1 : NSObject +@end + +@interface N1() +@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 instance = (argc) ? array : set; + id instance1 = (argc) ? set : array; + + N1 *n1 = ((void*)0); + id instance2 = (argc) ? set : n1; + id instance3 = (argc) ? n1 : array; + + NSArray *qual_array = ((void*)0); + id instance4 = (argc) ? array : qual_array; + id instance5 = (argc) ? qual_array : array; + NSSet *qual_set = ((void*)0); + id instance6 = (argc) ? qual_set : qual_array; + id instance7 = (argc) ? qual_set : array; + id instance8 = (argc) ? qual_array : set; + id instance9 = (argc) ? qual_array : qual_set; + + return (argc) ? array : set; } -- 2.40.0