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