]> git.saurik.com Git - apple/objc4.git/blob - test/ignoredSelector.m
objc4-532.tar.gz
[apple/objc4.git] / test / ignoredSelector.m
1 // TEST_CONFIG MEM=mrc,gc
2 // TEST_CFLAGS -Wno-deprecated-declarations
3
4 #include "test.h"
5 #include <objc/runtime.h>
6 #include <objc/message.h>
7 #include <objc/objc-auto.h>
8
9 static int state = 0;
10
11 @interface Super { id isa; } @end
12 @implementation Super
13 +(id)class { return self; }
14 +(void)initialize { }
15
16 +(id)ordinary { state = 1; return self; }
17 +(id)ordinary2 { testassert(0); }
18 +(id)retain { state = 2; return self; }
19 +(void)release { state = 3; }
20 +(id)autorelease { state = 4; return self; }
21 +(void)dealloc { state = 5; }
22 +(uintptr_t)retainCount { state = 6; return 6; }
23 @end
24
25 @interface Sub : Super @end
26 @implementation Sub @end
27
28 @interface Sub2 : Super @end
29 @implementation Sub2 @end
30
31 @interface Empty { id isa; } @end
32 @implementation Empty
33 +(id)class { return self; }
34 +(void)initialize { }
35 +(id)forward:(SEL)sel :(marg_list)margs {
36 (void)sel; (void)margs;
37 state = 1;
38 return nil;
39 }
40 @end
41
42 @interface Empty (Unimplemented)
43 +(id)ordinary;
44 +(id)retain;
45 +(void)release;
46 +(id)autorelease;
47 +(void)dealloc;
48 +(uintptr_t)retainCount;
49 @end
50
51
52 #define getImp(sel) \
53 do { \
54 sel##Method = class_getClassMethod(cls, @selector(sel)); \
55 testassert(sel##Method); \
56 testassert(@selector(sel) == method_getName(sel##Method)); \
57 sel = method_getImplementation(sel##Method); \
58 } while (0)
59
60
61 static IMP ordinary, ordinary2, retain, release, autorelease, dealloc, retainCount;
62 static Method ordinaryMethod, ordinary2Method, retainMethod, releaseMethod, autoreleaseMethod, deallocMethod, retainCountMethod;
63
64 void cycle(Class cls)
65 {
66 id idVal;
67 uintptr_t intVal;
68
69 #if defined(__i386__)
70 if (objc_collectingEnabled()) {
71 // i386 GC: all ignored selectors are identical
72 testassert(@selector(retain) == @selector(release) &&
73 @selector(retain) == @selector(autorelease) &&
74 @selector(retain) == @selector(dealloc) &&
75 @selector(retain) == @selector(retainCount) );
76 }
77 else
78 #endif
79 {
80 // x86_64 GC or no GC: all ignored selectors are distinct
81 testassert(@selector(retain) != @selector(release) &&
82 @selector(retain) != @selector(autorelease) &&
83 @selector(retain) != @selector(dealloc) &&
84 @selector(retain) != @selector(retainCount) );
85 }
86
87 // no ignored selector matches a real selector
88 testassert(@selector(ordinary) != @selector(retain) &&
89 @selector(ordinary) != @selector(release) &&
90 @selector(ordinary) != @selector(autorelease) &&
91 @selector(ordinary) != @selector(dealloc) &&
92 @selector(ordinary) != @selector(retainCount) );
93
94 getImp(ordinary);
95 getImp(ordinary2);
96 getImp(retain);
97 getImp(release);
98 getImp(autorelease);
99 getImp(dealloc);
100 getImp(retainCount);
101
102 if (objc_collectingEnabled()) {
103 // GC: all ignored selector IMPs are identical
104 testassert(retain == release &&
105 retain == autorelease &&
106 retain == dealloc &&
107 retain == retainCount );
108 }
109 else {
110 // no GC: all ignored selector IMPs are distinct
111 testassert(retain != release &&
112 retain != autorelease &&
113 retain != dealloc &&
114 retain != retainCount );
115 }
116
117 // no ignored selector IMP matches a real selector IMP
118 testassert(ordinary != retain &&
119 ordinary != release &&
120 ordinary != autorelease &&
121 ordinary != dealloc &&
122 ordinary != retainCount );
123
124 // Test calls via method_invoke
125
126 idVal = ((id(*)(id, Method))method_invoke)(cls, ordinaryMethod);
127 testassert(state == 1);
128 testassert(idVal == cls);
129
130 state = 0;
131 idVal = ((id(*)(id, Method))method_invoke)(cls, retainMethod);
132 testassert(state == (objc_collectingEnabled() ? 0 : 2));
133 testassert(idVal == cls);
134
135 (void) ((void(*)(id, Method))method_invoke)(cls, releaseMethod);
136 testassert(state == (objc_collectingEnabled() ? 0 : 3));
137
138 idVal = ((id(*)(id, Method))method_invoke)(cls, autoreleaseMethod);
139 testassert(state == (objc_collectingEnabled() ? 0 : 4));
140 testassert(idVal == cls);
141
142 (void) ((void(*)(id, Method))method_invoke)(cls, deallocMethod);
143 testassert(state == (objc_collectingEnabled() ? 0 : 5));
144
145 intVal = ((uintptr_t(*)(id, Method))method_invoke)(cls, retainCountMethod);
146 testassert(state == (objc_collectingEnabled() ? 0 : 6));
147 testassert(intVal == (objc_collectingEnabled() ? (uintptr_t)cls : 6));
148
149
150 // Test calls via compiled objc_msgSend
151
152 state = 0;
153 idVal = [cls ordinary];
154 testassert(state == 1);
155 testassert(idVal == cls);
156
157 state = 0;
158 idVal = [cls retain];
159 testassert(state == (objc_collectingEnabled() ? 0 : 2));
160 testassert(idVal == cls);
161
162 (void) [cls release];
163 testassert(state == (objc_collectingEnabled() ? 0 : 3));
164
165 idVal = [cls autorelease];
166 testassert(state == (objc_collectingEnabled() ? 0 : 4));
167 testassert(idVal == cls);
168
169 (void) [cls dealloc];
170 testassert(state == (objc_collectingEnabled() ? 0 : 5));
171
172 intVal = [cls retainCount];
173 testassert(state == (objc_collectingEnabled() ? 0 : 6));
174 testassert(intVal == (objc_collectingEnabled() ? (uintptr_t)cls : 6));
175
176 // Test calls via handwritten objc_msgSend
177
178 state = 0;
179 idVal = ((id(*)(id,SEL))objc_msgSend)(cls, @selector(ordinary));
180 testassert(state == 1);
181 testassert(idVal == cls);
182
183 state = 0;
184 idVal = ((id(*)(id,SEL))objc_msgSend)(cls, @selector(retain));
185 testassert(state == (objc_collectingEnabled() ? 0 : 2));
186 testassert(idVal == cls);
187
188 (void) ((void(*)(id,SEL))objc_msgSend)(cls, @selector(release));
189 testassert(state == (objc_collectingEnabled() ? 0 : 3));
190
191 idVal = ((id(*)(id,SEL))objc_msgSend)(cls, @selector(autorelease));
192 testassert(state == (objc_collectingEnabled() ? 0 : 4));
193 testassert(idVal == cls);
194
195 (void) ((void(*)(id,SEL))objc_msgSend)(cls, @selector(dealloc));
196 testassert(state == (objc_collectingEnabled() ? 0 : 5));
197
198 intVal = ((uintptr_t(*)(id,SEL))objc_msgSend)(cls, @selector(retainCount));
199 testassert(state == (objc_collectingEnabled() ? 0 : 6));
200 testassert(intVal == (objc_collectingEnabled() ? (uintptr_t)cls : 6));
201 }
202
203 int main()
204 {
205 Class cls;
206
207 // Test selector API
208
209 testassert(sel_registerName("retain") == @selector(retain));
210 testassert(sel_getUid("retain") == @selector(retain));
211 #if defined(__i386__)
212 if (objc_collectingEnabled()) {
213 // only i386's GC currently remaps these
214 testassert(0 == strcmp(sel_getName(@selector(retain)), "<ignored selector>"));
215 } else
216 #endif
217 {
218 testassert(0 == strcmp(sel_getName(@selector(retain)), "retain"));
219 }
220 #if !__OBJC2__
221 testassert(sel_isMapped(@selector(retain)));
222 #endif
223
224 cls = [Sub class];
225 testassert(cls);
226 cycle(cls);
227
228 cls = [Super class];
229 testassert(cls);
230 cycle(cls);
231
232 if (objc_collectingEnabled()) {
233 // rdar://6200570 Method manipulation shouldn't affect ignored methods.
234
235 cls = [Super class];
236 testassert(cls);
237 cycle(cls);
238
239 method_setImplementation(retainMethod, (IMP)1);
240 method_setImplementation(releaseMethod, (IMP)1);
241 method_setImplementation(autoreleaseMethod, (IMP)1);
242 method_setImplementation(deallocMethod, (IMP)1);
243 method_setImplementation(retainCountMethod, (IMP)1);
244 cycle(cls);
245
246 testassert(ordinary2 != retainCount);
247 method_exchangeImplementations(retainMethod, autoreleaseMethod);
248 method_exchangeImplementations(deallocMethod, releaseMethod);
249 method_exchangeImplementations(retainCountMethod, ordinary2Method);
250 cycle(cls);
251 // ordinary2 exchanged with ignored method is now ignored too
252 testassert(ordinary2 == retainCount);
253
254 // replace == replace existing
255 class_replaceMethod(cls, @selector(retain), (IMP)1, "");
256 class_replaceMethod(cls, @selector(release), (IMP)1, "");
257 class_replaceMethod(cls, @selector(autorelease), (IMP)1, "");
258 class_replaceMethod(cls, @selector(dealloc), (IMP)1, "");
259 class_replaceMethod(cls, @selector(retainCount), (IMP)1, "");
260 cycle(cls);
261
262 cls = [Sub class];
263 testassert(cls);
264 cycle(cls);
265
266 // replace == add override
267 class_replaceMethod(cls, @selector(retain), (IMP)1, "");
268 class_replaceMethod(cls, @selector(release), (IMP)1, "");
269 class_replaceMethod(cls, @selector(autorelease), (IMP)1, "");
270 class_replaceMethod(cls, @selector(dealloc), (IMP)1, "");
271 class_replaceMethod(cls, @selector(retainCount), (IMP)1, "");
272 cycle(cls);
273
274 cls = [Sub2 class];
275 testassert(cls);
276 cycle(cls);
277
278 class_addMethod(cls, @selector(retain), (IMP)1, "");
279 class_addMethod(cls, @selector(release), (IMP)1, "");
280 class_addMethod(cls, @selector(autorelease), (IMP)1, "");
281 class_addMethod(cls, @selector(dealloc), (IMP)1, "");
282 class_addMethod(cls, @selector(retainCount), (IMP)1, "");
283 cycle(cls);
284 }
285
286 // Test calls via objc_msgSend - ignored selectors are ignored
287 // under GC even if the class provides no implementation for them
288 if (objc_collectingEnabled()) {
289 Class cls;
290 id idVal;
291 uintptr_t intVal;
292
293 cls = [Empty class];
294 state = 0;
295
296 idVal = [Empty retain];
297 testassert(state == 0);
298 testassert(idVal == cls);
299
300 (void) [Empty release];
301 testassert(state == 0);
302
303 idVal = [Empty autorelease];
304 testassert(state == 0);
305 testassert(idVal == cls);
306
307 (void) [Empty dealloc];
308 testassert(state == 0);
309
310 intVal = [Empty retainCount];
311 testassert(state == 0);
312 testassert(intVal == (uintptr_t)cls);
313
314 idVal = [Empty ordinary];
315 testassert(state == 1);
316 testassert(idVal == nil);
317
318 state = 0;
319
320 idVal = ((id(*)(id,SEL))objc_msgSend)(cls, @selector(retain));
321 testassert(state == 0);
322 testassert(idVal == cls);
323
324 (void) ((void(*)(id,SEL))objc_msgSend)(cls, @selector(release));
325 testassert(state == 0);
326
327 idVal = ((id(*)(id,SEL))objc_msgSend)(cls, @selector(autorelease));
328 testassert(state == 0);
329 testassert(idVal == cls);
330
331 (void) ((void(*)(id,SEL))objc_msgSend)(cls, @selector(dealloc));
332 testassert(state == 0);
333
334 intVal = ((uintptr_t(*)(id,SEL))objc_msgSend)(cls, @selector(retainCount));
335 testassert(state == 0);
336 testassert(intVal == (uintptr_t)cls);
337
338 idVal = ((id(*)(id,SEL))objc_msgSend)(cls, @selector(ordinary));
339 testassert(state == 1);
340 testassert(idVal == nil);
341 }
342
343 succeed(__FILE__);
344 }