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
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index c70b364..dca55b6 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -837,6 +837,8 @@
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
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index d60a820..f29f56e 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -873,6 +873,55 @@
}
}
+/// 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 @@
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 @@
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();
diff --git a/test/SemaObjC/conditional-expr-6.m b/test/SemaObjC/conditional-expr-6.m
index 88e943f..bba51bb 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 <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* 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;
}