/// 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
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
/// 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,
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);
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)) {
}
}
}
-
+
// 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.
break;
}
}
-
+
if (issueDiagnostic) {
if (issueError)
Diag(R.getBegin(), diag::err_arc_multiple_method_decl) << Sel << 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) {
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,
SourceLocation RParenLoc,
bool WarnMultipleSelectors) {
ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool(Sel,
- SourceRange(LParenLoc, RParenLoc), false, false);
+ SourceRange(LParenLoc, RParenLoc));
if (!Method)
Method = LookupFactoryMethodInGlobalPool(Sel,
SourceRange(LParenLoc, RParenLoc));
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()) {
// 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())) {
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()
AtIndexGetter =
S.LookupInstanceMethodInGlobalPool(AtIndexGetterSelector,
RefExpr->getSourceRange(),
- true, false);
+ true);
}
if (AtIndexGetter) {
AtIndexSetter =
S.LookupInstanceMethodInGlobalPool(AtIndexSetterSelector,
RefExpr->getSourceRange(),
- true, false);
+ true);
}
bool err = false;
@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
@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>
[(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