3 .*exchangeImp.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\](\n.* note: expanded from macro 'checkExchange')?
4 .*exchangeImp.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\](\n.* note: expanded from macro 'checkExchange')?
5 .*exchangeImp.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\](\n.* note: expanded from macro 'checkExchange')?
6 .*exchangeImp.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\](\n.* note: expanded from macro 'checkExchange')?
7 .*exchangeImp.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\](\n.* note: expanded from macro 'checkExchange')?
8 .*exchangeImp.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\](\n.* note: expanded from macro 'checkExchange')?
9 .*exchangeImp.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\](\n.* note: expanded from macro 'checkExchange')?
10 .*exchangeImp.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\](\n.* note: expanded from macro 'checkExchange')?
11 .*exchangeImp.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\](\n.* note: expanded from macro 'checkExchange')?
12 .*exchangeImp.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\](\n.* note: expanded from macro 'checkExchange')?
13 .*exchangeImp.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\](\n.* note: expanded from macro 'checkExchange')?
14 .*exchangeImp.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\](\n.* note: expanded from macro 'checkExchange')?
15 .*exchangeImp.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\](\n.* note: expanded from macro 'checkExchange')?
16 .*exchangeImp.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\](\n.* note: expanded from macro 'checkExchange')?
17 .*exchangeImp.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\](\n.* note: expanded from macro 'checkExchange')?
18 .*exchangeImp.m:\d+:\d+: warning: null passed to a callee that requires a non-null argument \[-Wnonnull\](\n.* note: expanded from macro 'checkExchange')?
24 #include <objc/runtime.h>
27 static int swizzleOld;
28 static int swizzleNew;
36 @interface Super : TestRoot @end
38 +(void) one { state = ONE; }
39 +(void) two { state = TWO; }
40 +(void) length { state = LENGTH; }
41 +(void) count { state = COUNT; }
43 -(void) swizzleTarget {
46 -(void) swizzleReplacement {
51 #define checkExchange(s1, v1, s2, v2) \
55 testprintf("Check unexchanged version\n"); \
58 testassert(state == v1); \
61 testassert(state == v2); \
63 testprintf("Exchange\n"); \
64 m1 = class_getClassMethod([Super class], @selector(s1)); \
65 m2 = class_getClassMethod([Super class], @selector(s2)); \
68 method_exchangeImplementations(m1, m2); \
70 testprintf("Check exchanged version\n"); \
73 testassert(state == v2); \
76 testassert(state == v1); \
78 testprintf("NULL should do nothing\n"); \
79 method_exchangeImplementations(m1, NULL); \
80 method_exchangeImplementations(NULL, m2); \
81 method_exchangeImplementations(NULL, NULL); \
83 testprintf("Make sure NULL did nothing\n"); \
86 testassert(state == v2); \
89 testassert(state == v1); \
91 testprintf("Put them back\n"); \
92 method_exchangeImplementations(m1, m2); \
94 testprintf("Check restored version\n"); \
97 testassert(state == v1); \
100 testassert(state == v2); \
111 - (void) swizzleTarget {
122 static IMP findInCache(Class cls, SEL sel)
124 struct objc_imp_cache_entry *ents;
128 ents = class_copyImpCache(cls, &count);
129 for (int i = 0; i < count; i++) {
130 if (ents[i].sel == sel) {
141 // Check ordinary selectors
142 checkExchange(one, ONE, two, TWO);
144 // Check vtable selectors
145 checkExchange(length, LENGTH, count, COUNT);
147 // Check ordinary<->vtable and vtable<->ordinary
148 checkExchange(count, COUNT, one, ONE);
149 checkExchange(two, TWO, length, LENGTH);
151 Super *s = [Super new];
156 // cache swizzleTarget in Super, A and B
158 testassert(swizzleOld == 1);
159 testassert(swizzleNew == 0);
160 testassert(swizzleB == 0);
161 testassert(findInCache([Super class], @selector(swizzleTarget)) != nil);
164 testassert(swizzleOld == 2);
165 testassert(swizzleNew == 0);
166 testassert(swizzleB == 0);
167 testassert(findInCache([A class], @selector(swizzleTarget)) != nil);
170 testassert(swizzleOld == 2);
171 testassert(swizzleNew == 0);
172 testassert(swizzleB == 1);
173 testassert(findInCache([B class], @selector(swizzleTarget)) != nil);
175 // prime C's cache too
177 testassert(findInCache([C class], @selector(hello)) != nil);
179 Method m1 = class_getInstanceMethod([Super class], @selector(swizzleTarget));
180 Method m2 = class_getInstanceMethod([Super class], @selector(swizzleReplacement));
181 method_exchangeImplementations(m1, m2);
183 // this should invalidate Super, A, but:
184 // - not B because it overrides - swizzleTarget and hence doesn't care
185 // - not C because it neither called swizzleTarget nor swizzleReplacement
186 testassert(findInCache([Super class], @selector(swizzleTarget)) == nil);
187 testassert(findInCache([A class], @selector(swizzleTarget)) == nil);
188 testassert(findInCache([B class], @selector(swizzleTarget)) != nil);
189 testassert(findInCache([C class], @selector(hello)) != nil);
191 // now check that all lookups do the right thing
193 testassert(swizzleOld == 2);
194 testassert(swizzleNew == 1);
195 testassert(swizzleB == 1);
198 testassert(swizzleOld == 2);
199 testassert(swizzleNew == 2);
200 testassert(swizzleB == 1);
203 testassert(swizzleOld == 2);
204 testassert(swizzleNew == 2);
205 testassert(swizzleB == 2);
208 testassert(swizzleOld == 2);
209 testassert(swizzleNew == 3);
210 testassert(swizzleB == 2);