forked from OSchip/llvm-project
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:
parent
a459f12862
commit
4a82d815de
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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}}
|
||||
}
|
Loading…
Reference in New Issue