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
13 confused by Foundation
20 #include <objc/objc.h>
21 #include <objc/objc-runtime.h>
24 #if __has_feature(objc_arc)
28 testwarn("rdar://11368528 confused by Foundation");
29 fprintf(stderr, "confused by Foundation\n");
37 @interface Super : TestRoot @end
38 @interface Sub : Super @end
43 if (self == [Super class]) {
44 testassert(state == 1);
48 +(id)forward:(SEL)sel :(marg_list)__unused args
50 if (sel == @selector(missingClassMethod)) {
51 testassert(state == 21 || state == 25 || state == 80);
52 if (state == 21) state = 22;
53 if (state == 25) state = 26;
54 if (state == 80) state = 81;;
56 } else if (sel == @selector(lyingClassMethod)) {
57 testassert(state == 31 || state == 35);
58 if (state == 31) state = 32;
59 if (state == 35) state = 36;
62 fail("+forward:: shouldn't be called with sel %s", sel_getName(sel));
65 -(id)forward:(SEL)sel :(marg_list)__unused args
67 if (sel == @selector(missingInstanceMethod)) {
68 testassert(state == 61 || state == 65);
69 if (state == 61) state = 62;
70 if (state == 65) state = 66;
72 } else if (sel == @selector(lyingInstanceMethod)) {
73 testassert(state == 71 || state == 75);
74 if (state == 71) state = 72;
75 if (state == 75) state = 76;
78 fail("-forward:: shouldn't be called with sel %s", sel_getName(sel));
84 static id classMethod_c(id __unused self, SEL __unused sel)
86 testassert(state == 4 || state == 10);
87 if (state == 4) state = 5;
88 if (state == 10) state = 11;
92 static id instanceMethod_c(id __unused self, SEL __unused sel)
94 testassert(state == 41 || state == 50);
95 if (state == 41) state = 42;
96 if (state == 50) state = 51;
109 if (self == [Sub class]) {
110 testassert(state == 2);
115 +(BOOL)resolveClassMethod:(SEL)sel
117 if (sel == @selector(classMethod)) {
118 testassert(state == 3);
120 class_addMethod(object_getClass(self), sel, (IMP)&classMethod_c, "");
122 } else if (sel == @selector(missingClassMethod)) {
123 testassert(state == 20);
126 } else if (sel == @selector(lyingClassMethod)) {
127 testassert(state == 30);
131 fail("+resolveClassMethod: called incorrectly (sel %s)",
137 +(BOOL)resolveInstanceMethod:(SEL)sel
139 if (sel == @selector(instanceMethod)) {
140 testassert(state == 40);
142 class_addMethod(self, sel, (IMP)instanceMethod_c, "");
144 } else if (sel == @selector(missingInstanceMethod)) {
145 testassert(state == 60);
148 } else if (sel == @selector(lyingInstanceMethod)) {
149 testassert(state == 70);
153 fail("+resolveInstanceMethod: called incorrectly (sel %s)",
161 @interface Super (MissingMethods)
162 +(id)missingClassMethod;
165 @interface Sub (ResolvedMethods)
168 +(id)missingClassMethod;
169 -(id)missingInstanceMethod;
170 +(id)lyingClassMethod;
171 -(id)lyingInstanceMethod;
180 // Be ready for ARC to retain the class object and call +initialize early
183 Class dup = objc_duplicateClass(objc_getClass("Sub"), "Sub_copy", 0);
185 // Resolve a class method
186 // +initialize should fire first (if it hasn't already)
187 ret = [Sub classMethod];
188 testassert(state == 5);
189 testassert(ret == [Super class]);
191 // Call it again, cached
192 // Resolver shouldn't be called again.
194 ret = [Sub classMethod];
195 testassert(state == 11);
196 testassert(ret == [Super class]);
198 _objc_flush_caches(object_getClass([Sub class]));
200 // Call a method that won't get resolved
202 ret = [Sub missingClassMethod];
203 testassert(state == 22);
204 testassert(ret == nil);
206 // Call it again, cached
207 // Resolver shouldn't be called again.
209 ret = [Sub missingClassMethod];
210 testassert(state == 26);
211 testassert(ret == nil);
213 _objc_flush_caches(object_getClass([Sub class]));
215 // Call a method that won't get resolved but the resolver lies about it
217 ret = [Sub lyingClassMethod];
218 testassert(state == 32);
219 testassert(ret == nil);
221 // Call it again, cached
222 // Resolver shouldn't be called again.
224 ret = [Sub lyingClassMethod];
225 testassert(state == 36);
226 testassert(ret == nil);
228 _objc_flush_caches(object_getClass([Sub class]));
231 // Resolve an instance method
234 ret = [s instanceMethod];
235 testassert(state == 42);
236 testassert(ret == [Sub class]);
238 // Call it again, cached
239 // Resolver shouldn't be called again.
241 ret = [s instanceMethod];
242 testassert(state == 51);
243 testassert(ret == [Sub class]);
245 _objc_flush_caches([Sub class]);
247 // Call a method that won't get resolved
249 ret = [s missingInstanceMethod];
250 testassert(state == 62);
251 testassert(ret == nil);
253 // Call it again, cached
254 // Resolver shouldn't be called again.
256 ret = [s missingInstanceMethod];
257 testassert(state == 66);
258 testassert(ret == nil);
260 _objc_flush_caches([Sub class]);
262 // Call a method that won't get resolved but the resolver lies about it
264 ret = [s lyingInstanceMethod];
265 testassert(state == 72);
266 testassert(ret == nil);
268 // Call it again, cached
269 // Resolver shouldn't be called again.
271 ret = [s lyingInstanceMethod];
272 testassert(state == 76);
273 testassert(ret == nil);
275 _objc_flush_caches([Sub class]);
277 // Call a missing method on a class that doesn't support resolving
279 ret = [Super missingClassMethod];
280 testassert(state == 81);
281 testassert(ret == nil);
284 // Resolve an instance method on a class duplicated before resolving
287 ret = [s instanceMethod];
288 testassert(state == 42);
289 testassert(ret == [Sub class]);
291 // Call it again, cached
292 // Resolver shouldn't be called again.
294 ret = [s instanceMethod];
295 testassert(state == 51);
296 testassert(ret == [Sub class]);