[ObjC kindof] Use type bound to filter out the candidate methods.
rdar://21306753 llvm-svn: 265712
This commit is contained in:
parent
d2a3cd7261
commit
7ed4f988c1
|
@ -3162,7 +3162,8 @@ public:
|
|||
bool
|
||||
CollectMultipleMethodsInGlobalPool(Selector Sel,
|
||||
SmallVectorImpl<ObjCMethodDecl*>& Methods,
|
||||
bool InstanceFirst, bool CheckTheOther);
|
||||
bool InstanceFirst, bool CheckTheOther,
|
||||
const ObjCObjectType *TypeBound = nullptr);
|
||||
|
||||
bool
|
||||
AreMultipleMethodsInGlobalPool(Selector Sel, ObjCMethodDecl *BestMethod,
|
||||
|
|
|
@ -3281,11 +3281,45 @@ static bool isAcceptableMethodMismatch(ObjCMethodDecl *chosen,
|
|||
return (chosen->getReturnType()->isIntegerType());
|
||||
}
|
||||
|
||||
/// Return true if the given method is wthin the type bound.
|
||||
static bool FilterMethodsByTypeBound(ObjCMethodDecl *Method,
|
||||
const ObjCObjectType *TypeBound) {
|
||||
if (!TypeBound)
|
||||
return true;
|
||||
|
||||
if (TypeBound->isObjCId())
|
||||
// FIXME: should we handle the case of bounding to id<A, B> differently?
|
||||
return true;
|
||||
|
||||
auto *BoundInterface = TypeBound->getInterface();
|
||||
assert(BoundInterface && "unexpected object type!");
|
||||
|
||||
// Check if the Method belongs to a protocol. We should allow any method
|
||||
// defined in any protocol, because any subclass could adopt the protocol.
|
||||
auto *MethodProtocol = dyn_cast<ObjCProtocolDecl>(Method->getDeclContext());
|
||||
if (MethodProtocol) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the Method belongs to a class, check if it belongs to the class
|
||||
// hierarchy of the class bound.
|
||||
if (ObjCInterfaceDecl *MethodInterface = Method->getClassInterface()) {
|
||||
// We allow methods declared within classes that are part of the hierarchy
|
||||
// of the class bound (superclass of, subclass of, or the same as the class
|
||||
// bound).
|
||||
return MethodInterface == BoundInterface ||
|
||||
MethodInterface->isSuperClassOf(BoundInterface) ||
|
||||
BoundInterface->isSuperClassOf(MethodInterface);
|
||||
}
|
||||
llvm_unreachable("unknow method context");
|
||||
}
|
||||
|
||||
/// We first select the type of the method: Instance or Factory, then collect
|
||||
/// all methods with that type.
|
||||
bool Sema::CollectMultipleMethodsInGlobalPool(
|
||||
Selector Sel, SmallVectorImpl<ObjCMethodDecl *> &Methods,
|
||||
bool InstanceFirst, bool CheckTheOther) {
|
||||
bool InstanceFirst, bool CheckTheOther,
|
||||
const ObjCObjectType *TypeBound) {
|
||||
if (ExternalSource)
|
||||
ReadMethodPool(Sel);
|
||||
|
||||
|
@ -3297,8 +3331,10 @@ bool Sema::CollectMultipleMethodsInGlobalPool(
|
|||
ObjCMethodList &MethList = InstanceFirst ? Pos->second.first :
|
||||
Pos->second.second;
|
||||
for (ObjCMethodList *M = &MethList; M; M = M->getNext())
|
||||
if (M->getMethod() && !M->getMethod()->isHidden())
|
||||
Methods.push_back(M->getMethod());
|
||||
if (M->getMethod() && !M->getMethod()->isHidden()) {
|
||||
if (FilterMethodsByTypeBound(M->getMethod(), TypeBound))
|
||||
Methods.push_back(M->getMethod());
|
||||
}
|
||||
|
||||
// Return if we find any method with the desired kind.
|
||||
if (!Methods.empty())
|
||||
|
@ -3311,8 +3347,10 @@ bool Sema::CollectMultipleMethodsInGlobalPool(
|
|||
ObjCMethodList &MethList2 = InstanceFirst ? Pos->second.second :
|
||||
Pos->second.first;
|
||||
for (ObjCMethodList *M = &MethList2; M; M = M->getNext())
|
||||
if (M->getMethod() && !M->getMethod()->isHidden())
|
||||
Methods.push_back(M->getMethod());
|
||||
if (M->getMethod() && !M->getMethod()->isHidden()) {
|
||||
if (FilterMethodsByTypeBound(M->getMethod(), TypeBound))
|
||||
Methods.push_back(M->getMethod());
|
||||
}
|
||||
|
||||
return Methods.size() > 1;
|
||||
}
|
||||
|
|
|
@ -2618,16 +2618,15 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
|
|||
if (!Method) {
|
||||
// Handle messages to id and __kindof types (where we use the
|
||||
// global method pool).
|
||||
// FIXME: The type bound is currently ignored by lookup in the
|
||||
// global pool.
|
||||
const ObjCObjectType *typeBound = nullptr;
|
||||
bool receiverIsIdLike = ReceiverType->isObjCIdOrObjectKindOfType(Context,
|
||||
typeBound);
|
||||
if (receiverIsIdLike || ReceiverType->isBlockPointerType() ||
|
||||
(Receiver && Context.isObjCNSObjectType(Receiver->getType()))) {
|
||||
SmallVector<ObjCMethodDecl*, 4> Methods;
|
||||
// If we have a type bound, further filter the methods.
|
||||
CollectMultipleMethodsInGlobalPool(Sel, Methods, true/*InstanceFirst*/,
|
||||
true/*CheckTheOther*/);
|
||||
true/*CheckTheOther*/, typeBound);
|
||||
if (!Methods.empty()) {
|
||||
// We chose the first method as the initial condidate, then try to
|
||||
// select a better one.
|
||||
|
|
|
@ -24,7 +24,7 @@ __attribute__((objc_root_class))
|
|||
- (NSObject *)retain;
|
||||
@end
|
||||
|
||||
@interface NSString : NSObject <NSCopying>
|
||||
@interface NSString : NSObject <NSCopying> // expected-note{{receiver is instance of class declared here}}
|
||||
- (NSString *)stringByAppendingString:(NSString *)string;
|
||||
+ (instancetype)string;
|
||||
@end
|
||||
|
@ -246,7 +246,7 @@ void message_kindof_object(__kindof NSString *kindof_NSString) {
|
|||
[kindof_NSString retain]; // in superclass
|
||||
[kindof_NSString stringByAppendingString:0]; // in class
|
||||
[kindof_NSString appendString:0]; // in subclass
|
||||
[kindof_NSString numberByAddingNumber: 0]; // FIXME: in unrelated class
|
||||
[kindof_NSString numberByAddingNumber: 0]; // expected-warning{{instance method '-numberByAddingNumber:' not found (return type defaults to 'id')}}
|
||||
[kindof_NSString randomMethod]; // in protocol
|
||||
}
|
||||
|
||||
|
@ -263,6 +263,18 @@ void message_kindof_qualified_class(
|
|||
[kindof_NSCopying randomClassMethod]; // in unrelated protocol
|
||||
}
|
||||
|
||||
// Make sure we don't emit warning about multiple methods found.
|
||||
typedef int NSInteger;
|
||||
@interface Foo : NSObject
|
||||
- (NSString*)test;
|
||||
@end
|
||||
@interface Bar : NSObject
|
||||
- (NSInteger)test;
|
||||
@end
|
||||
void test(__kindof Bar *kBar) {
|
||||
[kBar test];
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// __kindof within specialized types
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in New Issue