1/* resolve.m 2 * Test +resolveClassMethod: and +resolveInstanceMethod: 3 */ 4 5// TEST_CFLAGS -Wno-deprecated-declarations 6 7#include "test.h" 8#include "testroot.i" 9#include <objc/objc.h> 10#include <objc/objc-runtime.h> 11#include <unistd.h> 12 13#if __has_feature(objc_arc) 14 15int main() 16{ 17 testwarn("rdar://11368528 confused by Foundation"); 18 succeed(__FILE__); 19} 20 21#else 22 23static int state = 0; 24 25@interface Super : TestRoot @end 26@interface Sub : Super @end 27 28 29@implementation Super 30+(void)initialize { 31 if (self == [Super class]) { 32 testassert(state == 1); 33 state = 2; 34 } 35} 36@end 37 38static id forward_handler(id self, SEL sel) 39{ 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;; 47 return nil; 48 } else if (sel == @selector(lyingClassMethod)) { 49 testassert(state == 31 || state == 35); 50 if (state == 31) state = 32; 51 if (state == 35) state = 36; 52 return nil; 53 } 54 fail("+forward:: shouldn't be called with sel %s", sel_getName(sel)); 55 return nil; 56 } 57 else { 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; 63 return nil; 64 } else if (sel == @selector(lyingInstanceMethod)) { 65 testassert(state == 71 || state == 75); 66 if (state == 71) state = 72; 67 if (state == 75) state = 76; 68 return nil; 69 } 70 fail("-forward:: shouldn't be called with sel %s", sel_getName(sel)); 71 return nil; 72 } 73} 74 75 76static id classMethod_c(id __unused self, SEL __unused sel) 77{ 78 testassert(state == 4 || state == 10); 79 if (state == 4) state = 5; 80 if (state == 10) state = 11; 81 return [Super class]; 82} 83 84static id instanceMethod_c(id __unused self, SEL __unused sel) 85{ 86 testassert(state == 41 || state == 50); 87 if (state == 41) state = 42; 88 if (state == 50) state = 51; 89 return [Sub class]; 90} 91 92 93@implementation Sub 94 95+(void)method2 { } 96+(void)method3 { } 97+(void)method4 { } 98+(void)method5 { } 99 100+(void)initialize { 101 if (self == [Sub class]) { 102 testassert(state == 2); 103 state = 3; 104 } 105} 106 107+(BOOL)resolveClassMethod:(SEL)sel 108{ 109 if (sel == @selector(classMethod)) { 110 testassert(state == 3); 111 state = 4; 112 class_addMethod(object_getClass(self), sel, (IMP)&classMethod_c, ""); 113 return YES; 114 } else if (sel == @selector(missingClassMethod)) { 115 testassert(state == 20); 116 state = 21; 117 return NO; 118 } else if (sel == @selector(lyingClassMethod)) { 119 testassert(state == 30); 120 state = 31; 121 return YES; // lie 122 } else { 123 fail("+resolveClassMethod: called incorrectly (sel %s)", 124 sel_getName(sel)); 125 return NO; 126 } 127} 128 129+(BOOL)resolveInstanceMethod:(SEL)sel 130{ 131 if (sel == @selector(instanceMethod)) { 132 testassert(state == 40); 133 state = 41; 134 class_addMethod(self, sel, (IMP)instanceMethod_c, ""); 135 return YES; 136 } else if (sel == @selector(missingInstanceMethod)) { 137 testassert(state == 60); 138 state = 61; 139 return NO; 140 } else if (sel == @selector(lyingInstanceMethod)) { 141 testassert(state == 70); 142 state = 71; 143 return YES; // lie 144 } else { 145 fail("+resolveInstanceMethod: called incorrectly (sel %s)", 146 sel_getName(sel)); 147 return NO; 148 } 149} 150 151@end 152 153@interface Super (MissingMethods) 154+(id)missingClassMethod; 155@end 156 157@interface Sub (ResolvedMethods) 158+(id)classMethod; 159-(id)instanceMethod; 160+(id)missingClassMethod; 161-(id)missingInstanceMethod; 162+(id)lyingClassMethod; 163-(id)lyingInstanceMethod; 164@end 165 166 167int main() 168{ 169 Sub *s; 170 id ret; 171 172 objc_setForwardHandler((void*)&forward_handler, NULL); 173 174 // Be ready for ARC to retain the class object and call +initialize early 175 state = 1; 176 177 Class dup = objc_duplicateClass(objc_getClass("Sub"), "Sub_copy", 0); 178 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]); 184 185 // Call it again, cached 186 // Resolver shouldn't be called again. 187 state = 10; 188 ret = [Sub classMethod]; 189 testassert(state == 11); 190 testassert(ret == [Super class]); 191 192 _objc_flush_caches(object_getClass([Sub class])); 193 194 // Call a method that won't get resolved 195 state = 20; 196 ret = [Sub missingClassMethod]; 197 testassert(state == 22); 198 testassert(ret == nil); 199 200 // Call it again, cached 201 // Resolver shouldn't be called again. 202 state = 25; 203 ret = [Sub missingClassMethod]; 204 testassert(state == 26); 205 testassert(ret == nil); 206 207 _objc_flush_caches(object_getClass([Sub class])); 208 209 // Call a method that won't get resolved but the resolver lies about it 210 state = 30; 211 ret = [Sub lyingClassMethod]; 212 testassert(state == 32); 213 testassert(ret == nil); 214 215 // Call it again, cached 216 // Resolver shouldn't be called again. 217 state = 35; 218 ret = [Sub lyingClassMethod]; 219 testassert(state == 36); 220 testassert(ret == nil); 221 222 _objc_flush_caches(object_getClass([Sub class])); 223 224 225 // Resolve an instance method 226 s = [Sub new]; 227 state = 40; 228 ret = [s instanceMethod]; 229 testassert(state == 42); 230 testassert(ret == [Sub class]); 231 232 // Call it again, cached 233 // Resolver shouldn't be called again. 234 state = 50; 235 ret = [s instanceMethod]; 236 testassert(state == 51); 237 testassert(ret == [Sub class]); 238 239 _objc_flush_caches([Sub class]); 240 241 // Call a method that won't get resolved 242 state = 60; 243 ret = [s missingInstanceMethod]; 244 testassert(state == 62); 245 testassert(ret == nil); 246 247 // Call it again, cached 248 // Resolver shouldn't be called again. 249 state = 65; 250 ret = [s missingInstanceMethod]; 251 testassert(state == 66); 252 testassert(ret == nil); 253 254 _objc_flush_caches([Sub class]); 255 256 // Call a method that won't get resolved but the resolver lies about it 257 state = 70; 258 ret = [s lyingInstanceMethod]; 259 testassert(state == 72); 260 testassert(ret == nil); 261 262 // Call it again, cached 263 // Resolver shouldn't be called again. 264 state = 75; 265 ret = [s lyingInstanceMethod]; 266 testassert(state == 76); 267 testassert(ret == nil); 268 269 _objc_flush_caches([Sub class]); 270 271 // Call a missing method on a class that doesn't support resolving 272 state = 80; 273 ret = [Super missingClassMethod]; 274 testassert(state == 81); 275 testassert(ret == nil); 276 RELEASE_VAR(s); 277 278 // Resolve an instance method on a class duplicated before resolving 279 s = [dup new]; 280 state = 40; 281 ret = [s instanceMethod]; 282 testassert(state == 42); 283 testassert(ret == [Sub class]); 284 285 // Call it again, cached 286 // Resolver shouldn't be called again. 287 state = 50; 288 ret = [s instanceMethod]; 289 testassert(state == 51); 290 testassert(ret == [Sub class]); 291 RELEASE_VAR(s); 292 293 succeed(__FILE__); 294 return 0; 295} 296 297#endif 298 299