From 7cdaec7226b4fa62d57f16704c84291c702b2968 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Wed, 13 Aug 2014 21:07:35 +0000 Subject: [PATCH] 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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@215577 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Sema.h | 13 ++++ lib/Sema/SemaDeclObjC.cpp | 17 +++++ lib/Sema/SemaExprObjC.cpp | 7 ++ lib/Sema/SemaOverload.cpp | 73 +++++++++++++++++++ test/SemaObjC/resolve-method-in-global-pool.m | 35 +++++++++ test/SemaObjC/warn-strict-selector-match.m | 6 +- 6 files changed, 147 insertions(+), 4 deletions(-) create mode 100644 test/SemaObjC/resolve-method-in-global-pool.m diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index b1707517b7..db8ba03d51 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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& 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& Methods); + /// \brief Record the typo correction failure and return an empty correction. TypoCorrection FailedCorrection(IdentifierInfo *Typo, SourceLocation TypoLoc, diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 469e45c753..8e3e85ed28 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -2315,6 +2315,23 @@ static bool isAcceptableMethodMismatch(ObjCMethodDecl *chosen, return (chosen->getReturnType()->isIntegerType()); } +bool Sema::CollectMultipleMethodsInGlobalPool(Selector Sel, + SmallVectorImpl& 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) { diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 3e7b620466..6cc1658934 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -2418,6 +2418,13 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(LBracLoc,RBracLoc), receiverIsId); + if (Method) { + SmallVector 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. diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index d719b84c96..660d60da2a 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -5677,6 +5677,79 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, } } +ObjCMethodDecl *Sema::SelectBestMethod(Selector Sel, MultiExprArg Args, + SmallVectorImpl& 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()) + 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(A); } EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef Args, diff --git a/test/SemaObjC/resolve-method-in-global-pool.m b/test/SemaObjC/resolve-method-in-global-pool.m new file mode 100644 index 0000000000..38a2bb7ca5 --- /dev/null +++ b/test/SemaObjC/resolve-method-in-global-pool.m @@ -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 diff --git a/test/SemaObjC/warn-strict-selector-match.m b/test/SemaObjC/warn-strict-selector-match.m index 34f1712f8b..9f22e73edc 100644 --- a/test/SemaObjC/warn-strict-selector-match.m +++ b/test/SemaObjC/warn-strict-selector-match.m @@ -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)data { - NTGridDataObject *result = [(id)0 initWithData:data]; // expected-warning {{multiple methods named 'initWithData:' found}} \ - expected-warning {{sending 'id' to parameter of incompatible type 'Object *'}} + NTGridDataObject *result = [(id)0 initWithData:data]; // expected-warning {{multiple methods named 'initWithData:' found}} return result; } @end -- 2.50.1