]> granicus.if.org Git - clang/commitdiff
Fix a corner case of message lookup looking for class methods.
authorFariborz Jahanian <fjahanian@apple.com>
Wed, 4 Mar 2009 17:50:39 +0000 (17:50 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Wed, 4 Mar 2009 17:50:39 +0000 (17:50 +0000)
If all else failed, find the message in class's root's
list of instacne methods!

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

lib/Sema/SemaExprObjC.cpp
test/SemaObjC/call-super-2.m
test/SemaObjC/class-method-lookup.m [new file with mode: 0644]

index 8705baffcb6eec3c9ccd99d509578eb72b3c9dc4..80120a7b7a4ac7f69770d3c712ad11e6c589ffa7 100644 (file)
@@ -314,8 +314,14 @@ Sema::ExprResult Sema::ActOnClassMessage(
     Method = LookupPrivateMethod(Sel, ClassDecl);
 
   // Before we give up, check if the selector is an instance method.
-  if (!Method)
-    Method = ClassDecl->lookupInstanceMethod(Sel);
+  // But only in the root. This matches gcc's behaviour and what the
+  // runtime expects.
+  if (!Method) {
+    ObjCInterfaceDecl *Root = ClassDecl;
+    while (Root->getSuperClass())
+      Root = Root->getSuperClass(); 
+    Method = Root->lookupInstanceMethod(Sel);
+  }
 
   if (Method && DiagnoseUseOfDecl(Method, receiverLoc))
     return true;
@@ -400,6 +406,15 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
         
         if (!Method)
           Method = LookupPrivateMethod(Sel, ClassDecl);
+        // Before we give up, check if the selector is an instance method.
+        // But only in the root. This matches gcc's behaviour and what the
+        // runtime expects.
+        if (!Method) {
+          ObjCInterfaceDecl *Root = ClassDecl;
+          while (Root->getSuperClass())
+            Root = Root->getSuperClass();
+          Method = Root->lookupInstanceMethod(Sel);
+        }
       }
       if (Method && DiagnoseUseOfDecl(Method, receiverLoc))
         return true;
@@ -408,9 +423,12 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
       // If not messaging 'self', look for any factory method named 'Sel'.
       if (!isSelfExpr(RExpr)) {
         Method = FactoryMethodPool[Sel].Method;
-        if (!Method)
+        if (!Method) {
           Method = LookupInstanceMethodInGlobalPool(
                                    Sel, SourceRange(lbrac,rbrac));
+          if (Method)
+            Diag(receiverLoc, diag::warn_maynot_respond) << Sel;
+        }
       }
     }
     if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false,
index 98e4e088576ba22863a6ef01f263fbcb7d14d0a8..a1f8c8722e1f1b79fface912c5ac856fbcbf3711 100644 (file)
@@ -83,7 +83,7 @@ id objc_getClass(const char *s);
 }   
 - (int) instance_func5
 {
-   int i = (size_t)[Derived instance_func1]; // GCC currently warns.
+   int i = (size_t)[Derived instance_func1]; // expected-warning {{method '+instance_func1' not found (return type defaults to 'id')}} 
    return i + (size_t)[Object instance_func1]; // expected-warning {{method '+instance_func1' not found (return type defaults to 'id')}}
 }
 - (int) instance_func6
diff --git a/test/SemaObjC/class-method-lookup.m b/test/SemaObjC/class-method-lookup.m
new file mode 100644 (file)
index 0000000..a62f0f0
--- /dev/null
@@ -0,0 +1,46 @@
+// RUN: clang -fsyntax-only -verify %s
+
+@interface MyBase 
+- (void) rootInstanceMethod;
+@end
+
+@interface MyIntermediate: MyBase
+@end
+
+@interface MyDerived: MyIntermediate
+- (void) instanceMethod;
++ (void) classMethod;
+@end
+
+@implementation MyDerived
+- (void) instanceMethod {
+}
+
++ (void) classMethod {                    /* If a class method is not found, the root  */
+    [self rootInstanceMethod];            /* class is searched for an instance method  */
+    [MyIntermediate rootInstanceMethod];  /* with the same name.                       */
+
+    [self instanceMethod];// expected-warning {{'-instanceMethod' not found (return type defaults to 'id')}}
+    [MyDerived instanceMethod];// expected-warning {{'+instanceMethod' not found (return type defaults to 'id')}}
+}
+@end
+
+@interface Object @end
+
+@interface Class1
+- (void)setWindow:(Object *)wdw;
+@end
+
+@interface Class2
+- (void)setWindow:(Class1 *)window;
+@end
+
+#define nil (void*)0
+
+id foo(void) {
+  Object *obj;
+  id obj2 = obj;
+  [obj setWindow:nil]; // expected-warning {{Object  may not respond to 'setWindow:'}}
+
+  return obj;
+}