forked from OSchip/llvm-project
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:
parent
abea99f65a
commit
30ae8d4413
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue