summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Sema/Sema.h3
-rw-r--r--lib/Sema/SemaDeclObjC.cpp48
-rw-r--r--lib/Sema/SemaExprObjC.cpp5
-rw-r--r--test/SemaObjC/kindof.m16
4 files changed, 61 insertions, 11 deletions
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 8e9489f8cf..f5813bf097 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -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,
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 8ba3e7acec..32244e9e19 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -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;
}
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 7a51e612af..56161c7a4d 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -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.
diff --git a/test/SemaObjC/kindof.m b/test/SemaObjC/kindof.m
index f205e68ea1..36c9b8f0a2 100644
--- a/test/SemaObjC/kindof.m
+++ b/test/SemaObjC/kindof.m
@@ -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
// ---------------------------------------------------------------------------