2 * Test +resolveClassMethod: and +resolveInstanceMethod:
5 // TEST_CFLAGS -Wno-deprecated-declarations
10 #include <objc/objc-runtime.h>
13 #if __has_feature(objc_arc)
17 testwarn("rdar://11368528 confused by Foundation");
25 @interface Super : TestRoot @end
26 @interface Sub : Super @end
31 if (self == [Super class]) {
32 testassert(state == 1);
38 static id forward_handler(id self, SEL sel)
40 if (class_isMetaClass(object_getClass(self))) {
41 // self is a class object
42 if (sel == @selector(missingClassMethod)) {
43 testassert(state == 21 || state == 25 || state == 80);
44 if (state == 21) state = 22;
45 if (state == 25) state = 26;
46 if (state == 80) state = 81;;
48 } else if (sel == @selector(lyingClassMethod)) {
49 testassert(state == 31 || state == 35);
50 if (state == 31) state = 32;
51 if (state == 35) state = 36;
54 fail("+forward:: shouldn't be called with sel %s", sel_getName(sel));
58 // self is not a class object
59 if (sel == @selector(missingInstanceMethod)) {
60 testassert(state == 61 || state == 65);
61 if (state == 61) state = 62;
62 if (state == 65) state = 66;
64 } else if (sel == @selector(lyingInstanceMethod)) {
65 testassert(state == 71 || state == 75);
66 if (state == 71) state = 72;
67 if (state == 75) state = 76;
70 fail("-forward:: shouldn't be called with sel %s", sel_getName(sel));
76 static id classMethod_c(id __unused self, SEL __unused sel)
78 testassert(state == 4 || state == 10);
79 if (state == 4) state = 5;
80 if (state == 10) state = 11;
84 static id instanceMethod_c(id __unused self, SEL __unused sel)
86 testassert(state == 41 || state == 50);
87 if (state == 41) state = 42;
88 if (state == 50) state = 51;
101 if (self == [Sub class]) {
102 testassert(state == 2);
107 +(BOOL)resolveClassMethod:(SEL)sel
109 if (sel == @selector(classMethod)) {
110 testassert(state == 3);
112 class_addMethod(object_getClass(self), sel, (IMP)&classMethod_c, "");
114 } else if (sel == @selector(missingClassMethod)) {
115 testassert(state == 20);
118 } else if (sel == @selector(lyingClassMethod)) {
119 testassert(state == 30);
123 fail("+resolveClassMethod: called incorrectly (sel %s)",
129 +(BOOL)resolveInstanceMethod:(SEL)sel
131 if (sel == @selector(instanceMethod)) {
132 testassert(state == 40);
134 class_addMethod(self, sel, (IMP)instanceMethod_c, "");
136 } else if (sel == @selector(missingInstanceMethod)) {
137 testassert(state == 60);
140 } else if (sel == @selector(lyingInstanceMethod)) {
141 testassert(state == 70);
145 fail("+resolveInstanceMethod: called incorrectly (sel %s)",
153 @interface Super (MissingMethods)
154 +(id)missingClassMethod;
157 @interface Sub (ResolvedMethods)
160 +(id)missingClassMethod;
161 -(id)missingInstanceMethod;
162 +(id)lyingClassMethod;
163 -(id)lyingInstanceMethod;
172 objc_setForwardHandler((void*)&forward_handler, (void*)&abort);
174 // Be ready for ARC to retain the class object and call +initialize early
177 Class dup = objc_duplicateClass(objc_getClass("Sub"), "Sub_copy", 0);
179 // Resolve a class method
180 // +initialize should fire first (if it hasn't already)
181 ret = [Sub classMethod];
182 testassert(state == 5);
183 testassert(ret == [Super class]);
185 // Call it again, cached
186 // Resolver shouldn't be called again.
188 ret = [Sub classMethod];
189 testassert(state == 11);
190 testassert(ret == [Super class]);
192 _objc_flush_caches(object_getClass([Sub class]));
194 // Call a method that won't get resolved
196 ret = [Sub missingClassMethod];
197 testassert(state == 22);
198 testassert(ret == nil);
200 // Call it again, cached
201 // Resolver shouldn't be called again.
203 ret = [Sub missingClassMethod];
204 testassert(state == 26);
205 testassert(ret == nil);
207 _objc_flush_caches(object_getClass([Sub class]));
209 // Call a method that won't get resolved but the resolver lies about it
211 ret = [Sub lyingClassMethod];
212 testassert(state == 32);
213 testassert(ret == nil);
215 // Call it again, cached
216 // Resolver shouldn't be called again.
218 ret = [Sub lyingClassMethod];
219 testassert(state == 36);
220 testassert(ret == nil);
222 _objc_flush_caches(object_getClass([Sub class]));
225 // Resolve an instance method
228 ret = [s instanceMethod];
229 testassert(state == 42);
230 testassert(ret == [Sub class]);
232 // Call it again, cached
233 // Resolver shouldn't be called again.
235 ret = [s instanceMethod];
236 testassert(state == 51);
237 testassert(ret == [Sub class]);
239 _objc_flush_caches([Sub class]);
241 // Call a method that won't get resolved
243 ret = [s missingInstanceMethod];
244 testassert(state == 62);
245 testassert(ret == nil);
247 // Call it again, cached
248 // Resolver shouldn't be called again.
250 ret = [s missingInstanceMethod];
251 testassert(state == 66);
252 testassert(ret == nil);
254 _objc_flush_caches([Sub class]);
256 // Call a method that won't get resolved but the resolver lies about it
258 ret = [s lyingInstanceMethod];
259 testassert(state == 72);
260 testassert(ret == nil);
262 // Call it again, cached
263 // Resolver shouldn't be called again.
265 ret = [s lyingInstanceMethod];
266 testassert(state == 76);
267 testassert(ret == nil);
269 _objc_flush_caches([Sub class]);
271 // Call a missing method on a class that doesn't support resolving
273 ret = [Super missingClassMethod];
274 testassert(state == 81);
275 testassert(ret == nil);
278 // Resolve an instance method on a class duplicated before resolving
281 ret = [s instanceMethod];
282 testassert(state == 42);
283 testassert(ret == [Sub class]);
285 // Call it again, cached
286 // Resolver shouldn't be called again.
288 ret = [s instanceMethod];
289 testassert(state == 51);
290 testassert(ret == [Sub class]);