testsuite: Allow matching `{_1, { 0,0,0,0 }}` for vect/slp-gap-1.c
[official-gcc.git] / gcc / testsuite / obj-c++.dg / gnu-api-2-class-meta.mm
blob92852c3ecea0eaea4951cb9c224db549e81c3e66
1 /* Test the Modern GNU Objective-C Runtime API.
3   This is test 'class-meta', covering calling functions starting with
4   'class' but using a meta class as argument.
6   Functions that manipulate methods (adding, replacing methods)
7   usually take a meta class argument to manipulate the class methods
8   instead of the instance ones.  This is an important part of the API
9   that needs testing.
11   Functions that manipulate instances, instance variables, properties
12   and protocols at the moment must take a normal class as argument;
13   calling them with a meta class as argument is of no particular use
14   and generally produces a behavior that is undocumented and/or
15   undefined (and this is true with all runtimes).  As in the future
16   this behavior may be defined or documented (for example, if class
17   variables are implemented as instance variables of meta classes) we
18   avoid testing it for compatibility with future runtimes.  */
20 /* { dg-do run } */
21 /* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */
22 /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
23 /* { dg-additional-options "-DOBJC_OLD_DISPATCH_PROTOTYPES" { target { *-*-darwin* } } } */
24 // { dg-additional-options "-Wno-objc-root-class" }
26 /* To get the modern GNU Objective-C Runtime API, you include
27    objc/runtime.h.  */
28 #include <objc/runtime.h>
29 #include <stdlib.h>
30 #include <iostream>
31 #include <cstring>
33 @interface MyRootClass
34 { Class isa; }
35 + alloc;
36 - init;
37 + initialize;
38 @end
40 @implementation MyRootClass
41 + alloc { return class_createInstance (self, 0); }
42 - init  { return self; }
43 + initialize { return self; }
44 @end
46 static id static_variable = nil;
48 @interface MySubClass : MyRootClass
49 + (void) setVariable: (id)value;
50 + (id) variable;
51 @end
53 @implementation MySubClass
54 + (void) setVariable: (id)value { static_variable = value; }
55 + (id) variable { return static_variable; }
56 @end
58 @interface DifferentClass : MyRootClass
59 + (id) myClass;
60 @end
62 @implementation DifferentClass
63 + (id) myClass { return self; }
64 @end
66 @interface MySubClass (MySelf)
67 + (id) mySelf;
68 @end
70 int main ()
72   /* Functions are tested in alphabetical order.  */
74   /* Calling class_addIvar() with a meta class is not documented and
75      (currently) of no use.  */
76   /* std::cout << "Testing class_addIvar ()...\n"; */
77   
78   std::cout << "Testing class_addMethod () on a meta class...\n";
79   {
80     /* Here we test adding methods to meta classes, ie, adding class methods.  */
81     Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MySubClass2", 0);
82     Method method1 = class_getInstanceMethod (objc_getMetaClass ("MySubClass"), @selector (setVariable:));
83     Method method2 = class_getInstanceMethod (objc_getMetaClass ("MySubClass"), @selector (variable));
85     if (new_class == Nil)
86       abort ();
87     
88     if (! class_addMethod (object_getClass (new_class), @selector (setVariable:), method_getImplementation (method1),
89                            method_getTypeEncoding (method1)))
90       abort ();
92     if (! class_addMethod (object_getClass (new_class), @selector (variable), method_getImplementation (method2),
93                            method_getTypeEncoding (method2)))
94       abort ();
95     
96     /* Test that if the method already exists in the class,
97        class_addMethod() returns NO.  */
98     if (class_addMethod (object_getClass (new_class), @selector (variable), method_getImplementation (method2),
99                          method_getTypeEncoding (method2)))
100       abort ();
101     
102     objc_registerClassPair (new_class);
103     
104     /* Now, MySubClass2 is basically the same as MySubClass!  We'll
105        use the +variable and +setVariable: methods on it.  */
106     {
107       Class c = objc_getClass ("MySubClass2");
108       id o = [[MyRootClass alloc] init];
110       [c setVariable: o];
111       
112       if ([c variable] != o)
113         abort ();
114     }
115     
116     /* Now, try that if you take an existing class and try to add an
117        already existing method, class_addMethod returns NO.  This is
118        subtly different from before, when 'new_class' was still in
119        construction.  Now it's a real class and the libobjc internals
120        differ between the two cases.  */
121     if (class_addMethod (object_getClass (new_class), @selector (variable), method_getImplementation (method2),
122                          method_getTypeEncoding (method2)))
123       abort ();
124   }
126   /* Calling class_addProtocol() on a meta class is not documented and
127      (currently) of no use.  */
128   /* std::cout << "Testing class_addProtocol () on a meta class...\n"; */
130   /* Calling class_conformsToProtocol() on a meta class is not
131      documented and (currently) of no use.  */
132   /* std::cout << "Testing class_conformsToProtocol () on a meta class...\n"; */
133   
134   /* Calling class_copyIvarList() on a meta class is not documented
135      and (currently) of no use.  */
136   /* std::cout << "Testing class_copyIvarList () on a meta class...\n"; */
138   std::cout << "Testing class_copyMethodList () on a meta class...\n";
139   {
140     /* Test that you can copy the method list of a meta class.  They
141        are the class methods of the class.  */
142     unsigned int count;
143     Method * list = class_copyMethodList (objc_getMetaClass ("MySubClass"), &count);
145     if (count != 2)
146       abort ();
147     
148     if (! ((std::strcmp (sel_getName (method_getName (list[0])), "variable") == 0
149             && std::strcmp (sel_getName (method_getName (list[1])), "setVariable:") == 0)
150            || (std::strcmp (sel_getName (method_getName (list[0])), "setVariable:") == 0
151                && std::strcmp (sel_getName (method_getName (list[1])), "variable") == 0)))
152       abort ();
153     
154     if (list[2] != NULL)
155       abort ();
156   }
158   /* Calling class_copyPropertyList() on a meta class is not
159      documented and (currently) of no use.  */
160   /* std::cout << "Testing class_copyPropertyList () on a meta class...\n"; */
162   /* Calling class_copyProtocolList() on a meta class is not
163      documented and (currently) of no use.  */
164   /* std::cout << "Testing class_copyProtocolList () on a meta class...\n"; */
166   /* Calling class_createInstance() on a meta class is not documented
167      and (currently) of no use.  */
168   /* std::cout << "Testing class_createInstance () on a meta class...\n"; */
170   /* Calling class_getClassMethod () on a meta class is not documented
171      and (currently) of no use.  */
172   /* std::cout << "Testing class_getClassMethod () on a meta class...\n"; */
174   /* Calling class_getClassVariable () on a meta class is not
175      documented and (currently) of no use.  */
176   /* std::cout << "Testing class_getClassVariable () on a meta class ...\n"; */
178   std::cout << "Testing class_getInstanceMethod () on a meta class...\n";
179   {
180     /* The instance method of a meta class is the class method with
181        the same name of the class. */
182     Method method_1 = class_getInstanceMethod (objc_getMetaClass ("MySubClass"),
183                                                @selector(variable));
184     Method method_2 = class_getClassMethod (objc_getClass ("MySubClass"),
185                                             @selector(variable));
186     
187     if (method_1 == NULL || method_2 == NULL)
188       abort ();
190     if (method_1 != method_2)
191       abort ();
193     if (std::strcmp (sel_getName (method_getName (method_1)), "variable") != 0)
194       abort ();
195   }
197   /* Calling class_getInstanceSize() with a meta class is not
198      documented and (currently) of no use.  */
199   /* std::cout << "Testing class_getInstanceSize () on a meta class...\n"; */
201   /* Calling class_getInstanceVariable() with a meta class is not
202      documented and (currently) of no use.  */
203   /* std::cout << "Testing class_getInstanceVariable () on a meta class...\n"; */
205   /* Calling class_getIvarLayout() with a meta class is not documented
206      and (currently) of no use.  */
207   /* std::cout << "Testing class_getIvarLayout () on a meta class...\n"; */
209   std::cout << "Testing class_getMethodImplementation () on a meta class...\n";
210   {
211     /* Getting the method implementation with a meta class returns a
212        class method.  */
213     MySubClass *object = [[MySubClass alloc] init];
214     IMP imp = class_getMethodImplementation (objc_getMetaClass ("MySubClass"), 
215                                              @selector(variable));
217     if (imp == NULL)
218       abort ();
220     [MySubClass setVariable: object];
222     if ((*imp)(objc_getClass ("MySubClass"), @selector(variable)) != object)
223       abort ();
224   }
226   /* This function does not exist with the GNU runtime.  */
227   /* std::cout << "Testing class_getMethodImplementation_stret () on a meta class...\n"; */
229   std::cout << "Testing class_getName () on a meta class...\n";
230   {
231     /* Traditionally, a meta class has the same name as the class.  */
232     if (std::strcmp (class_getName (objc_getMetaClass ("MyRootClass")),
233                      "MyRootClass") != 0)
234       abort ();
235   }
237   /* Calling class_getProperty() with a meta class is not documented
238      and (currently) of no use.  */
239   /* std::cout << "Testing class_getProperty ()...\n"; */
241   std::cout << "Testing class_getSuperclass () on a meta class...\n";
242   {
243     /* The superclass of a meta class is the meta class of the superclass.  */
244     if (class_getSuperclass (objc_getMetaClass ("MySubClass")) != objc_getMetaClass ("MyRootClass"))
245       abort ();
247     /* Test that it works on a newly created, but not registered, class.  */
248     {
249       Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MySubClass3", 0);
251       if (class_getSuperclass (object_getClass (new_class)) != object_getClass (objc_getClass ("MyRootClass")))
252         abort ();
253     }
254   }
256   /* Calling class_getVersion() with a meta class is not documented
257      and (currently) of no use.  */
258   /* std::cout << "Testing class_getVersion ()...\n"; */
260   /* Calling class_getWeakIvarLayout() with a meta class is not
261      documented and (currently) of no use.  */
262   /* std::cout << "Testing class_getWeakIvarLayout () on a meta class...\n"; */
264   /* class_isMetaClass() is already tested in gnu-api-2-class.m  */
265   /* std::cout << "Testing class_isMetaClass ()...\n"; */
267   std::cout << "Testing class_replaceMethod () on a meta class...\n";
268   {
269     /* We are going to replace the [MySubclass +variable] method with
270        the [DifferentClass +myClass] one.  */
271     Method new_method = class_getClassMethod (objc_getClass ("DifferentClass"),
272                                               @selector (myClass));
273     Method old_method = class_getClassMethod (objc_getClass ("MySubClass"),
274                                               @selector (variable));
275     const char *new_types = method_getTypeEncoding (new_method);
276     IMP new_imp = method_getImplementation (new_method);
277     const char *old_types = method_getTypeEncoding (old_method);
278     IMP old_imp = class_replaceMethod (objc_getMetaClass ("MySubClass"), @selector (variable),
279                                        method_getImplementation (new_method),
280                                        method_getTypeEncoding (new_method));
281     id o = [[MyRootClass alloc] init];
283     [MySubClass setVariable: o];
285     /* Try the new method implementation.  */
286     if ([MySubClass variable] != objc_getClass ("MySubClass"))
287       abort ();
289     /* Put the original method back.  */
290     class_replaceMethod (objc_getMetaClass ("MySubClass"), @selector (variable),
291                          old_imp, old_types);
293     /* Test it's back to what it was.  */
294     if ([MySubClass variable] != o)
295       abort ();
297     {
298       /* Finally, try adding a new method.  */
299       class_replaceMethod (objc_getMetaClass ("DifferentClass"), @selector (mySelf),
300                            new_imp, new_types);
301       
302       if ([(Class)objc_getClass ("DifferentClass") mySelf] != objc_getClass ("DifferentClass"))
303         abort ();
304     }
305   }
307   std::cout << "Testing class_respondsToSelector () on a meta class...\n";
308   {
309     /* A meta class responds to a selector if and only if the class
310        responds to the corresponding class method.  */
311     if (! class_respondsToSelector (objc_getMetaClass ("MySubClass"), @selector(setVariable:)))
312       abort ();
314     if (class_respondsToSelector (objc_getMetaClass ("MyRootClass"), @selector(setVariable:)))
315       abort ();
316   }
318   /* This is not really implemented with the GNU runtime.  */
319   /* std::cout << "Testing class_setIvarLayout () on a meta class...\n"; */
321   /* Calling class_setVersion() with a meta class is not documented
322      and (currently) of no use.  */
323   /* std::cout << "Testing class_setVersion () on a meta class...\n"; */
325   /* This is not really implemented with the GNU runtime.  */
326   /* std::cout << "Testing class_setWeakIvarLayout () on a meta class...\n"; */
328 return (0);