From: Fariborz Jahanian Date: Wed, 15 Apr 2015 17:26:21 +0000 (+0000) Subject: [Objective-C Sema]This patch fixes the warning when clang issues X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d6104dcab55259935bfc5287a2e9d0b89c6365f9;p=clang [Objective-C Sema]This patch fixes the warning when clang issues "multiple methods named '' found" warning by noting the method that is actualy used. It also cleans up and refactors code in this area and selects a method that matches actual arguments in case of receiver being a forward class object. rdar://19265430 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@235023 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 3f31071790..84302fa669 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -2908,7 +2908,7 @@ private: /// optionally warns if there are multiple signatures. ObjCMethodDecl *LookupMethodInGlobalPool(Selector Sel, SourceRange R, bool receiverIdOrClass, - bool warn, bool instance); + bool instance); public: /// \brief - Returns instance or factory methods in global method pool for @@ -2918,8 +2918,13 @@ public: SmallVectorImpl& Methods, bool instance); - bool AreMultipleMethodsInGlobalPool(Selector Sel, - bool instance); + bool AreMultipleMethodsInGlobalPool(Selector Sel, ObjCMethodDecl *BestMethod, + SourceRange R, + bool receiverIdOrClass); + + void DiagnoseMultipleMethodInGlobalPool(SmallVectorImpl &Methods, + Selector Sel, SourceRange R, + bool receiverIdOrClass); private: /// \brief - Returns a selector which best matches given argument list or @@ -2957,19 +2962,17 @@ public: /// LookupInstanceMethodInGlobalPool - Returns the method and warns if /// there are multiple signatures. ObjCMethodDecl *LookupInstanceMethodInGlobalPool(Selector Sel, SourceRange R, - bool receiverIdOrClass=false, - bool warn=true) { + bool receiverIdOrClass=false) { return LookupMethodInGlobalPool(Sel, R, receiverIdOrClass, - warn, /*instance*/true); + /*instance*/true); } /// LookupFactoryMethodInGlobalPool - Returns the method and warns if /// there are multiple signatures. ObjCMethodDecl *LookupFactoryMethodInGlobalPool(Selector Sel, SourceRange R, - bool receiverIdOrClass=false, - bool warn=true) { + bool receiverIdOrClass=false) { return LookupMethodInGlobalPool(Sel, R, receiverIdOrClass, - warn, /*instance*/false); + /*instance*/false); } const ObjCMethodDecl *SelectorsForTypoCorrection(Selector Sel, diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 800abd13e0..256419353c 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -2346,19 +2346,33 @@ bool Sema::CollectMultipleMethodsInGlobalPool( return Methods.size() > 1; } -bool Sema::AreMultipleMethodsInGlobalPool(Selector Sel, bool instance) { +bool Sema::AreMultipleMethodsInGlobalPool(Selector Sel, ObjCMethodDecl *BestMethod, + SourceRange R, + bool receiverIdOrClass) { GlobalMethodPool::iterator Pos = MethodPool.find(Sel); // Test for no method in the pool which should not trigger any warning by // caller. if (Pos == MethodPool.end()) return true; - ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second; + ObjCMethodList &MethList = + BestMethod->isInstanceMethod() ? Pos->second.first : Pos->second.second; + + // Diagnose finding more than one method in global pool + SmallVector Methods; + Methods.push_back(BestMethod); + for (ObjCMethodList *M = &MethList; M; M = M->getNext()) + if (M->getMethod() && !M->getMethod()->isHidden() && + M->getMethod() != BestMethod) + Methods.push_back(M->getMethod()); + if (Methods.size() > 1) + DiagnoseMultipleMethodInGlobalPool(Methods, Sel, R, receiverIdOrClass); + return MethList.hasMoreThanOneDecl(); } ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R, bool receiverIdOrClass, - bool warn, bool instance) { + bool instance) { if (ExternalSource) ReadMethodPool(Sel); @@ -2370,31 +2384,23 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R, ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second; SmallVector Methods; for (ObjCMethodList *M = &MethList; M; M = M->getNext()) { - if (M->getMethod() && !M->getMethod()->isHidden()) { - // If we're not supposed to warn about mismatches, we're done. - if (!warn) - return M->getMethod(); - - Methods.push_back(M->getMethod()); - } + if (M->getMethod() && !M->getMethod()->isHidden()) + return M->getMethod(); } + return nullptr; +} - // If there aren't any visible methods, we're done. - // FIXME: Recover if there are any known-but-hidden methods? - if (Methods.empty()) - return nullptr; - - if (Methods.size() == 1) - return Methods[0]; - +void Sema::DiagnoseMultipleMethodInGlobalPool(SmallVectorImpl &Methods, + Selector Sel, SourceRange R, + bool receiverIdOrClass) { // We found multiple methods, so we may have to complain. bool issueDiagnostic = false, issueError = false; - + // We support a warning which complains about *any* difference in // method signature. bool strictSelectorMatch = - receiverIdOrClass && warn && - !Diags.isIgnored(diag::warn_strict_multiple_method_decl, R.getBegin()); + receiverIdOrClass && + !Diags.isIgnored(diag::warn_strict_multiple_method_decl, R.getBegin()); if (strictSelectorMatch) { for (unsigned I = 1, N = Methods.size(); I != N; ++I) { if (!MatchTwoMethodDeclarations(Methods[0], Methods[I], MMS_strict)) { @@ -2403,7 +2409,7 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R, } } } - + // If we didn't see any strict differences, we won't see any loose // differences. In ARC, however, we also need to check for loose // mismatches, because most of them are errors. @@ -2419,7 +2425,7 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R, break; } } - + if (issueDiagnostic) { if (issueError) Diag(R.getBegin(), diag::err_arc_multiple_method_decl) << Sel << R; @@ -2427,16 +2433,15 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R, Diag(R.getBegin(), diag::warn_strict_multiple_method_decl) << Sel << R; else Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R; - + Diag(Methods[0]->getLocStart(), issueError ? diag::note_possibility : diag::note_using) - << Methods[0]->getSourceRange(); + << Methods[0]->getSourceRange(); for (unsigned I = 1, N = Methods.size(); I != N; ++I) { Diag(Methods[I]->getLocStart(), diag::note_also_found) - << Methods[I]->getSourceRange(); - } + << Methods[I]->getSourceRange(); + } } - return Methods[0]; } ObjCMethodDecl *Sema::LookupImplementedMethodInGlobalPool(Selector Sel) { diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index e095ee7158..d18aeab57a 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -8175,8 +8175,7 @@ static bool hasIsEqualMethod(Sema &S, const Expr *LHS, const Expr *RHS) { if (Type->isObjCIdType()) { // For 'id', just check the global pool. Method = S.LookupInstanceMethodInGlobalPool(IsEqualSel, SourceRange(), - /*receiverId=*/true, - /*warn=*/false); + /*receiverId=*/true); } else { // Check protocols. Method = S.LookupMethodInQualifiedType(IsEqualSel, Type, diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 62c1b874d5..63b7485c87 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -1043,7 +1043,7 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, SourceLocation RParenLoc, bool WarnMultipleSelectors) { ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool(Sel, - SourceRange(LParenLoc, RParenLoc), false, false); + SourceRange(LParenLoc, RParenLoc)); if (!Method) Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(LParenLoc, RParenLoc)); @@ -2393,8 +2393,11 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (ObjCMethodDecl *BestMethod = SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod())) Method = BestMethod; - if (!AreMultipleMethodsInGlobalPool(Sel, Method->isInstanceMethod())) + if (!AreMultipleMethodsInGlobalPool(Sel, Method, + SourceRange(LBracLoc, RBracLoc), + receiverIsId)) { DiagnoseUseOfDecl(Method, SelLoc); + } } } else if (ReceiverType->isObjCClassType() || ReceiverType->isObjCQualifiedClassType()) { @@ -2432,14 +2435,12 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, // If not messaging 'self', look for any factory method named 'Sel'. if (!Receiver || !isSelfExpr(Receiver)) { Method = LookupFactoryMethodInGlobalPool(Sel, - SourceRange(LBracLoc, RBracLoc), - true); + SourceRange(LBracLoc, RBracLoc)); if (!Method) { // If no class (factory) method was found, check if an _instance_ // method of the same name exists in the root class only. Method = LookupInstanceMethodInGlobalPool(Sel, - SourceRange(LBracLoc, RBracLoc), - true); + SourceRange(LBracLoc, RBracLoc)); if (Method) if (const ObjCInterfaceDecl *ID = dyn_cast(Method->getDeclContext())) { @@ -2516,6 +2517,14 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (OCIType->qual_empty()) { Method = LookupInstanceMethodInGlobalPool(Sel, SourceRange(LBracLoc, RBracLoc)); + if (Method) { + if (auto BestMethod = + SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod())) + Method = BestMethod; + AreMultipleMethodsInGlobalPool(Sel, Method, + SourceRange(LBracLoc, RBracLoc), + true); + } if (Method && !forwardClass) Diag(SelLoc, diag::warn_maynot_respond) << OCIType->getInterfaceDecl()->getIdentifier() diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp index 935128b7ec..3e465af963 100644 --- a/lib/Sema/SemaPseudoObject.cpp +++ b/lib/Sema/SemaPseudoObject.cpp @@ -1192,7 +1192,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() { AtIndexGetter = S.LookupInstanceMethodInGlobalPool(AtIndexGetterSelector, RefExpr->getSourceRange(), - true, false); + true); } if (AtIndexGetter) { @@ -1314,7 +1314,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() { AtIndexSetter = S.LookupInstanceMethodInGlobalPool(AtIndexSetterSelector, RefExpr->getSourceRange(), - true, false); + true); } bool err = false; diff --git a/test/SemaObjC/warn-strict-selector-match.m b/test/SemaObjC/warn-strict-selector-match.m index 9f22e73edc..13e9bac462 100644 --- a/test/SemaObjC/warn-strict-selector-match.m +++ b/test/SemaObjC/warn-strict-selector-match.m @@ -13,23 +13,24 @@ int main() { [(id)0 method]; } // expected-warning {{multiple methods named 'met @interface Object @end @interface Class1 -- (void)setWindow:(Object *)wdw; // expected-note {{using}} +- (void)setWindow:(Object *)wdw; // expected-note 2 {{using}} @end @interface Class2 -- (void)setWindow:(Class1 *)window; // expected-note {{also found}} +- (void)setWindow:(Class1 *)window; // expected-note 2 {{also found}} @end id foo(void) { Object *obj = 0; id obj2 = obj; - [obj setWindow:0]; // expected-warning {{Object' may not respond to 'setWindow:'}} + [obj setWindow:0]; // expected-warning {{Object' may not respond to 'setWindow:'}} \ + // expected-warning {{multiple methods named 'setWindow:' found}} [obj2 setWindow:0]; // expected-warning {{multiple methods named 'setWindow:' found}} return obj; } @protocol MyObject -- (id)initWithData:(Object *)data; // expected-note {{using}} +- (id)initWithData:(Object *)data; // expected-note {{also found}} @end @protocol SomeOther @@ -37,7 +38,7 @@ id foo(void) { @end @protocol MyCoding -- (id)initWithData:(id)data; // expected-note {{also found}} +- (id)initWithData:(id)data; // expected-note {{using}} @end @interface NTGridDataObject: Object @@ -71,3 +72,29 @@ void foo1(void) { [(Class)0 port]; // OK - gcc issues warning but there is only one Class method so no ambiguity to warn } +// rdar://19265430 +@interface NSObject +- (id)class; +- (id) alloc; +@end + +@class NSString; + +@interface A : NSObject +- (instancetype)initWithType:(NSString *)whatever; // expected-note {{also found}} +@end + +@interface Test : NSObject +@end + +@implementation Test ++ (instancetype)foo +{ + return [[[self class] alloc] initWithType:3]; // expected-warning {{multiple methods named 'initWithType:'}} +} + +- (instancetype)initWithType:(unsigned int)whatever // expected-note {{using}} +{ + return 0; +} +@end