resolve.m 7.2 KB

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