In libobjc/: 2011-08-06 Nicola Pero <nicola.pero@meta-innovation.com>
authorNicola Pero <nicola.pero@meta-innovation.com>
Sat, 6 Aug 2011 14:20:09 +0000 (14:20 +0000)
committerNicola Pero <nicola@gcc.gnu.org>
Sat, 6 Aug 2011 14:20:09 +0000 (14:20 +0000)
In libobjc/:
2011-08-06  Nicola Pero  <nicola.pero@meta-innovation.com>

PR libobjc/50002
* class.c (__objc_update_classes_with_methods): Iterate over meta
classes as well as normal classes when refreshing the method
implementations.  This fixes replacing class methods.

2011-08-06  Nicola Pero  <nicola.pero@meta-innovation.com>

* class.c (class_getSuperclass): Fixed to work with meta classes
still in construction too.

In gcc/testsuite/:
2011-08-06  Nicola Pero  <nicola.pero@meta-innovation.com>

PR libobjc/50002
* objc.dg/gnu-api-2-class.m: Updated comments.
* obj-c++.dg/gnu-api-2-class.mm: Likewise.
* objc.dg/gnu-api-2-class-meta.m: New test.
* obj-c++.dg/gnu-api-2-class-meta.mm: Likewise.

2011-08-06  Nicola Pero  <nicola.pero@meta-innovation.com>

PR libobjc/49882
* obj-c++.dg/gnu-api-2-class.mm (main): Test class_getSuperclass()
with classes that are in construction.

From-SVN: r177510

gcc/testsuite/ChangeLog
gcc/testsuite/obj-c++.dg/gnu-api-2-class-meta.mm [new file with mode: 0644]
gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm
gcc/testsuite/objc.dg/gnu-api-2-class-meta.m [new file with mode: 0644]
gcc/testsuite/objc.dg/gnu-api-2-class.m
libobjc/ChangeLog
libobjc/class.c

index f61bdab31cfa6e0aa0e6558ff4bb3b7aee606201..3b004cf4f607618dc255c866e7ea72467d217606 100644 (file)
@@ -1,3 +1,17 @@
+2011-08-06  Nicola Pero  <nicola.pero@meta-innovation.com>
+
+       PR libobjc/50002
+       * objc.dg/gnu-api-2-class.m: Updated comments.
+       * obj-c++.dg/gnu-api-2-class.mm: Likewise.
+       * objc.dg/gnu-api-2-class-meta.m: New test.
+       * obj-c++.dg/gnu-api-2-class-meta.mm: Likewise.
+       
+2011-08-06  Nicola Pero  <nicola.pero@meta-innovation.com>
+       
+       PR libobjc/49882
+       * obj-c++.dg/gnu-api-2-class.mm (main): Test class_getSuperclass()
+       with classes that are in construction.
+       
 2011-08-06  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR target/48084
diff --git a/gcc/testsuite/obj-c++.dg/gnu-api-2-class-meta.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-class-meta.mm
new file mode 100644 (file)
index 0000000..e7c5fc2
--- /dev/null
@@ -0,0 +1,327 @@
+/* Test the Modern GNU Objective-C Runtime API.
+
+  This is test 'class-meta', covering calling functions starting with
+  'class' but using a meta class as argument.
+
+  Functions that manipulate methods (adding, replacing methods)
+  usually take a meta class argument to manipulate the class methods
+  instead of the instance ones.  This is an important part of the API
+  that needs testing.
+
+  Functions that manipulate instances, instance variables, properties
+  and protocols at the moment must take a normal class as argument;
+  calling them with a meta class as argument is of no particular use
+  and generally produces a behaviour that is undocumented and/or
+  undefined (and this is true with all runtimes).  As in the future
+  this behaviour may be defined or documented (for example, if class
+  variables are implemented as instance variables of meta classes) we
+  avoid testing it for compatibility with future runtimes.  */
+
+/* { dg-do run } */
+/* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */
+/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
+
+/* To get the modern GNU Objective-C Runtime API, you include
+   objc/runtime.h.  */
+#include <objc/runtime.h>
+#include <stdlib.h>
+#include <iostream>
+#include <cstring>
+
+@interface MyRootClass
+{ Class isa; }
++ alloc;
+- init;
++ initialize;
+@end
+
+@implementation MyRootClass
++ alloc { return class_createInstance (self, 0); }
+- init  { return self; }
++ initialize { return self; }
+@end
+
+static id static_variable = nil;
+
+@interface MySubClass : MyRootClass
++ (void) setVariable: (id)value;
++ (id) variable;
+@end
+
+@implementation MySubClass
++ (void) setVariable: (id)value { static_variable = value; }
++ (id) variable { return static_variable; }
+@end
+
+@interface DifferentClass : MyRootClass
++ (id) myClass;
+@end
+
+@implementation DifferentClass
++ (id) myClass { return self; }
+@end
+
+@interface MySubClass (MySelf)
++ (id) mySelf;
+@end
+
+int main ()
+{
+  /* Functions are tested in alphabetical order.  */
+
+  /* Calling class_addIvar() with a meta class is not documented and
+     (currently) of no use.  */
+  /* std::cout << "Testing class_addIvar ()...\n"; */
+  
+  std::cout << "Testing class_addMethod () on a meta class...\n";
+  {
+    /* Here we test adding methods to meta classes, ie, adding class methods.  */
+    Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MySubClass2", 0);
+    Method method1 = class_getInstanceMethod (objc_getMetaClass ("MySubClass"), @selector (setVariable:));
+    Method method2 = class_getInstanceMethod (objc_getMetaClass ("MySubClass"), @selector (variable));
+
+    if (new_class == Nil)
+      abort ();
+    
+    if (! class_addMethod (object_getClass (new_class), @selector (setVariable:), method_getImplementation (method1),
+                          method_getTypeEncoding (method1)))
+      abort ();
+
+    if (! class_addMethod (object_getClass (new_class), @selector (variable), method_getImplementation (method2),
+                          method_getTypeEncoding (method2)))
+      abort ();
+    
+    /* Test that if the method already exists in the class,
+       class_addMethod() returns NO.  */
+    if (class_addMethod (object_getClass (new_class), @selector (variable), method_getImplementation (method2),
+                        method_getTypeEncoding (method2)))
+      abort ();
+    
+    objc_registerClassPair (new_class);
+    
+    /* Now, MySubClass2 is basically the same as MySubClass!  We'll
+       use the +variable and +setVariable: methods on it.  */
+    {
+      Class c = objc_getClass ("MySubClass2");
+      id o = [[MyRootClass alloc] init];
+
+      [c setVariable: o];
+      
+      if ([c variable] != o)
+       abort ();
+    }
+    
+    /* Now, try that if you take an existing class and try to add an
+       already existing method, class_addMethod returns NO.  This is
+       subtly different from before, when 'new_class' was still in
+       construction.  Now it's a real class and the libobjc internals
+       differ between the two cases.  */
+    if (class_addMethod (object_getClass (new_class), @selector (variable), method_getImplementation (method2),
+                        method_getTypeEncoding (method2)))
+      abort ();
+  }
+
+  /* Calling class_addProtocol() on a meta class is not documented and
+     (currently) of no use.  */
+  /* std::cout << "Testing class_addProtocol () on a meta class...\n"; */
+
+  /* Calling class_conformsToProtocol() on a meta class is not
+     documented and (currently) of no use.  */
+  /* std::cout << "Testing class_conformsToProtocol () on a meta class...\n"; */
+  
+  /* Calling class_copyIvarList() on a meta class is not documented
+     and (currently) of no use.  */
+  /* std::cout << "Testing class_copyIvarList () on a meta class...\n"; */
+
+  std::cout << "Testing class_copyMethodList () on a meta class...\n";
+  {
+    /* Test that you can copy the method list of a meta class.  They
+       are the class methods of the class.  */
+    unsigned int count;
+    Method * list = class_copyMethodList (objc_getMetaClass ("MySubClass"), &count);
+
+    if (count != 2)
+      abort ();
+    
+    if (! ((std::strcmp (sel_getName (method_getName (list[0])), "variable") == 0
+           && std::strcmp (sel_getName (method_getName (list[1])), "setVariable:") == 0)
+          || (std::strcmp (sel_getName (method_getName (list[0])), "setVariable:") == 0
+              && std::strcmp (sel_getName (method_getName (list[1])), "variable") == 0)))
+      abort ();
+    
+    if (list[2] != NULL)
+      abort ();
+  }
+
+  /* Calling class_copyPropertyList() on a meta class is not
+     documented and (currently) of no use.  */
+  /* std::cout << "Testing class_copyPropertyList () on a meta class...\n"; */
+
+  /* Calling class_copyProtocolList() on a meta class is not
+     documented and (currently) of no use.  */
+  /* std::cout << "Testing class_copyProtocolList () on a meta class...\n"; */
+
+  /* Calling class_createInstance() on a meta class is not documented
+     and (currently) of no use.  */
+  /* std::cout << "Testing class_createInstance () on a meta class...\n"; */
+
+  /* Calling class_getClassMethod () on a meta class is not documented
+     and (currently) of no use.  */
+  /* std::cout << "Testing class_getClassMethod () on a meta class...\n"; */
+
+  /* Calling class_getClassVariable () on a meta class is not
+     documented and (currently) of no use.  */
+  /* std::cout << "Testing class_getClassVariable () on a meta class ...\n"; */
+
+  std::cout << "Testing class_getInstanceMethod () on a meta class...\n";
+  {
+    /* The instance method of a meta class is the class method with
+       the same name of the class. */
+    Method method_1 = class_getInstanceMethod (objc_getMetaClass ("MySubClass"),
+                                              @selector(variable));
+    Method method_2 = class_getClassMethod (objc_getClass ("MySubClass"),
+                                           @selector(variable));
+    
+    if (method_1 == NULL || method_2 == NULL)
+      abort ();
+
+    if (method_1 != method_2)
+      abort ();
+
+    if (std::strcmp (sel_getName (method_getName (method_1)), "variable") != 0)
+      abort ();
+  }
+
+  /* Calling class_getInstanceSize() with a meta class is not
+     documented and (currently) of no use.  */
+  /* std::cout << "Testing class_getInstanceSize () on a meta class...\n"; */
+
+  /* Calling class_getInstanceVariable() with a meta class is not
+     documented and (currently) of no use.  */
+  /* std::cout << "Testing class_getInstanceVariable () on a meta class...\n"; */
+
+  /* Calling class_getIvarLayout() with a meta class is not documented
+     and (currently) of no use.  */
+  /* std::cout << "Testing class_getIvarLayout () on a meta class...\n"; */
+
+  std::cout << "Testing class_getMethodImplementation () on a meta class...\n";
+  {
+    /* Getting the method implementation with a meta class returns a
+       class method.  */
+    MySubClass *object = [[MySubClass alloc] init];
+    IMP imp = class_getMethodImplementation (objc_getMetaClass ("MySubClass"), 
+                                            @selector(variable));
+
+    if (imp == NULL)
+      abort ();
+
+    [MySubClass setVariable: object];
+
+    if ((*imp)(objc_getClass ("MySubClass"), @selector(variable)) != object)
+      abort ();
+  }
+
+  /* This function does not exist with the GNU runtime.  */
+  /* std::cout << "Testing class_getMethodImplementation_stret () on a meta class...\n"; */
+
+  std::cout << "Testing class_getName () on a meta class...\n";
+  {
+    /* Traditionally, a meta class has the same name as the class.  */
+    if (std::strcmp (class_getName (objc_getMetaClass ("MyRootClass")),
+                    "MyRootClass") != 0)
+      abort ();
+  }
+
+  /* Calling class_getProperty() with a meta class is not documented
+     and (currently) of no use.  */
+  /* std::cout << "Testing class_getProperty ()...\n"; */
+
+  std::cout << "Testing class_getSuperclass () on a meta class...\n";
+  {
+    /* The superclass of a meta class is the meta class of the superclass.  */
+    if (class_getSuperclass (objc_getMetaClass ("MySubClass")) != objc_getMetaClass ("MyRootClass"))
+      abort ();
+
+    /* Test that it works on a newly created, but not registered, class.  */
+    {
+      Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MySubClass3", 0);
+
+      if (class_getSuperclass (object_getClass (new_class)) != object_getClass (objc_getClass ("MyRootClass")))
+       abort ();
+    }
+  }
+
+  /* Calling class_getVersion() with a meta class is not documented
+     and (currently) of no use.  */
+  /* std::cout << "Testing class_getVersion ()...\n"; */
+
+  /* Calling class_getWeakIvarLayout() with a meta class is not
+     documented and (currently) of no use.  */
+  /* std::cout << "Testing class_getWeakIvarLayout () on a meta class...\n"; */
+
+  /* class_isMetaClass() is already tested in gnu-api-2-class.m  */
+  /* std::cout << "Testing class_isMetaClass ()...\n"; */
+
+  std::cout << "Testing class_replaceMethod () on a meta class...\n";
+  {
+    /* We are going to replace the [MySubclass +variable] method with
+       the [DifferentClass +myClass] one.  */
+    Method new_method = class_getClassMethod (objc_getClass ("DifferentClass"),
+                                             @selector (myClass));
+    Method old_method = class_getClassMethod (objc_getClass ("MySubClass"),
+                                             @selector (variable));
+    const char *new_types = method_getTypeEncoding (new_method);
+    IMP new_imp = method_getImplementation (new_method);
+    const char *old_types = method_getTypeEncoding (old_method);
+    IMP old_imp = class_replaceMethod (objc_getMetaClass ("MySubClass"), @selector (variable),
+                                      method_getImplementation (new_method),
+                                      method_getTypeEncoding (new_method));
+    id o = [[MyRootClass alloc] init];
+
+    [MySubClass setVariable: o];
+
+    /* Try the new method implementation.  */
+    if ([MySubClass variable] != objc_getClass ("MySubClass"))
+      abort ();
+
+    /* Put the original method back.  */
+    class_replaceMethod (objc_getMetaClass ("MySubClass"), @selector (variable),
+                        old_imp, old_types);
+
+    /* Test it's back to what it was.  */
+    if ([MySubClass variable] != o)
+      abort ();
+
+    {
+      /* Finally, try adding a new method.  */
+      class_replaceMethod (objc_getMetaClass ("DifferentClass"), @selector (mySelf),
+                          new_imp, new_types);
+      
+      if ([(Class)objc_getClass ("DifferentClass") mySelf] != objc_getClass ("DifferentClass"))
+       abort ();
+    }
+  }
+
+  std::cout << "Testing class_respondsToSelector () on a meta class...\n";
+  {
+    /* A meta class responds to a selector if and only if the class
+       responds to the corresponding class method.  */
+    if (! class_respondsToSelector (objc_getMetaClass ("MySubClass"), @selector(setVariable:)))
+      abort ();
+
+    if (class_respondsToSelector (objc_getMetaClass ("MyRootClass"), @selector(setVariable:)))
+      abort ();
+  }
+
+  /* This is not really implemented with the GNU runtime.  */
+  /* std::cout << "Testing class_setIvarLayout () on a meta class...\n"; */
+
+  /* Calling class_setVersion() with a meta class is not documented
+     and (currently) of no use.  */
+  /* std::cout << "Testing class_setVersion () on a meta class...\n"; */
+
+  /* This is not really implemented with the GNU runtime.  */
+  /* std::cout << "Testing class_setWeakIvarLayout () on a meta class...\n"; */
+
+return (0);
+}
index 6dc9dd3733c12bd811ab2a546c96b7b8db76db7e..9a7c092f3b27580e8b40b009d40b40c0fd3d6b85 100644 (file)
@@ -1,6 +1,8 @@
 /* Test the Modern GNU Objective-C Runtime API.
 
-  This is test 'class', covering all functions starting with 'class'.  */
+  This is test 'class', covering all functions starting with 'class'.
+  Tests calling the functions with a meta class as argument are covered
+  in the separate file, gnu-api-2-class-meta.mm.  */
 
 /* { dg-do run } */
 /* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */
@@ -394,6 +396,14 @@ int main ()
     MySubClass *object = [[MySubClass alloc] init];
     if (class_getSuperclass (object_getClass (object)) != objc_getClass ("MyRootClass"))
       abort ();
+
+    /* Test that it works on a newly created, but not registered, class.  */
+    {
+      Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MySubClass3", 0);
+
+      if (class_getSuperclass (new_class) != objc_getClass ("MyRootClass"))
+       abort ();
+    }
   }
 
   std::cout << "Testing class_getVersion ()...\n";
diff --git a/gcc/testsuite/objc.dg/gnu-api-2-class-meta.m b/gcc/testsuite/objc.dg/gnu-api-2-class-meta.m
new file mode 100644 (file)
index 0000000..ea187b6
--- /dev/null
@@ -0,0 +1,327 @@
+/* Test the Modern GNU Objective-C Runtime API.
+
+  This is test 'class-meta', covering calling functions starting with
+  'class' but using a meta class as argument.
+
+  Functions that manipulate methods (adding, replacing methods)
+  usually take a meta class argument to manipulate the class methods
+  instead of the instance ones.  This is an important part of the API
+  that needs testing.
+
+  Functions that manipulate instances, instance variables, properties
+  and protocols at the moment must take a normal class as argument;
+  calling them with a meta class as argument is of no particular use
+  and generally produces a behaviour that is undocumented and/or
+  undefined (and this is true with all runtimes).  As in the future
+  this behaviour may be defined or documented (for example, if class
+  variables are implemented as instance variables of meta classes) we
+  avoid testing it for compatibility with future runtimes.  */
+
+/* { dg-do run } */
+/* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */
+/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
+
+/* To get the modern GNU Objective-C Runtime API, you include
+   objc/runtime.h.  */
+#include <objc/runtime.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+@interface MyRootClass
+{ Class isa; }
++ alloc;
+- init;
++ initialize;
+@end
+
+@implementation MyRootClass
++ alloc { return class_createInstance (self, 0); }
+- init  { return self; }
++ initialize { return self; }
+@end
+
+static id static_variable = nil;
+
+@interface MySubClass : MyRootClass
++ (void) setVariable: (id)value;
++ (id) variable;
+@end
+
+@implementation MySubClass
++ (void) setVariable: (id)value { static_variable = value; }
++ (id) variable { return static_variable; }
+@end
+
+@interface DifferentClass : MyRootClass
++ (id) myClass;
+@end
+
+@implementation DifferentClass
++ (id) myClass { return self; }
+@end
+
+@interface MySubClass (MySelf)
++ (id) mySelf;
+@end
+
+int main(int argc, void **args)
+{
+  /* Functions are tested in alphabetical order.  */
+
+  /* Calling class_addIvar() with a meta class is not documented and
+     (currently) of no use.  */
+  /* printf ("Testing class_addIvar ()...\n"); */
+  
+  printf ("Testing class_addMethod () on a meta class...\n");
+  {
+    /* Here we test adding methods to meta classes, ie, adding class methods.  */
+    Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MySubClass2", 0);
+    Method method1 = class_getInstanceMethod (objc_getMetaClass ("MySubClass"), @selector (setVariable:));
+    Method method2 = class_getInstanceMethod (objc_getMetaClass ("MySubClass"), @selector (variable));
+
+    if (new_class == Nil)
+      abort ();
+    
+    if (! class_addMethod (object_getClass (new_class), @selector (setVariable:), method_getImplementation (method1),
+                          method_getTypeEncoding (method1)))
+      abort ();
+
+    if (! class_addMethod (object_getClass (new_class), @selector (variable), method_getImplementation (method2),
+                          method_getTypeEncoding (method2)))
+      abort ();
+    
+    /* Test that if the method already exists in the class,
+       class_addMethod() returns NO.  */
+    if (class_addMethod (object_getClass (new_class), @selector (variable), method_getImplementation (method2),
+                        method_getTypeEncoding (method2)))
+      abort ();
+    
+    objc_registerClassPair (new_class);
+    
+    /* Now, MySubClass2 is basically the same as MySubClass!  We'll
+       use the +variable and +setVariable: methods on it.  */
+    {
+      Class c = objc_getClass ("MySubClass2");
+      id o = [[MyRootClass alloc] init];
+
+      [c setVariable: o];
+      
+      if ([c variable] != o)
+       abort ();
+    }
+    
+    /* Now, try that if you take an existing class and try to add an
+       already existing method, class_addMethod returns NO.  This is
+       subtly different from before, when 'new_class' was still in
+       construction.  Now it's a real class and the libobjc internals
+       differ between the two cases.  */
+    if (class_addMethod (object_getClass (new_class), @selector (variable), method_getImplementation (method2),
+                        method_getTypeEncoding (method2)))
+      abort ();
+  }
+
+  /* Calling class_addProtocol() on a meta class is not documented and
+     (currently) of no use.  */
+  /* printf ("Testing class_addProtocol () on a meta class...\n"); */
+
+  /* Calling class_conformsToProtocol() on a meta class is not
+     documented and (currently) of no use.  */
+  /* printf ("Testing class_conformsToProtocol () on a meta class...\n"); */
+  
+  /* Calling class_copyIvarList() on a meta class is not documented
+     and (currently) of no use.  */
+  /* printf ("Testing class_copyIvarList () on a meta class...\n"); */
+
+  printf ("Testing class_copyMethodList () on a meta class...\n");
+  {
+    /* Test that you can copy the method list of a meta class.  They
+       are the class methods of the class.  */
+    unsigned int count;
+    Method * list = class_copyMethodList (objc_getMetaClass ("MySubClass"), &count);
+
+    if (count != 2)
+      abort ();
+    
+    if (! ((strcmp (sel_getName (method_getName (list[0])), "variable") == 0
+           && strcmp (sel_getName (method_getName (list[1])), "setVariable:") == 0)
+          || (strcmp (sel_getName (method_getName (list[0])), "setVariable:") == 0
+              && strcmp (sel_getName (method_getName (list[1])), "variable") == 0)))
+      abort ();
+    
+    if (list[2] != NULL)
+      abort ();
+  }
+
+  /* Calling class_copyPropertyList() on a meta class is not
+     documented and (currently) of no use.  */
+  /* printf ("Testing class_copyPropertyList () on a meta class...\n"); */
+
+  /* Calling class_copyProtocolList() on a meta class is not
+     documented and (currently) of no use.  */
+  /* printf ("Testing class_copyProtocolList () on a meta class...\n"); */
+
+  /* Calling class_createInstance() on a meta class is not documented
+     and (currently) of no use.  */
+  /* printf ("Testing class_createInstance () on a meta class...\n"); */
+
+  /* Calling class_getClassMethod () on a meta class is not documented
+     and (currently) of no use.  */
+  /* printf ("Testing class_getClassMethod () on a meta class...\n"); */
+
+  /* Calling class_getClassVariable () on a meta class is not
+     documented and (currently) of no use.  */
+  /* printf ("Testing class_getClassVariable () on a meta class ...\n"); */
+
+  printf ("Testing class_getInstanceMethod () on a meta class...\n");
+  {
+    /* The instance method of a meta class is the class method with
+       the same name of the class. */
+    Method method_1 = class_getInstanceMethod (objc_getMetaClass ("MySubClass"),
+                                              @selector(variable));
+    Method method_2 = class_getClassMethod (objc_getClass ("MySubClass"),
+                                           @selector(variable));
+    
+    if (method_1 == NULL || method_2 == NULL)
+      abort ();
+
+    if (method_1 != method_2)
+      abort ();
+
+    if (strcmp (sel_getName (method_getName (method_1)), "variable") != 0)
+      abort ();
+  }
+
+  /* Calling class_getInstanceSize() with a meta class is not
+     documented and (currently) of no use.  */
+  /* printf ("Testing class_getInstanceSize () on a meta class...\n"); */
+
+  /* Calling class_getInstanceVariable() with a meta class is not
+     documented and (currently) of no use.  */
+  /* printf ("Testing class_getInstanceVariable () on a meta class...\n"); */
+
+  /* Calling class_getIvarLayout() with a meta class is not documented
+     and (currently) of no use.  */
+  /* printf ("Testing class_getIvarLayout () on a meta class...\n"); */
+
+  printf ("Testing class_getMethodImplementation () on a meta class...\n");
+  {
+    /* Getting the method implementation with a meta class returns a
+       class method.  */
+    MySubClass *object = [[MySubClass alloc] init];
+    IMP imp = class_getMethodImplementation (objc_getMetaClass ("MySubClass"), 
+                                            @selector(variable));
+
+    if (imp == NULL)
+      abort ();
+
+    [MySubClass setVariable: object];
+
+    if ((*imp)(objc_getClass ("MySubClass"), @selector(variable)) != object)
+      abort ();
+  }
+
+  /* This function does not exist with the GNU runtime.  */
+  /* printf ("Testing class_getMethodImplementation_stret () on a meta class...\n"); */
+
+  printf ("Testing class_getName () on a meta class...\n");
+  {
+    /* Traditionally, a meta class has the same name as the class.  */
+    if (strcmp (class_getName (objc_getMetaClass ("MyRootClass")),
+               "MyRootClass") != 0)
+      abort ();
+  }
+
+  /* Calling class_getProperty() with a meta class is not documented
+     and (currently) of no use.  */
+  /* printf ("Testing class_getProperty ()...\n"); */
+
+  printf ("Testing class_getSuperclass () on a meta class...\n");
+  {
+    /* The superclass of a meta class is the meta class of the superclass.  */
+    if (class_getSuperclass (objc_getMetaClass ("MySubClass")) != objc_getMetaClass ("MyRootClass"))
+      abort ();
+
+    /* Test that it works on a newly created, but not registered, class.  */
+    {
+      Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MySubClass3", 0);
+
+      if (class_getSuperclass (object_getClass (new_class)) != object_getClass (objc_getClass ("MyRootClass")))
+       abort ();
+    }
+  }
+
+  /* Calling class_getVersion() with a meta class is not documented
+     and (currently) of no use.  */
+  /* printf ("Testing class_getVersion ()...\n"); */
+
+  /* Calling class_getWeakIvarLayout() with a meta class is not
+     documented and (currently) of no use.  */
+  /* printf ("Testing class_getWeakIvarLayout () on a meta class...\n"); */
+
+  /* class_isMetaClass() is already tested in gnu-api-2-class.m  */
+  /* printf ("Testing class_isMetaClass ()...\n"); */
+
+  printf ("Testing class_replaceMethod () on a meta class...\n");
+  {
+    /* We are going to replace the [MySubclass +variable] method with
+       the [DifferentClass +myClass] one.  */
+    Method new_method = class_getClassMethod (objc_getClass ("DifferentClass"),
+                                             @selector (myClass));
+    Method old_method = class_getClassMethod (objc_getClass ("MySubClass"),
+                                             @selector (variable));
+    const char *new_types = method_getTypeEncoding (new_method);
+    IMP new_imp = method_getImplementation (new_method);
+    const char *old_types = method_getTypeEncoding (old_method);
+    IMP old_imp = class_replaceMethod (objc_getMetaClass ("MySubClass"), @selector (variable),
+                                      method_getImplementation (new_method),
+                                      method_getTypeEncoding (new_method));
+    id o = [[MyRootClass alloc] init];
+
+    [MySubClass setVariable: o];
+
+    /* Try the new method implementation.  */
+    if ([MySubClass variable] != objc_getClass ("MySubClass"))
+      abort ();
+
+    /* Put the original method back.  */
+    class_replaceMethod (objc_getMetaClass ("MySubClass"), @selector (variable),
+                        old_imp, old_types);
+
+    /* Test it's back to what it was.  */
+    if ([MySubClass variable] != o)
+      abort ();
+
+    {
+      /* Finally, try adding a new method.  */
+      class_replaceMethod (objc_getMetaClass ("DifferentClass"), @selector (mySelf),
+                          new_imp, new_types);
+      
+      if ([(Class)objc_getClass ("DifferentClass") mySelf] != objc_getClass ("DifferentClass"))
+       abort ();
+    }
+  }
+
+  printf ("Testing class_respondsToSelector () on a meta class...\n");
+  {
+    /* A meta class responds to a selector if and only if the class
+       responds to the corresponding class method.  */
+    if (! class_respondsToSelector (objc_getMetaClass ("MySubClass"), @selector(setVariable:)))
+      abort ();
+
+    if (class_respondsToSelector (objc_getMetaClass ("MyRootClass"), @selector(setVariable:)))
+      abort ();
+  }
+
+  /* This is not really implemented with the GNU runtime.  */
+  /* printf ("Testing class_setIvarLayout () on a meta class...\n"); */
+
+  /* Calling class_setVersion() with a meta class is not documented
+     and (currently) of no use.  */
+  /* printf ("Testing class_setVersion () on a meta class...\n"); */
+
+  /* This is not really implemented with the GNU runtime.  */
+  /* printf ("Testing class_setWeakIvarLayout () on a meta class...\n"); */
+
+  return 0;
+}
index d69f8eba20f82538302e79a7a2c1c1c6c0ab1c80..7f9cf861c8abd563e8c491d4531ce615bba4e8d4 100644 (file)
@@ -1,6 +1,8 @@
 /* Test the Modern GNU Objective-C Runtime API.
 
-  This is test 'class', covering all functions starting with 'class'.  */
+  This is test 'class', covering all functions starting with 'class'.
+  Tests calling the functions with a meta class as argument are covered
+  in the separate file, gnu-api-2-class-meta.m.  */
 
 /* { dg-do run } */
 /* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */
@@ -401,7 +403,7 @@ int main(int argc, void **args)
 
       if (class_getSuperclass (new_class) != objc_getClass ("MyRootClass"))
        abort ();
-    }    
+    }
   }
 
   printf ("Testing class_getVersion ()...\n");
index a69e59032cc955049912197eb8627cb78b5ecef6..b9f87fabec9ff4d2da24a80b48b37db17ea4492c 100644 (file)
@@ -1,3 +1,15 @@
+2011-08-06  Nicola Pero  <nicola.pero@meta-innovation.com>
+
+       PR libobjc/50002
+       * class.c (__objc_update_classes_with_methods): Iterate over meta
+       classes as well as normal classes when refreshing the method
+       implementations.  This fixes replacing class methods.
+
+2011-08-06  Nicola Pero  <nicola.pero@meta-innovation.com>
+
+       * class.c (class_getSuperclass): Fixed to work with meta classes
+       still in construction too.
+
 2011-08-06  Nicola Pero  <nicola.pero@meta-innovation.com>
 
        * class.c (class_getSuperclass): Fixed typo in comment.
index fa21afc461d7803d2a3c9de5f7edf45682046b28..edc56aa9ec4d2679e7b8f8e53f6b67bd7785e797 100644 (file)
@@ -781,35 +781,57 @@ __objc_update_classes_with_methods (struct objc_method *method_a, struct objc_me
       
       while (node != NULL)
        {
-         /* Iterate over all methods in the class.  */
-         Class class = node->pointer;
-         struct objc_method_list * method_list = class->methods;
-
-         while (method_list)
+         /* We execute this loop twice: the first time, we iterate
+            over all methods in the class (instance methods), while
+            the second time we iterate over all methods in the meta
+            class (class methods).  */
+         Class class = Nil;
+         BOOL done = NO;
+
+         while (done == NO)
            {
-             int i;
+             struct objc_method_list * method_list;
 
-             for (i = 0; i < method_list->method_count; ++i)
+             if (class == Nil)
+               {
+                 /* The first time, we work on the class.  */
+                 class = node->pointer;
+               }
+             else
                {
-                 struct objc_method *method = &method_list->method_list[i];
+                 /* The second time, we work on the meta class.  */
+                 class = class->class_pointer;
+                 done = YES;
+               }
 
-                 /* If the method is one of the ones we are looking
-                    for, update the implementation.  */
-                 if (method == method_a)
-                   sarray_at_put_safe (class->dtable,
-                                       (sidx) method_a->method_name->sel_id,
-                                       method_a->method_imp);
+             method_list = class->methods;
 
-                 if (method == method_b)
+             while (method_list)
+               {
+                 int i;
+                 
+                 for (i = 0; i < method_list->method_count; ++i)
                    {
-                     if (method_b != NULL)
+                     struct objc_method *method = &method_list->method_list[i];
+                     
+                     /* If the method is one of the ones we are
+                        looking for, update the implementation.  */
+                     if (method == method_a)
                        sarray_at_put_safe (class->dtable,
-                                           (sidx) method_b->method_name->sel_id,
-                                           method_b->method_imp);
+                                           (sidx) method_a->method_name->sel_id,
+                                           method_a->method_imp);
+                     
+                     if (method == method_b)
+                       {
+                         if (method_b != NULL)
+                           sarray_at_put_safe (class->dtable,
+                                               (sidx) method_b->method_name->sel_id,
+                                               method_b->method_imp);
+                       }
                    }
+                 
+                 method_list = method_list->method_next;
                }
-         
-             method_list = method_list->method_next;
            }
          node = node->next;
        }
@@ -929,7 +951,12 @@ class_getSuperclass (Class class_)
      superclass name to return the superclass.  We can not resolve the
      class until it is registered.  */
   if (CLS_IS_IN_CONSTRUCTION (class_))
-    return objc_lookUpClass ((const char *)(class_->super_class));
+    {
+      if (CLS_ISMETA (class_))
+       return object_getClass ((id)objc_lookUpClass ((const char *)(class_->super_class)));
+      else
+       return objc_lookUpClass ((const char *)(class_->super_class));
+    }
 
   /* If the class is not resolved yet, super_class would point to a
      string (the name of the super class) as opposed to the actual