Fix <rdar://problem/6191148> [sema] Objective-C method lookup (at global scope) fails to handle overloaded selectors properly.

Long standing bug in Sema::ActOnInstanceMessage(). We now warn when messaging an "id" with multiple method signatures in scope. The diags are a little verbose, however they can be streamlined if necessary. 

llvm-svn: 56843
This commit is contained in:
Steve Naroff 2008-09-30 14:38:43 +00:00
parent a459f12862
commit 4a82d815de
5 changed files with 86 additions and 6 deletions

View File

@ -467,6 +467,12 @@ DIAG(warn_undef_method_impl, WARNING,
"method definition for '%0' not found")
DIAG(warn_incomplete_impl, WARNING,
"incomplete implementation")
DIAG(warn_multiple_method_decl, WARNING,
"multiple methods named '%0' found")
DIAG(warn_using_decl, WARNING,
"using")
DIAG(warn_also_found_decl, WARNING,
"also found")
DIAG(error_duplicate_method_decl, ERROR,
"duplicate declaration of method '%0'")
DIAG(err_previous_declaration, ERROR,

View File

@ -379,6 +379,10 @@ private:
/// messages sent to "id" (where the class of the object is unknown).
void AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method);
/// LookupInstanceMethodInGlobalPool - Returns the method and warns if
/// there are multiple signatures.
ObjCMethodDecl *LookupInstanceMethodInGlobalPool(Selector Sel, SourceRange R);
/// AddFactoryMethodToGlobalPool - Same as above, but for factory methods.
void AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method);
//===--------------------------------------------------------------------===//

View File

@ -776,6 +776,21 @@ void Sema::AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method) {
}
}
ObjCMethodDecl *Sema::LookupInstanceMethodInGlobalPool(Selector Sel,
SourceRange R) {
ObjCMethodList &MethList = InstanceMethodPool[Sel];
if (MethList.Method && MethList.Next) {
Diag(R.getBegin(), diag::warn_multiple_method_decl, Sel.getName(), R);
Diag(MethList.Method->getLocStart(), diag::warn_using_decl,
MethList.Method->getSourceRange());
for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next)
Diag(Next->Method->getLocStart(), diag::warn_also_found_decl,
Next->Method->getSourceRange());
}
return MethList.Method;
}
void Sema::AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method) {
ObjCMethodList &FirstMethod = FactoryMethodPool[Method->getSelector()];
if (!FirstMethod.Method) {

View File

@ -283,7 +283,8 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
// Handle messages to id.
if (ReceiverCType == Context.getCanonicalType(Context.getObjCIdType()) ||
ReceiverCType->getAsBlockPointerType()) {
ObjCMethodDecl *Method = InstanceMethodPool[Sel].Method;
ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool(
Sel, SourceRange(lbrac,rbrac));
if (!Method)
Method = FactoryMethodPool[Sel].Method;
if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, "-",
@ -306,7 +307,8 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
if (!Method)
Method = FactoryMethodPool[Sel].Method;
if (!Method)
Method = InstanceMethodPool[Sel].Method;
Method = LookupInstanceMethodInGlobalPool(
Sel, SourceRange(lbrac,rbrac));
if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, "-",
lbrac, rbrac, returnType))
return true;
@ -335,9 +337,9 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
// We allow sending a message to a pointer to an interface (an object).
ClassDecl = OCIReceiver->getDecl();
// FIXME: consider using InstanceMethodPool, since it will be faster
// than the following method (which can do *many* linear searches). The
// idea is to add class info to InstanceMethodPool.
// FIXME: consider using LookupInstanceMethodInGlobalPool, since it will be
// faster than the following method (which can do *many* linear searches).
// The idea is to add class info to InstanceMethodPool.
Method = ClassDecl->lookupInstanceMethod(Sel);
if (!Method) {
@ -369,7 +371,8 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
// behavior isn't very desirable, however we need it for GCC
// compatibility.
if (!Method)
Method = InstanceMethodPool[Sel].Method;
Method = LookupInstanceMethodInGlobalPool(
Sel, SourceRange(lbrac,rbrac));
}
if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, "-",
lbrac, rbrac, returnType))

View File

@ -0,0 +1,52 @@
// RUN: clang -fsyntax-only -verify %s
typedef struct { int y; } Abstract;
typedef struct { int x; } Alternate;
#define INTERFERE_TYPE Alternate*
@protocol A
@property Abstract *x; // expected-warning{{using}}
@end
@interface B
@property Abstract *y; // expected-warning{{using}}
@end
@interface B (Category)
@property Abstract *z; // expected-warning{{using}}
@end
@interface InterferencePre
-(void) x; // expected-warning{{also found}}
-(void) y; // expected-warning{{also found}}
-(void) z; // expected-warning{{also found}}
-(void) setX: (INTERFERE_TYPE) arg; // expected-warning{{also found}}
-(void) setY: (INTERFERE_TYPE) arg; // expected-warning{{also found}}
-(void) setZ: (INTERFERE_TYPE) arg; // expected-warning{{also found}}
@end
void f0(id a0) {
Abstract *l = [a0 x]; // expected-warning {{multiple methods named 'x' found}}
}
void f1(id a0) {
Abstract *l = [a0 y]; // expected-warning {{multiple methods named 'y' found}}
}
void f2(id a0) {
Abstract *l = [a0 z]; // expected-warning {{multiple methods named 'z' found}}
}
void f3(id a0, Abstract *a1) {
[ a0 setX: a1]; // expected-warning {{multiple methods named 'setX:' found}}
}
void f4(id a0, Abstract *a1) {
[ a0 setY: a1]; // expected-warning {{multiple methods named 'setY:' found}}
}
void f5(id a0, Abstract *a1) {
[ a0 setZ: a1]; // expected-warning {{multiple methods named 'setZ:' found}}
}