summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornicola <nicola@138bc75d-0d04-0410-961f-82ee72b054a4>2011-08-06 14:20:09 +0000
committernicola <nicola@138bc75d-0d04-0410-961f-82ee72b054a4>2011-08-06 14:20:09 +0000
commit1db7b8a843e41f8e4858fbbdaac698e9f4ea371e (patch)
tree2eebcd872b6090c0533651d1c56a014d20130d9b
parent0f4721f30396b56d99ec291495dd38dc1fe40aec (diff)
downloadgcc-1db7b8a843e41f8e4858fbbdaac698e9f4ea371e.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@177510 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/testsuite/ChangeLog14
-rw-r--r--gcc/testsuite/obj-c++.dg/gnu-api-2-class-meta.mm327
-rw-r--r--gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm12
-rw-r--r--gcc/testsuite/objc.dg/gnu-api-2-class-meta.m327
-rw-r--r--gcc/testsuite/objc.dg/gnu-api-2-class.m6
-rw-r--r--libobjc/ChangeLog12
-rw-r--r--libobjc/class.c69
7 files changed, 743 insertions, 24 deletions
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index f61bdab31cf..3b004cf4f60 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 00000000000..e7c5fc20e43
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-class-meta.mm
@@ -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);
+}
diff --git a/gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm
index 6dc9dd3733c..9a7c092f3b2 100644
--- a/gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm
+++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm
@@ -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
index 00000000000..ea187b6a45a
--- /dev/null
+++ b/gcc/testsuite/objc.dg/gnu-api-2-class-meta.m
@@ -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;
+}
diff --git a/gcc/testsuite/objc.dg/gnu-api-2-class.m b/gcc/testsuite/objc.dg/gnu-api-2-class.m
index d69f8eba20f..7f9cf861c8a 100644
--- a/gcc/testsuite/objc.dg/gnu-api-2-class.m
+++ b/gcc/testsuite/objc.dg/gnu-api-2-class.m
@@ -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");
diff --git a/libobjc/ChangeLog b/libobjc/ChangeLog
index a69e59032cc..b9f87fabec9 100644
--- a/libobjc/ChangeLog
+++ b/libobjc/ChangeLog
@@ -1,5 +1,17 @@
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.
2011-08-06 Nicola Pero <nicola.pero@meta-innovation.com>
diff --git a/libobjc/class.c b/libobjc/class.c
index fa21afc461d..edc56aa9ec4 100644
--- a/libobjc/class.c
+++ b/libobjc/class.c
@@ -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