diff options
-rw-r--r-- | include/clang/Basic/DiagnosticKinds.def | 6 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 4 | ||||
-rw-r--r-- | lib/Sema/SemaDeclObjC.cpp | 15 | ||||
-rw-r--r-- | lib/Sema/SemaExprObjC.cpp | 15 | ||||
-rw-r--r-- | test/SemaObjC/method-lookup-3.m | 52 |
5 files changed, 86 insertions, 6 deletions
diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index cf4bf2a235..84aa391437 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -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, diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index dcd197dad6..49d69ad92d 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -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); //===--------------------------------------------------------------------===// diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index f98eeb6112..05c3bc78b3 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -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) { diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index db83405283..a474b7eee7 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -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)) diff --git a/test/SemaObjC/method-lookup-3.m b/test/SemaObjC/method-lookup-3.m new file mode 100644 index 0000000000..a1815fa386 --- /dev/null +++ b/test/SemaObjC/method-lookup-3.m @@ -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}} +} |