copyMethodList.m 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // TEST_CFLAGS -Wl,-no_objc_category_merging
  2. #include "test.h"
  3. #include "testroot.i"
  4. #include <malloc/malloc.h>
  5. #include <objc/runtime.h>
  6. @interface SuperMethods : TestRoot { } @end
  7. @implementation SuperMethods
  8. +(BOOL)SuperMethodClass { return NO; }
  9. +(BOOL)SuperMethodClass2 { return NO; }
  10. -(BOOL)SuperMethodInstance { return NO; }
  11. -(BOOL)SuperMethodInstance2 { return NO; }
  12. @end
  13. @interface SubMethods : SuperMethods { } @end
  14. @implementation SubMethods
  15. +(BOOL)SubMethodClass { return NO; }
  16. +(BOOL)SubMethodClass2 { return NO; }
  17. -(BOOL)SubMethodInstance { return NO; }
  18. -(BOOL)SubMethodInstance2 { return NO; }
  19. @end
  20. @interface SuperMethods (Category) @end
  21. @implementation SuperMethods (Category)
  22. +(BOOL)SuperMethodClass { return YES; }
  23. +(BOOL)SuperMethodClass2 { return YES; }
  24. -(BOOL)SuperMethodInstance { return YES; }
  25. -(BOOL)SuperMethodInstance2 { return YES; }
  26. @end
  27. @interface SubMethods (Category) @end
  28. @implementation SubMethods (Category)
  29. +(BOOL)SubMethodClass { return YES; }
  30. +(BOOL)SubMethodClass2 { return YES; }
  31. -(BOOL)SubMethodInstance { return YES; }
  32. -(BOOL)SubMethodInstance2 { return YES; }
  33. @end
  34. @interface FourMethods : TestRoot @end
  35. @implementation FourMethods
  36. -(void)one { }
  37. -(void)two { }
  38. -(void)three { }
  39. -(void)four { }
  40. @end
  41. @interface NoMethods : TestRoot @end
  42. @implementation NoMethods @end
  43. static void checkReplacement(Method *list, const char *name)
  44. {
  45. Method first = NULL, second = NULL;
  46. SEL sel = sel_registerName(name);
  47. int i;
  48. testassert(list);
  49. // Find the methods. There should be two.
  50. for (i = 0; list[i]; i++) {
  51. if (method_getName(list[i]) == sel) {
  52. if (!first) first = list[i];
  53. else if (!second) second = list[i];
  54. else testassert(0);
  55. }
  56. }
  57. // Call the methods. The first should be the category (returns YES).
  58. BOOL isCat;
  59. isCat = ((BOOL(*)(id, Method))method_invoke)(NULL, first);
  60. testassert(isCat);
  61. isCat = ((BOOL(*)(id, Method))method_invoke)(NULL, second);
  62. testassert(! isCat);
  63. }
  64. int main()
  65. {
  66. // Class SubMethods has not yet been touched, so runtime must attach
  67. // the lazy categories
  68. Method *methods;
  69. unsigned int count;
  70. Class cls;
  71. cls = objc_getClass("SubMethods");
  72. testassert(cls);
  73. testprintf("calling class_copyMethodList(SubMethods) (should be unmethodized)\n");
  74. count = 100;
  75. methods = class_copyMethodList(cls, &count);
  76. testassert(methods);
  77. testassert(count == 4);
  78. // methods[] should be null-terminated
  79. testassert(methods[4] == NULL);
  80. // Class and category methods may be mixed in the method list thanks
  81. // to linker / shared cache sorting, but a category's replacement should
  82. // always precede the class's implementation.
  83. checkReplacement(methods, "SubMethodInstance");
  84. checkReplacement(methods, "SubMethodInstance2");
  85. free(methods);
  86. testprintf("calling class_copyMethodList(SubMethods(meta)) (should be unmethodized)\n");
  87. count = 100;
  88. methods = class_copyMethodList(object_getClass(cls), &count);
  89. testassert(methods);
  90. testassert(count == 4);
  91. // methods[] should be null-terminated
  92. testassert(methods[4] == NULL);
  93. // Class and category methods may be mixed in the method list thanks
  94. // to linker / shared cache sorting, but a category's replacement should
  95. // always precede the class's implementation.
  96. checkReplacement(methods, "SubMethodClass");
  97. checkReplacement(methods, "SubMethodClass2");
  98. free(methods);
  99. // Check null-termination - this method list block would be 16 bytes
  100. // if it weren't for the terminator
  101. count = 100;
  102. cls = objc_getClass("FourMethods");
  103. methods = class_copyMethodList(cls, &count);
  104. testassert(methods);
  105. testassert(count == 4);
  106. testassert(malloc_size(methods) >= (4+1) * sizeof(Method));
  107. testassert(methods[3] != NULL);
  108. testassert(methods[4] == NULL);
  109. free(methods);
  110. // Check NULL count parameter
  111. methods = class_copyMethodList(cls, NULL);
  112. testassert(methods);
  113. testassert(methods[4] == NULL);
  114. testassert(methods[3] != NULL);
  115. free(methods);
  116. // Check NULL class parameter
  117. count = 100;
  118. methods = class_copyMethodList(NULL, &count);
  119. testassert(!methods);
  120. testassert(count == 0);
  121. // Check NULL class and count
  122. methods = class_copyMethodList(NULL, NULL);
  123. testassert(!methods);
  124. // Check class with no methods
  125. count = 100;
  126. cls = objc_getClass("NoMethods");
  127. methods = class_copyMethodList(cls, &count);
  128. testassert(!methods);
  129. testassert(count == 0);
  130. succeed(__FILE__);
  131. }