]> granicus.if.org Git - clang/commitdiff
Fix <rdar://problem/6191148> [sema] Objective-C method lookup (at global scope) fails...
authorSteve Naroff <snaroff@apple.com>
Tue, 30 Sep 2008 14:38:43 +0000 (14:38 +0000)
committerSteve Naroff <snaroff@apple.com>
Tue, 30 Sep 2008 14:38:43 +0000 (14:38 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@56843 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticKinds.def
lib/Sema/Sema.h
lib/Sema/SemaDeclObjC.cpp
lib/Sema/SemaExprObjC.cpp
test/SemaObjC/method-lookup-3.m [new file with mode: 0644]

index cf4bf2a2358bfaa7d0d16000a976970273510592..84aa391437853331306fa129c1534af14104410c 100644 (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,
index dcd197dad6feae4f4e9054c62e36d7e5708f7795..49d69ad92da1a8c87b77d2ae6d905756da9b1803 100644 (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);
   //===--------------------------------------------------------------------===//
index f98eeb611254e6ea358a0acd2b4ff5bf274e10b7..05c3bc78b31ece250c7d09182161f28e106d6e12 100644 (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) {
index db83405283652016d14f049b8b526a795821353b..a474b7eee78622501bb01b70e9c325e69ba92ed9 100644 (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))
diff --git a/test/SemaObjC/method-lookup-3.m b/test/SemaObjC/method-lookup-3.m
new file mode 100644 (file)
index 0000000..a1815fa
--- /dev/null
@@ -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}}
+}