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