Objective-C. This patch is to resolve the method used in method

expression to the best method found in global method pools. 
This is wip.  // rdar://16808765

llvm-svn: 215577
This commit is contained in:
Fariborz Jahanian 2014-08-13 21:07:35 +00:00
parent abea99f65a
commit 30ae8d4413
6 changed files with 147 additions and 4 deletions

View File

@ -2883,6 +2883,19 @@ private:
ObjCMethodDecl *LookupMethodInGlobalPool(Selector Sel, SourceRange R,
bool receiverIdOrClass,
bool warn, bool instance);
/// \brief - Returns instance or factory methods in global method pool for
/// given selector. If no such method or only one method found, function returns
/// false; otherwise, it returns true
bool CollectMultipleMethodsInGlobalPool(Selector Sel,
SmallVectorImpl<ObjCMethodDecl*>& Methods,
bool instance);
/// \brief - Returns a selector which best matches given argument list or
/// nullptr if none could be found
ObjCMethodDecl *SelectBestMethod(Selector Sel, MultiExprArg Args,
SmallVectorImpl<ObjCMethodDecl*>& Methods);
/// \brief Record the typo correction failure and return an empty correction.
TypoCorrection FailedCorrection(IdentifierInfo *Typo, SourceLocation TypoLoc,

View File

@ -2315,6 +2315,23 @@ static bool isAcceptableMethodMismatch(ObjCMethodDecl *chosen,
return (chosen->getReturnType()->isIntegerType());
}
bool Sema::CollectMultipleMethodsInGlobalPool(Selector Sel,
SmallVectorImpl<ObjCMethodDecl*>& Methods,
bool instance) {
if (ExternalSource)
ReadMethodPool(Sel);
GlobalMethodPool::iterator Pos = MethodPool.find(Sel);
if (Pos == MethodPool.end())
return false;
// Gather the non-hidden methods.
ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second;
for (ObjCMethodList *M = &MethList; M; M = M->getNext())
if (M->Method && !M->Method->isHidden())
Methods.push_back(M->Method);
return (Methods.size() > 1);
}
ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
bool receiverIdOrClass,
bool warn, bool instance) {

View File

@ -2418,6 +2418,13 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
Method = LookupFactoryMethodInGlobalPool(Sel,
SourceRange(LBracLoc,RBracLoc),
receiverIsId);
if (Method) {
SmallVector<ObjCMethodDecl*, 4> Methods;
if (CollectMultipleMethodsInGlobalPool(Sel, Methods,
Method->isInstanceMethod()))
if (ObjCMethodDecl *BestMethod = SelectBestMethod(Sel, ArgsIn, Methods))
Method = BestMethod;
}
} else if (ReceiverType->isObjCClassType() ||
ReceiverType->isObjCQualifiedClassType()) {
// Handle messages to Class.

View File

@ -5677,6 +5677,79 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
}
}
ObjCMethodDecl *Sema::SelectBestMethod(Selector Sel, MultiExprArg Args,
SmallVectorImpl<ObjCMethodDecl*>& Methods) {
for (unsigned b = 0, e = Methods.size(); b < e; b++) {
bool Match = true;
ObjCMethodDecl *Method = Methods[b];
unsigned NumNamedArgs = Sel.getNumArgs();
// Method might have more arguments than selector indicates. This is due
// to addition of c-style arguments in method.
if (Method->param_size() > NumNamedArgs)
NumNamedArgs = Method->param_size();
if (Args.size() < NumNamedArgs)
continue;
for (unsigned i = 0; i < NumNamedArgs; i++) {
// We can't do any type-checking on a type-dependent argument.
if (Args[i]->isTypeDependent()) {
Match = false;
break;
}
ParmVarDecl *param = Method->parameters()[i];
Expr *argExpr = Args[i];
assert(argExpr && "SelectBestMethod(): missing expression");
// Strip the unbridged-cast placeholder expression off unless it's
// a consumed argument.
if (argExpr->hasPlaceholderType(BuiltinType::ARCUnbridgedCast) &&
!param->hasAttr<CFConsumedAttr>())
argExpr = stripARCUnbridgedCast(argExpr);
// If the parameter is __unknown_anytype, move on to the next method.
if (param->getType() == Context.UnknownAnyTy) {
Match = false;
break;
}
ImplicitConversionSequence ConversionState
= TryCopyInitialization(*this, argExpr, param->getType(),
/*SuppressUserConversions*/false,
/*InOverloadResolution=*/true,
/*AllowObjCWritebackConversion=*/
getLangOpts().ObjCAutoRefCount,
/*AllowExplicit*/false);
if (ConversionState.isBad()) {
Match = false;
break;
}
}
// Promote additional arguments to variadic methods.
if (Match && Method->isVariadic()) {
for (unsigned i = NumNamedArgs, e = Args.size(); i < e; ++i) {
if (Args[i]->isTypeDependent()) {
Match = false;
break;
}
ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], VariadicMethod,
nullptr);
if (Arg.isInvalid()) {
Match = false;
break;
}
}
} else
// Check for extra arguments to non-variadic methods.
if (Args.size() != NumNamedArgs)
Match = false;
if (Match)
return Method;
}
return nullptr;
}
static bool IsNotEnableIfAttr(Attr *A) { return !isa<EnableIfAttr>(A); }
EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,

View File

@ -0,0 +1,35 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -fblocks -Wno-objc-root-class %s
// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fsyntax-only -verify -fblocks -Wno-objc-root-class %s
// expected-no-diagnostics
// rdar://16808765
@interface NSObject @end
@class NSDictionary;
@class NSError;
@interface Foo : NSObject
- (void)getDonuts:(void (^)(NSDictionary *, NSError *))replyBlock;
- (void)getCake:(int*)arg, ...;
@end
@protocol Protocol
@required
- (void)getDonuts:(void (^)(NSDictionary *))replyBlock;
- (void)getCake:(float*)arg, ...;
@end
@implementation Foo
{
float g;
}
- (void)getDonuts:(void (^)(NSDictionary *, NSError *))replyBlock {
[(id) 0 getDonuts:^(NSDictionary *replyDict) { }];
}
- (void) getCake:(int*)arg, ... {
[(id)0 getCake: &g, 1,3.14];
}
@end

View File

@ -29,8 +29,7 @@ id foo(void) {
}
@protocol MyObject
- (id)initWithData:(Object *)data; // expected-note {{using}} \
// expected-note {{passing argument to parameter 'data' here}}
- (id)initWithData:(Object *)data; // expected-note {{using}}
@end
@protocol SomeOther
@ -54,8 +53,7 @@ id foo(void) {
}
+ (NTGridDataObject*)dataObject:(id<MyObject, MyCoding>)data
{
NTGridDataObject *result = [(id)0 initWithData:data]; // expected-warning {{multiple methods named 'initWithData:' found}} \
expected-warning {{sending 'id<MyObject,MyCoding>' to parameter of incompatible type 'Object *'}}
NTGridDataObject *result = [(id)0 initWithData:data]; // expected-warning {{multiple methods named 'initWithData:' found}}
return result;
}
@end