1// TEST_CFLAGS -framework Foundation -Wno-deprecated-declarations
2// need Foundation to get NSObject compatibility additions for class Protocol
3// because ARC calls [protocol retain]
4
5#include "test.h"
6#include "testroot.i"
7#include <string.h>
8#include <objc/runtime.h>
9#include <objc/objc-internal.h>
10
11#if !__OBJC2__
12#include <objc/Protocol.h>
13#endif
14
15@protocol Proto1 
16+(id)proto1ClassMethod;
17-(id)proto1InstanceMethod;
18@end
19
20@protocol Proto2
21+(id)proto2ClassMethod;
22-(id)proto2InstanceMethod;
23@end
24
25@protocol Proto3 <Proto2>
26+(id)proto3ClassMethod;
27-(id)proto3InstanceMethod;
28@end
29
30@protocol Proto4
31@property int i;
32@end
33
34
35// Force some of Proto5's selectors out of address order rdar://10582325
36SEL fn(int x) { if (x) return @selector(m12:); else return @selector(m22:); }
37
38// This declaration order deliberately looks weird because it determines the 
39// selector address order on some architectures rdar://10582325
40@protocol Proto5
41-(id)m11:(id<Proto1>)a;
42-(void)m12:(id<Proto1>)a;
43-(int)m13:(id<Proto1>)a;
44+(void)m22:(TestRoot<Proto1>*)a;
45+(int)m23:(TestRoot<Proto1>*)a;
46+(TestRoot*)m21:(TestRoot<Proto1>*)a;
47@optional
48-(id(^)(id))m31:(id<Proto1>(^)(id<Proto1>))a;
49-(void)m32:(id<Proto1>(^)(id<Proto1>))a;
50-(int)m33:(id<Proto1>(^)(id<Proto1>))a;
51+(void)m42:(TestRoot<Proto1>*(^)(TestRoot<Proto1>*))a;
52+(int)m43:(TestRoot<Proto1>*(^)(TestRoot<Proto1>*))a;
53+(TestRoot*(^)(TestRoot*))m41:(TestRoot<Proto1>*(^)(TestRoot<Proto1>*))a;
54@end
55
56@protocol Proto6 <Proto5>
57@optional
58+(TestRoot*(^)(TestRoot*))n41:(TestRoot<Proto1>*(^)(TestRoot<Proto1>*))a;
59@end
60
61@protocol ProtoEmpty
62@end
63
64@interface Super : TestRoot <Proto1> @end
65@implementation Super
66+(id)proto1ClassMethod { return self; }
67-(id)proto1InstanceMethod { return self; }
68@end
69
70@interface SubNoProtocols : Super @end
71@implementation SubNoProtocols @end
72
73@interface SuperNoProtocols : TestRoot @end
74@implementation SuperNoProtocols
75@end
76
77@interface SubProp : Super <Proto4> { int i; } @end
78@implementation SubProp 
79@synthesize i;
80@end
81
82
83int main()
84{
85    Class cls;
86    Protocol * __unsafe_unretained *list;
87    Protocol *protocol, *empty;
88#if !__OBJC2__
89    struct objc_method_description *desc;
90#endif
91    struct objc_method_description desc2;
92    objc_property_t *proplist;
93    unsigned int count;
94
95    protocol = @protocol(Proto3);
96    empty = @protocol(ProtoEmpty);
97    testassert(protocol);
98    testassert(empty);
99
100#if !__OBJC2__
101    testassert([protocol isKindOf:[Protocol class]]);
102    testassert([empty isKindOf:[Protocol class]]);
103    testassert(0 == strcmp([protocol name], "Proto3"));
104    testassert(0 == strcmp([empty name], "ProtoEmpty"));
105#endif
106    testassert(0 == strcmp(protocol_getName(protocol), "Proto3"));
107    testassert(0 == strcmp(protocol_getName(empty), "ProtoEmpty"));
108
109    testassert(class_conformsToProtocol([Super class], @protocol(Proto1)));
110    testassert(!class_conformsToProtocol([SubProp class], @protocol(Proto1)));
111    testassert(class_conformsToProtocol([SubProp class], @protocol(Proto4)));
112    testassert(!class_conformsToProtocol([SubProp class], @protocol(Proto3)));
113    testassert(!class_conformsToProtocol([Super class], @protocol(Proto3)));
114
115    testassert(!protocol_conformsToProtocol(@protocol(Proto1), @protocol(Proto2)));
116    testassert(protocol_conformsToProtocol(@protocol(Proto3), @protocol(Proto2)));
117    testassert(!protocol_conformsToProtocol(@protocol(Proto2), @protocol(Proto3)));
118
119#if !__OBJC2__
120    testassert([@protocol(Proto1) isEqual:@protocol(Proto1)]);
121    testassert(! [@protocol(Proto1) isEqual:@protocol(Proto2)]);
122#endif
123    testassert(protocol_isEqual(@protocol(Proto1), @protocol(Proto1)));
124    testassert(! protocol_isEqual(@protocol(Proto1), @protocol(Proto2)));
125
126#if !__OBJC2__
127    desc = [protocol descriptionForInstanceMethod:@selector(proto3InstanceMethod)];
128    testassert(desc);
129    testassert(desc->name == @selector(proto3InstanceMethod));
130    desc = [protocol descriptionForClassMethod:@selector(proto3ClassMethod)];
131    testassert(desc);
132    testassert(desc->name == @selector(proto3ClassMethod));
133    desc = [protocol descriptionForClassMethod:@selector(proto2ClassMethod)];
134    testassert(desc);
135    testassert(desc->name == @selector(proto2ClassMethod));
136
137    desc = [protocol descriptionForInstanceMethod:@selector(proto3ClassMethod)];
138    testassert(!desc);
139    desc = [protocol descriptionForClassMethod:@selector(proto3InstanceMethod)];
140    testassert(!desc);    
141    desc = [empty descriptionForInstanceMethod:@selector(proto3ClassMethod)];
142    testassert(!desc);
143    desc = [empty descriptionForClassMethod:@selector(proto3InstanceMethod)];
144    testassert(!desc);    
145#endif
146    desc2 = protocol_getMethodDescription(protocol, @selector(proto3InstanceMethod), YES, YES);
147    testassert(desc2.name && desc2.types);
148    testassert(desc2.name == @selector(proto3InstanceMethod));
149    desc2 = protocol_getMethodDescription(protocol, @selector(proto3ClassMethod), YES, NO);
150    testassert(desc2.name && desc2.types);
151    testassert(desc2.name == @selector(proto3ClassMethod));
152    desc2 = protocol_getMethodDescription(protocol, @selector(proto2ClassMethod), YES, NO);
153    testassert(desc2.name && desc2.types);
154    testassert(desc2.name == @selector(proto2ClassMethod));
155
156    desc2 = protocol_getMethodDescription(protocol, @selector(proto3ClassMethod), YES, YES);
157    testassert(!desc2.name && !desc2.types);
158    desc2 = protocol_getMethodDescription(protocol, @selector(proto3InstanceMethod), YES, NO);
159    testassert(!desc2.name && !desc2.types);
160    desc2 = protocol_getMethodDescription(empty, @selector(proto3ClassMethod), YES, YES);
161    testassert(!desc2.name && !desc2.types);
162    desc2 = protocol_getMethodDescription(empty, @selector(proto3InstanceMethod), YES, NO);
163    testassert(!desc2.name && !desc2.types);
164
165    count = 100;
166    list = protocol_copyProtocolList(@protocol(Proto2), &count);
167    testassert(!list);
168    testassert(count == 0);
169    count = 100;
170    list = protocol_copyProtocolList(@protocol(Proto3), &count);
171    testassert(list);
172    testassert(count == 1);
173    testassert(protocol_isEqual(list[0], @protocol(Proto2)));
174    testassert(!list[1]);
175    free(list);    
176
177    count = 100;
178    cls = objc_getClass("Super");
179    testassert(cls);
180    list = class_copyProtocolList(cls, &count);
181    testassert(list);
182    testassert(list[count] == NULL);
183    testassert(count == 1);
184    testassert(0 == strcmp(protocol_getName(list[0]), "Proto1"));
185    free(list);
186
187    count = 100;
188    cls = objc_getClass("SuperNoProtocols");
189    testassert(cls);
190    list = class_copyProtocolList(cls, &count);
191    testassert(!list);
192    testassert(count == 0);
193
194    count = 100;
195    cls = objc_getClass("SubNoProtocols");
196    testassert(cls);
197    list = class_copyProtocolList(cls, &count);
198    testassert(!list);
199    testassert(count == 0);
200
201
202    cls = objc_getClass("SuperNoProtocols");
203    testassert(cls);
204    list = class_copyProtocolList(cls, NULL);
205    testassert(!list);
206
207    cls = objc_getClass("Super");
208    testassert(cls);
209    list = class_copyProtocolList(cls, NULL);
210    testassert(list);
211    free(list);
212
213    count = 100;
214    list = class_copyProtocolList(NULL, &count);
215    testassert(!list);
216    testassert(count == 0);
217
218
219    // Check property added by protocol
220    cls = objc_getClass("SubProp");
221    testassert(cls);
222
223    count = 100;
224    list = class_copyProtocolList(cls, &count);
225    testassert(list);
226    testassert(count == 1);
227    testassert(0 == strcmp(protocol_getName(list[0]), "Proto4"));
228    testassert(list[1] == NULL);
229    free(list);
230
231    count = 100;
232    proplist = class_copyPropertyList(cls, &count);
233    testassert(proplist);
234    testassert(count == 1);
235    testassert(0 == strcmp(property_getName(proplist[0]), "i"));
236    testassert(proplist[1] == NULL);
237    free(proplist);
238
239    // Check extended type encodings
240    testassert(_protocol_getMethodTypeEncoding(@protocol(Proto5), @selector(DoesNotExist), true, true) == NULL);
241    testassert(_protocol_getMethodTypeEncoding(NULL, @selector(m11), true, true) == NULL);
242    testassert(_protocol_getMethodTypeEncoding(@protocol(Proto5), @selector(m11), true, false) == NULL);
243    testassert(_protocol_getMethodTypeEncoding(@protocol(Proto5), @selector(m11), false, false) == NULL);
244    testassert(_protocol_getMethodTypeEncoding(@protocol(Proto5), @selector(m11), false, true) == NULL);
245    testassert(_protocol_getMethodTypeEncoding(@protocol(Proto5), @selector(m21), true, true) == NULL);
246#if __LP64__
247    const char *types11 = "@24@0:8@\"<Proto1>\"16";
248    const char *types12 = "v24@0:8@\"<Proto1>\"16";
249    const char *types13 = "i24@0:8@\"<Proto1>\"16";
250    const char *types21 = "@\"TestRoot\"24@0:8@\"TestRoot<Proto1>\"16";
251    const char *types22 = "v24@0:8@\"TestRoot<Proto1>\"16";
252    const char *types23 = "i24@0:8@\"TestRoot<Proto1>\"16";
253    const char *types31 = "@?<@@?@>24@0:8@?<@\"<Proto1>\"@?@\"<Proto1>\">16";
254    const char *types32 = "v24@0:8@?<@\"<Proto1>\"@?@\"<Proto1>\">16";
255    const char *types33 = "i24@0:8@?<@\"<Proto1>\"@?@\"<Proto1>\">16";
256    const char *types41 = "@?<@\"TestRoot\"@?@\"TestRoot\">24@0:8@?<@\"TestRoot<Proto1>\"@?@\"TestRoot<Proto1>\">16";
257    const char *types42 = "v24@0:8@?<@\"TestRoot<Proto1>\"@?@\"TestRoot<Proto1>\">16";
258    const char *types43 = "i24@0:8@?<@\"TestRoot<Proto1>\"@?@\"TestRoot<Proto1>\">16";
259#else
260    const char *types11 = "@12@0:4@\"<Proto1>\"8";
261    const char *types12 = "v12@0:4@\"<Proto1>\"8";
262    const char *types13 = "i12@0:4@\"<Proto1>\"8";
263    const char *types21 = "@\"TestRoot\"12@0:4@\"TestRoot<Proto1>\"8";
264    const char *types22 = "v12@0:4@\"TestRoot<Proto1>\"8";
265    const char *types23 = "i12@0:4@\"TestRoot<Proto1>\"8";
266    const char *types31 = "@?<@@?@>12@0:4@?<@\"<Proto1>\"@?@\"<Proto1>\">8";
267    const char *types32 = "v12@0:4@?<@\"<Proto1>\"@?@\"<Proto1>\">8";
268    const char *types33 = "i12@0:4@?<@\"<Proto1>\"@?@\"<Proto1>\">8";
269    const char *types41 = "@?<@\"TestRoot\"@?@\"TestRoot\">12@0:4@?<@\"TestRoot<Proto1>\"@?@\"TestRoot<Proto1>\">8";
270    const char *types42 = "v12@0:4@?<@\"TestRoot<Proto1>\"@?@\"TestRoot<Proto1>\">8";
271    const char *types43 = "i12@0:4@?<@\"TestRoot<Proto1>\"@?@\"TestRoot<Proto1>\">8";
272#endif
273
274    // Make sure some of Proto5's selectors are out of order rdar://10582325
275    // These comparisons deliberately look weird because they determine the 
276    // selector order on some architectures.
277    testassert(sel_registerName("m11:") > sel_registerName("m12:")  ||  
278               sel_registerName("m21:") > sel_registerName("m22:")  ||  
279               sel_registerName("m32:") < sel_registerName("m31:")  ||  
280               sel_registerName("m42:") < sel_registerName("m41:")  );
281
282    if (!_protocol_getMethodTypeEncoding(@protocol(Proto5), @selector(m11:), true, true)) {
283#if __clang__
284        testwarn("rdar://10492418 extended type encodings not present (is compiler old?)");
285#else
286        // extended type encodings quietly not supported
287        testwarn("rdar://10492418 extended type encodings not present (compiler is not clang?)");
288#endif
289    } else {
290        testassert(0 == strcmp(_protocol_getMethodTypeEncoding(@protocol(Proto5), @selector(m11:), true, true),   types11));
291        testassert(0 == strcmp(_protocol_getMethodTypeEncoding(@protocol(Proto5), @selector(m12:), true, true),   types12));
292        testassert(0 == strcmp(_protocol_getMethodTypeEncoding(@protocol(Proto5), @selector(m13:), true, true),   types13));
293        testassert(0 == strcmp(_protocol_getMethodTypeEncoding(@protocol(Proto5), @selector(m21:), true, false),  types21));
294        testassert(0 == strcmp(_protocol_getMethodTypeEncoding(@protocol(Proto5), @selector(m22:), true, false),  types22));
295        testassert(0 == strcmp(_protocol_getMethodTypeEncoding(@protocol(Proto5), @selector(m23:), true, false),  types23));
296        testassert(0 == strcmp(_protocol_getMethodTypeEncoding(@protocol(Proto5), @selector(m31:), false, true),  types31));
297        testassert(0 == strcmp(_protocol_getMethodTypeEncoding(@protocol(Proto5), @selector(m32:), false, true),  types32));
298        testassert(0 == strcmp(_protocol_getMethodTypeEncoding(@protocol(Proto5), @selector(m33:), false, true),  types33));
299        testassert(0 == strcmp(_protocol_getMethodTypeEncoding(@protocol(Proto5), @selector(m41:), false, false), types41));
300        testassert(0 == strcmp(_protocol_getMethodTypeEncoding(@protocol(Proto5), @selector(m42:), false, false), types42));
301        testassert(0 == strcmp(_protocol_getMethodTypeEncoding(@protocol(Proto5), @selector(m43:), false, false), types43));
302        
303        testassert(0 == strcmp(_protocol_getMethodTypeEncoding(@protocol(Proto6), @selector(n41:), false, false), types41));
304        testassert(0 == strcmp(_protocol_getMethodTypeEncoding(@protocol(Proto6), @selector(m41:), false, false), types41));
305    }
306
307    succeed(__FILE__);
308}
309