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