forked from OSchip/llvm-project
[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:
parent
7fa23fc78f
commit
890803f5f4
|
@ -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,
|
||||
|
|
|
@ -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,30 +2384,22 @@ 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)
|
||||
if (M->getMethod() && !M->getMethod()->isHidden())
|
||||
return M->getMethod();
|
||||
|
||||
Methods.push_back(M->getMethod());
|
||||
}
|
||||
}
|
||||
|
||||
// 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 &&
|
||||
receiverIdOrClass &&
|
||||
!Diags.isIgnored(diag::warn_strict_multiple_method_decl, R.getBegin());
|
||||
if (strictSelectorMatch) {
|
||||
for (unsigned I = 1, N = Methods.size(); I != N; ++I) {
|
||||
|
@ -2436,7 +2442,6 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
|
|||
<< Methods[I]->getSourceRange();
|
||||
}
|
||||
}
|
||||
return Methods[0];
|
||||
}
|
||||
|
||||
ObjCMethodDecl *Sema::LookupImplementedMethodInGlobalPool(Selector Sel) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,9 +2393,12 @@ 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()) {
|
||||
// Handle messages to Class.
|
||||
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue