addProtocol.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /*
  2. TEST_CFLAGS -framework Foundation
  3. TEST_BUILD_OUTPUT
  4. .*addProtocol.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\](\n.* note: expanded from macro 'testassert')?
  5. .*addProtocol.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\](\n.* note: expanded from macro 'testassert')?
  6. .*addProtocol.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\](\n.* note: expanded from macro 'testassert')?
  7. .*addProtocol.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\](\n.* note: expanded from macro 'testassert')?
  8. .*addProtocol.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\](\n.* note: expanded from macro 'testassert')?
  9. END
  10. TEST_RUN_OUTPUT
  11. objc\[\d+\]: protocol_addProtocol: added protocol 'EmptyProto' is still under construction!
  12. objc\[\d+\]: objc_registerProtocol: protocol 'Proto1' was already registered!
  13. objc\[\d+\]: protocol_addProtocol: modified protocol 'Proto1' is not under construction!
  14. objc\[\d+\]: protocol_addMethodDescription: protocol 'Proto1' is not under construction!
  15. objc\[\d+\]: objc_registerProtocol: protocol 'SuperProto' was already registered!
  16. objc\[\d+\]: protocol_addProtocol: modified protocol 'SuperProto' is not under construction!
  17. objc\[\d+\]: protocol_addMethodDescription: protocol 'SuperProto' is not under construction!
  18. OK: addProtocol.m
  19. END
  20. */
  21. #include "test.h"
  22. #include <objc/runtime.h>
  23. #include <Foundation/Foundation.h>
  24. @protocol SuperProto @end
  25. @protocol SuperProto2 @end
  26. @protocol UnrelatedProto @end
  27. void Crash(id self, SEL _cmd)
  28. {
  29. fail("%c[%s %s] called unexpectedly",
  30. class_isMetaClass(object_getClass(self)) ? '+' : '-',
  31. object_getClassName(self), sel_getName(_cmd));
  32. }
  33. int main()
  34. {
  35. // old-ABI implementation of [Protocol retain]
  36. // is added by +[NSObject(NSObject) load] in CF.
  37. [NSObject class];
  38. Protocol *proto, *proto2;
  39. Protocol * __unsafe_unretained *protolist;
  40. struct objc_method_description *desclist;
  41. objc_property_t *proplist;
  42. unsigned int count;
  43. // If objc_registerProtocol() fails to preserve the retain count
  44. // then ARC will deallocate Protocol objects too early.
  45. class_replaceMethod(objc_getClass("Protocol"),
  46. sel_registerName("dealloc"), (IMP)Crash, "v@:");
  47. class_replaceMethod(objc_getClass("__IncompleteProtocol"),
  48. sel_registerName("dealloc"), (IMP)Crash, "v@:");
  49. // make sure binary contains hard copies of these protocols
  50. proto = @protocol(SuperProto);
  51. proto = @protocol(SuperProto2);
  52. // Adding a protocol
  53. char *name = strdup("Proto1");
  54. proto = objc_allocateProtocol(name);
  55. testassert(proto);
  56. testassert(!objc_getProtocol(name));
  57. protocol_addProtocol(proto, @protocol(SuperProto));
  58. protocol_addProtocol(proto, @protocol(SuperProto2));
  59. // no inheritance cycles
  60. proto2 = objc_allocateProtocol("EmptyProto");
  61. protocol_addProtocol(proto, proto2); // fails
  62. objc_registerProtocol(proto2);
  63. protocol_addProtocol(proto, proto2); // succeeds
  64. char *types = strdup("@:");
  65. protocol_addMethodDescription(proto, @selector(ReqInst0), types, YES, YES);
  66. protocol_addMethodDescription(proto, @selector(ReqInst1), types, YES, YES);
  67. protocol_addMethodDescription(proto, @selector(ReqInst2), types, YES, YES);
  68. protocol_addMethodDescription(proto, @selector(ReqInst3), types, YES, YES);
  69. protocol_addMethodDescription(proto, @selector(ReqClas0), types, YES, NO);
  70. protocol_addMethodDescription(proto, @selector(ReqClas1), types, YES, NO);
  71. protocol_addMethodDescription(proto, @selector(ReqClas2), types, YES, NO);
  72. protocol_addMethodDescription(proto, @selector(ReqClas3), types, YES, NO);
  73. protocol_addMethodDescription(proto, @selector(OptInst0), types, NO, YES);
  74. protocol_addMethodDescription(proto, @selector(OptInst1), types, NO, YES);
  75. protocol_addMethodDescription(proto, @selector(OptInst2), types, NO, YES);
  76. protocol_addMethodDescription(proto, @selector(OptInst3), types, NO, YES);
  77. protocol_addMethodDescription(proto, @selector(OptClas0), types, NO, NO);
  78. protocol_addMethodDescription(proto, @selector(OptClas1), types, NO, NO);
  79. protocol_addMethodDescription(proto, @selector(OptClas2), types, NO, NO);
  80. protocol_addMethodDescription(proto, @selector(OptClas3), types, NO, NO);
  81. char *name0 = strdup("ReqInst0");
  82. char *name1 = strdup("ReqInst1");
  83. char *name2 = strdup("ReqInst2");
  84. char *name3 = strdup("ReqInst3");
  85. char *name4 = strdup("ReqClass0");
  86. char *name5 = strdup("ReqClass1");
  87. char *name6 = strdup("ReqClass2");
  88. char *name7 = strdup("ReqClass3");
  89. char *attrname = strdup("T");
  90. char *attrvalue = strdup("i");
  91. objc_property_attribute_t attrs[] = {{attrname, attrvalue}};
  92. int attrcount = sizeof(attrs) / sizeof(attrs[0]);
  93. protocol_addProperty(proto, name0, attrs, attrcount, YES, YES);
  94. protocol_addProperty(proto, name1, attrs, attrcount, YES, YES);
  95. protocol_addProperty(proto, name2, attrs, attrcount, YES, YES);
  96. protocol_addProperty(proto, name3, attrs, attrcount, YES, YES);
  97. protocol_addProperty(proto, name4, attrs, attrcount, YES, NO);
  98. protocol_addProperty(proto, name5, attrs, attrcount, YES, NO);
  99. protocol_addProperty(proto, name6, attrs, attrcount, YES, NO);
  100. protocol_addProperty(proto, name7, attrs, attrcount, YES, NO);
  101. objc_registerProtocol(proto);
  102. testassert(0 == strcmp(protocol_getName(proto), "Proto1"));
  103. // Use of added protocols
  104. testassert(proto == objc_getProtocol("Proto1"));
  105. strcpy(name, "XXXXXX"); // name is copied
  106. testassert(0 == strcmp(protocol_getName(proto), "Proto1"));
  107. protolist = protocol_copyProtocolList(proto, &count);
  108. testassert(protolist);
  109. testassert(count == 3);
  110. // note this order is not required
  111. testassert(protolist[0] == @protocol(SuperProto) &&
  112. protolist[1] == @protocol(SuperProto2) &&
  113. protolist[2] == proto2);
  114. free(protolist);
  115. testassert(protocol_conformsToProtocol(proto, proto2));
  116. testassert(protocol_conformsToProtocol(proto, @protocol(SuperProto)));
  117. testassert(!protocol_conformsToProtocol(proto, @protocol(UnrelatedProto)));
  118. strcpy(types, "XX"); // types is copied
  119. desclist = protocol_copyMethodDescriptionList(proto, YES, YES, &count);
  120. testassert(desclist && count == 4);
  121. testprintf("%p %p\n", desclist[0].name, @selector(ReqInst0));
  122. // testassert(desclist[0].name == @selector(ReqInst0));
  123. testassert(0 == strcmp(desclist[0].types, "@:"));
  124. free(desclist);
  125. desclist = protocol_copyMethodDescriptionList(proto, YES, NO, &count);
  126. testassert(desclist && count == 4);
  127. testassert(desclist[1].name == @selector(ReqClas1));
  128. testassert(0 == strcmp(desclist[1].types, "@:"));
  129. free(desclist);
  130. desclist = protocol_copyMethodDescriptionList(proto, NO, YES, &count);
  131. testassert(desclist && count == 4);
  132. testassert(desclist[2].name == @selector(OptInst2));
  133. testassert(0 == strcmp(desclist[2].types, "@:"));
  134. free(desclist);
  135. desclist = protocol_copyMethodDescriptionList(proto, NO, NO, &count);
  136. testassert(desclist && count == 4);
  137. testassert(desclist[3].name == @selector(OptClas3));
  138. testassert(0 == strcmp(desclist[3].types, "@:"));
  139. free(desclist);
  140. strcpy(name0, "XXXXXXXX"); // name is copied
  141. strcpy(name1, "XXXXXXXX"); // name is copied
  142. strcpy(name2, "XXXXXXXX"); // name is copied
  143. strcpy(name3, "XXXXXXXX"); // name is copied
  144. strcpy(name4, "XXXXXXXXX"); // name is copied
  145. strcpy(name5, "XXXXXXXXX"); // name is copied
  146. strcpy(name6, "XXXXXXXXX"); // name is copied
  147. strcpy(name7, "XXXXXXXXX"); // name is copied
  148. strcpy(attrname, "X"); // description is copied
  149. strcpy(attrvalue, "X"); // description is copied
  150. memset(attrs, 'X', sizeof(attrs)); // description is copied
  151. // instance properties
  152. count = 100;
  153. proplist = protocol_copyPropertyList(proto, &count);
  154. testassert(proplist);
  155. testassert(count == 4);
  156. // note this order is not required
  157. testassert(0 == strcmp(property_getName(proplist[0]), "ReqInst0"));
  158. testassert(0 == strcmp(property_getName(proplist[1]), "ReqInst1"));
  159. testassert(0 == strcmp(property_getName(proplist[2]), "ReqInst2"));
  160. testassert(0 == strcmp(property_getName(proplist[3]), "ReqInst3"));
  161. testassert(0 == strcmp(property_getAttributes(proplist[0]), "Ti"));
  162. testassert(0 == strcmp(property_getAttributes(proplist[1]), "Ti"));
  163. testassert(0 == strcmp(property_getAttributes(proplist[2]), "Ti"));
  164. testassert(0 == strcmp(property_getAttributes(proplist[3]), "Ti"));
  165. free(proplist);
  166. // class properties
  167. count = 100;
  168. proplist = protocol_copyPropertyList2(proto, &count, YES, NO);
  169. testassert(proplist);
  170. testassert(count == 4);
  171. // note this order is not required
  172. testassert(0 == strcmp(property_getName(proplist[0]), "ReqClass0"));
  173. testassert(0 == strcmp(property_getName(proplist[1]), "ReqClass1"));
  174. testassert(0 == strcmp(property_getName(proplist[2]), "ReqClass2"));
  175. testassert(0 == strcmp(property_getName(proplist[3]), "ReqClass3"));
  176. testassert(0 == strcmp(property_getAttributes(proplist[0]), "Ti"));
  177. testassert(0 == strcmp(property_getAttributes(proplist[1]), "Ti"));
  178. testassert(0 == strcmp(property_getAttributes(proplist[2]), "Ti"));
  179. testassert(0 == strcmp(property_getAttributes(proplist[3]), "Ti"));
  180. free(proplist);
  181. testassert(proto2 == objc_getProtocol("EmptyProto"));
  182. testassert(0 == strcmp(protocol_getName(proto2), "EmptyProto"));
  183. protolist = protocol_copyProtocolList(proto2, &count);
  184. testassert(!protolist);
  185. testassert(count == 0);
  186. testassert(!protocol_conformsToProtocol(proto2, proto));
  187. testassert(!protocol_conformsToProtocol(proto2,@protocol(SuperProto)));
  188. testassert(!protocol_conformsToProtocol(proto2,@protocol(UnrelatedProto)));
  189. desclist = protocol_copyMethodDescriptionList(proto2, YES, YES, &count);
  190. testassert(!desclist && count == 0);
  191. desclist = protocol_copyMethodDescriptionList(proto2, YES, NO, &count);
  192. testassert(!desclist && count == 0);
  193. desclist = protocol_copyMethodDescriptionList(proto2, NO, YES, &count);
  194. testassert(!desclist && count == 0);
  195. desclist = protocol_copyMethodDescriptionList(proto2, NO, NO, &count);
  196. testassert(!desclist && count == 0);
  197. // Immutability of existing protocols
  198. objc_registerProtocol(proto);
  199. protocol_addProtocol(proto, @protocol(SuperProto2));
  200. protocol_addMethodDescription(proto, @selector(foo), "", YES, YES);
  201. objc_registerProtocol(@protocol(SuperProto));
  202. protocol_addProtocol(@protocol(SuperProto), @protocol(SuperProto2));
  203. protocol_addMethodDescription(@protocol(SuperProto), @selector(foo), "", YES, YES);
  204. // No duplicates
  205. proto = objc_allocateProtocol("SuperProto");
  206. testassert(!proto);
  207. proto = objc_allocateProtocol("Proto1");
  208. testassert(!proto);
  209. // NULL protocols ignored
  210. protocol_addProtocol((__bridge Protocol *)((void*)1), NULL);
  211. protocol_addProtocol(NULL, (__bridge Protocol *)((void*)1));
  212. protocol_addProtocol(NULL, NULL);
  213. protocol_addMethodDescription(NULL, @selector(foo), "", YES, YES);
  214. succeed(__FILE__);
  215. }