2 * Test +resolveClassMethod: and +resolveInstanceMethod:
5 // TEST_CFLAGS -Wno-deprecated-declarations
9 objc\[\d+\]: \+\[Sub resolveClassMethod:lyingClassMethod\] returned YES, but no new implementation of \+\[Sub lyingClassMethod\] was found
10 objc\[\d+\]: \+\[Sub resolveInstanceMethod:lyingInstanceMethod\] returned YES, but no new implementation of -\[Sub lyingInstanceMethod\] was found
16 #include <objc/objc.h>
17 #include <objc/objc-runtime.h>
22 @interface Super { id isa; } @end
23 @interface Sub : Super @end
27 +class { return self; }
29 if (self == [Super class]) {
30 testassert(state == 1);
34 +new { return class_createInstance(self, 0); }
35 -(void)dealloc { object_dispose(self); }
36 -forward:(SEL)sel :(marg_list)args
38 if (sel == @selector(missingClassMethod)) {
39 testassert(state == 21 || state == 25 || state == 80);
40 if (state == 21) state = 22;
41 if (state == 25) state = 26;
42 if (state == 80) state = 81;;
44 } else if (sel == @selector(lyingClassMethod)) {
45 testassert(state == 31 || state == 35);
46 if (state == 31) state = 32;
47 if (state == 35) state = 36;
49 } else if (sel == @selector(missingInstanceMethod)) {
50 testassert(state == 61 || state == 65);
51 if (state == 61) state = 62;
52 if (state == 65) state = 66;
54 } else if (sel == @selector(lyingInstanceMethod)) {
55 testassert(state == 71 || state == 75);
56 if (state == 71) state = 72;
57 if (state == 75) state = 76;
60 fail("forward:: shouldn't be called (sel %s)", sel_getName(sel));
61 return (id)args; // unused
66 static id classMethod_c(id self, SEL sel)
68 testassert(state == 4 || state == 10);
69 if (state == 4) state = 5;
70 if (state == 10) state = 11;
71 self = (id)sel; // unused
75 static id instanceMethod_c(id self, SEL sel)
77 testassert(state == 41 || state == 50);
78 if (state == 41) state = 42;
79 if (state == 50) state = 51;
80 self = (id)sel; // unused
93 if (self == [Sub class]) {
94 testassert(state == 2);
99 +(BOOL)resolveClassMethod:(SEL)sel
101 if (sel == @selector(classMethod)) {
102 testassert(state == 3);
104 class_addMethod(self->isa, sel, (IMP)&classMethod_c, "");
106 } else if (sel == @selector(missingClassMethod)) {
107 testassert(state == 20);
110 } else if (sel == @selector(lyingClassMethod)) {
111 testassert(state == 30);
115 fail("+resolveClassMethod: called incorrectly (sel %s)",
121 +(BOOL)resolveInstanceMethod:(SEL)sel
123 if (sel == @selector(instanceMethod)) {
124 testassert(state == 40);
126 class_addMethod(self, sel, (IMP)instanceMethod_c, "");
128 } else if (sel == @selector(missingInstanceMethod)) {
129 testassert(state == 60);
132 } else if (sel == @selector(lyingInstanceMethod)) {
133 testassert(state == 70);
137 fail("+resolveInstanceMethod: called incorrectly (sel %s)",
145 @interface Super (MissingMethods)
149 @interface Sub (ResolvedMethods)
153 -missingInstanceMethod;
155 -lyingInstanceMethod;
163 Class dup = objc_duplicateClass(objc_getClass("Sub"), "Sub_copy", 0);
165 // Resolve a class method
166 // +initialize should fire first
168 ret = [Sub classMethod];
169 testassert(state == 5);
170 testassert(ret == [Super class]);
172 // Call it again, cached
173 // Resolver shouldn't be called again.
175 ret = [Sub classMethod];
176 testassert(state == 11);
177 testassert(ret == [Super class]);
179 _objc_flush_caches([Sub class]->isa);
181 // Call a method that won't get resolved
183 ret = [Sub missingClassMethod];
184 testassert(state == 22);
185 testassert(ret == nil);
187 // Call it again, cached
188 // Resolver shouldn't be called again.
190 ret = [Sub missingClassMethod];
191 testassert(state == 26);
192 testassert(ret == nil);
194 _objc_flush_caches([Sub class]->isa);
196 // Call a method that won't get resolved but the resolver lies about it
198 ret = [Sub lyingClassMethod];
199 testassert(state == 32);
200 testassert(ret == nil);
202 // Call it again, cached
203 // Resolver shouldn't be called again.
205 ret = [Sub lyingClassMethod];
206 testassert(state == 36);
207 testassert(ret == nil);
209 _objc_flush_caches([Sub class]->isa);
212 // Resolve an instance method
215 ret = [s instanceMethod];
216 testassert(state == 42);
217 testassert(ret == [Sub class]);
219 // Call it again, cached
220 // Resolver shouldn't be called again.
222 ret = [s instanceMethod];
223 testassert(state == 51);
224 testassert(ret == [Sub class]);
226 _objc_flush_caches([Sub class]);
228 // Call a method that won't get resolved
230 ret = [s missingInstanceMethod];
231 testassert(state == 62);
232 testassert(ret == nil);
234 // Call it again, cached
235 // Resolver shouldn't be called again.
237 ret = [s missingInstanceMethod];
238 testassert(state == 66);
239 testassert(ret == nil);
241 _objc_flush_caches([Sub class]);
243 // Call a method that won't get resolved but the resolver lies about it
245 ret = [s lyingInstanceMethod];
246 testassert(state == 72);
247 testassert(ret == nil);
249 // Call it again, cached
250 // Resolver shouldn't be called again.
252 ret = [s lyingInstanceMethod];
253 testassert(state == 76);
254 testassert(ret == nil);
256 _objc_flush_caches([Sub class]);
258 // Call a missing method on a class that doesn't support resolving
260 ret = [Super missingClassMethod];
261 testassert(state == 81);
262 testassert(ret == nil);
265 // Resolve an instance method on a class duplicated before resolving
268 ret = [s instanceMethod];
269 testassert(state == 42);
270 testassert(ret == [Sub class]);
272 // Call it again, cached
273 // Resolver shouldn't be called again.
275 ret = [s instanceMethod];
276 testassert(state == 51);
277 testassert(ret == [Sub class]);