2 * Test +resolveClassMethod: and +resolveInstanceMethod:
7 #include <objc/objc-runtime.h>
11 extern void _objc_flush_caches(Class cls, BOOL flushMeta);
15 @interface Super { id isa; } @end
16 @interface Sub : Super @end
20 +class { return self; }
22 if (self == [Super class]) {
23 testassert(state == 1);
27 +new { return class_createInstance(self, 0); }
28 -(void)dealloc { object_dispose(self); }
29 -forward:(SEL)sel :(marg_list)args
31 if (sel == @selector(missingClassMethod)) {
32 testassert(state == 21 || state == 25 || state == 80);
33 if (state == 21) state = 22;
34 if (state == 25) state = 26;
35 if (state == 80) state = 81;;
37 } else if (sel == @selector(lyingClassMethod)) {
38 testassert(state == 31 || state == 35);
39 if (state == 31) state = 32;
40 if (state == 35) state = 36;
42 } else if (sel == @selector(missingInstanceMethod)) {
43 testassert(state == 61 || state == 65);
44 if (state == 61) state = 62;
45 if (state == 65) state = 66;
47 } else if (sel == @selector(lyingInstanceMethod)) {
48 testassert(state == 71 || state == 75);
49 if (state == 71) state = 72;
50 if (state == 75) state = 76;
53 fail("forward:: shouldn't be called (sel %s)", sel_getName(sel));
54 return args; // unused
59 static id classMethod_c(id self, SEL sel)
61 testassert(state == 4 || state == 10);
62 if (state == 4) state = 5;
63 if (state == 10) state = 11;
64 self = (id)sel; // unused
68 static id instanceMethod_c(id self, SEL sel)
70 testassert(state == 41 || state == 50);
71 if (state == 41) state = 42;
72 if (state == 50) state = 51;
73 self = (id)sel; // unused
86 if (self == [Sub class]) {
87 testassert(state == 2);
92 +(BOOL)resolveClassMethod:(SEL)sel
94 if (sel == @selector(classMethod)) {
95 testassert(state == 3);
97 class_addMethod(self->isa, sel, (IMP)&classMethod_c, "");
99 } else if (sel == @selector(missingClassMethod)) {
100 testassert(state == 20);
103 } else if (sel == @selector(lyingClassMethod)) {
104 testassert(state == 30);
108 fail("+resolveClassMethod: called incorrectly (sel %s)",
114 +(BOOL)resolveInstanceMethod:(SEL)sel
116 if (sel == @selector(instanceMethod)) {
117 testassert(state == 40);
119 class_addMethod(self, sel, (IMP)instanceMethod_c, "");
121 } else if (sel == @selector(missingInstanceMethod)) {
122 testassert(state == 60);
125 } else if (sel == @selector(lyingInstanceMethod)) {
126 testassert(state == 70);
130 fail("+resolveInstanceMethod: called incorrectly (sel %s)",
138 @interface Super (MissingMethods)
142 @interface Sub (ResolvedMethods)
146 -missingInstanceMethod;
148 -lyingInstanceMethod;
156 Class dup = objc_duplicateClass(objc_getClass("Sub"), "Sub_copy", 0);
158 // Resolve a class method
159 // +initialize should fire first
161 ret = [Sub classMethod];
162 testassert(state == 5);
163 testassert(ret == [Super class]);
165 // Call it again, cached
166 // Resolver shouldn't be called again.
168 ret = [Sub classMethod];
169 testassert(state == 11);
170 testassert(ret == [Super class]);
172 _objc_flush_caches([Sub class]->isa, NO);
174 // Call a method that won't get resolved
176 ret = [Sub missingClassMethod];
177 testassert(state == 22);
178 testassert(ret == nil);
180 // Call it again, cached
181 // Resolver shouldn't be called again.
183 ret = [Sub missingClassMethod];
184 testassert(state == 26);
185 testassert(ret == nil);
187 _objc_flush_caches([Sub class]->isa, NO);
189 // Call a method that won't get resolved but the resolver lies about it
191 ret = [Sub lyingClassMethod];
192 testassert(state == 32);
193 testassert(ret == nil);
195 // Call it again, cached
196 // Resolver shouldn't be called again.
198 ret = [Sub lyingClassMethod];
199 testassert(state == 36);
200 testassert(ret == nil);
202 _objc_flush_caches([Sub class]->isa, NO);
205 // Resolve an instance method
208 ret = [s instanceMethod];
209 testassert(state == 42);
210 testassert(ret == [Sub class]);
212 // Call it again, cached
213 // Resolver shouldn't be called again.
215 ret = [s instanceMethod];
216 testassert(state == 51);
217 testassert(ret == [Sub class]);
219 _objc_flush_caches([Sub class], NO);
221 // Call a method that won't get resolved
223 ret = [s missingInstanceMethod];
224 testassert(state == 62);
225 testassert(ret == nil);
227 // Call it again, cached
228 // Resolver shouldn't be called again.
230 ret = [s missingInstanceMethod];
231 testassert(state == 66);
232 testassert(ret == nil);
234 _objc_flush_caches([Sub class], NO);
236 // Call a method that won't get resolved but the resolver lies about it
238 ret = [s lyingInstanceMethod];
239 testassert(state == 72);
240 testassert(ret == nil);
242 // Call it again, cached
243 // Resolver shouldn't be called again.
245 ret = [s lyingInstanceMethod];
246 testassert(state == 76);
247 testassert(ret == nil);
249 _objc_flush_caches([Sub class], NO);
251 // Call a missing method on a class that doesn't support resolving
253 ret = [Super missingClassMethod];
254 testassert(state == 81);
255 testassert(ret == nil);
258 // Resolve an instance method on a class duplicated before resolving
261 ret = [s instanceMethod];
262 testassert(state == 42);
263 testassert(ret == [Sub class]);
265 // Call it again, cached
266 // Resolver shouldn't be called again.
268 ret = [s instanceMethod];
269 testassert(state == 51);
270 testassert(ret == [Sub class]);