Author: mren Date: Thu Apr 7 14:32:24 2016 New Revision: 265712 URL: http://llvm.org/viewvc/llvm-project?rev=265712&view=rev Log: [ObjC kindof] Use type bound to filter out the candidate methods.
rdar://21306753 Modified: cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/lib/Sema/SemaDeclObjC.cpp cfe/trunk/lib/Sema/SemaExprObjC.cpp cfe/trunk/test/SemaObjC/kindof.m Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=265712&r1=265711&r2=265712&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Thu Apr 7 14:32:24 2016 @@ -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, Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=265712&r1=265711&r2=265712&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Thu Apr 7 14:32:24 2016 @@ -3281,11 +3281,45 @@ static bool isAcceptableMethodMismatch(O 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::CollectMultipleMethodsInGloba 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::CollectMultipleMethodsInGloba 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; } Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=265712&r1=265711&r2=265712&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Thu Apr 7 14:32:24 2016 @@ -2618,16 +2618,15 @@ ExprResult Sema::BuildInstanceMessage(Ex 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. Modified: cfe/trunk/test/SemaObjC/kindof.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/kindof.m?rev=265712&r1=265711&r2=265712&view=diff ============================================================================== --- cfe/trunk/test/SemaObjC/kindof.m (original) +++ cfe/trunk/test/SemaObjC/kindof.m Thu Apr 7 14:32:24 2016 @@ -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 NSSt [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 // --------------------------------------------------------------------------- _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits