[Objective-C Sema]This patch fixes the warning when clang issues

"multiple methods named '<selector>' 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

llvm-svn: 235023
This commit is contained in:
Fariborz Jahanian 2015-04-15 17:26:21 +00:00
parent 7fa23fc78f
commit 890803f5f4
6 changed files with 95 additions and 52 deletions

View File

@ -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<ObjCMethodDecl*>& Methods,
bool instance);
bool AreMultipleMethodsInGlobalPool(Selector Sel,
bool instance);
bool AreMultipleMethodsInGlobalPool(Selector Sel, ObjCMethodDecl *BestMethod,
SourceRange R,
bool receiverIdOrClass);
void DiagnoseMultipleMethodInGlobalPool(SmallVectorImpl<ObjCMethodDecl*> &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,

View File

@ -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<ObjCMethodDecl *, 4> 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<ObjCMethodDecl *, 4> 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<ObjCMethodDecl*> &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) {

View File

@ -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,

View File

@ -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<ObjCInterfaceDecl>(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()

View File

@ -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;

View File

@ -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<MyObject, MyCoding>)data; // expected-note {{also found}}
- (id)initWithData:(id<MyObject, MyCoding>)data; // expected-note {{using}}
@end
@interface NTGridDataObject: Object <MyCoding>
@ -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