1 | // RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -fblocks -Wno-objc-root-class -std=c++14 -Warc-repeated-use-of-weak -verify %s |
2 | // RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-weak -fblocks -Wno-objc-root-class -std=c++14 -Warc-repeated-use-of-weak -verify %s |
3 | |
4 | @interface Test { |
5 | @public |
6 | Test *ivar; |
7 | __weak id weakIvar; |
8 | } |
9 | @property(weak) Test *weakProp; |
10 | @property(strong) Test *strongProp; |
11 | |
12 | - (__weak id)implicitProp; |
13 | |
14 | + (__weak id)weakProp; |
15 | @end |
16 | |
17 | extern void use(id); |
18 | extern id get(); |
19 | extern bool condition(); |
20 | #define nil ((id)0) |
21 | |
22 | void sanity(Test *a) { |
23 | use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times in this function but may be unpredictably set to nil; assign to a strong variable to keep the object alive}} |
24 | use(a.weakProp); // expected-note{{also accessed here}} |
25 | |
26 | use(a.strongProp); |
27 | use(a.strongProp); // no-warning |
28 | |
29 | use(a.weakProp); // expected-note{{also accessed here}} |
30 | } |
31 | |
32 | void singleUse(Test *a) { |
33 | use(a.weakProp); // no-warning |
34 | use(a.strongProp); // no-warning |
35 | } |
36 | |
37 | void assignsOnly(Test *a) { |
38 | a.weakProp = get(); // no-warning |
39 | |
40 | id next = get(); |
41 | if (next) |
42 | a.weakProp = next; // no-warning |
43 | |
44 | a->weakIvar = get(); // no-warning |
45 | next = get(); |
46 | if (next) |
47 | a->weakIvar = next; // no-warning |
48 | |
49 | extern __weak id x; |
50 | x = get(); // no-warning |
51 | next = get(); |
52 | if (next) |
53 | x = next; // no-warning |
54 | } |
55 | |
56 | void assignThenRead(Test *a) { |
57 | a.weakProp = get(); // expected-note{{also accessed here}} |
58 | use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}} |
59 | } |
60 | |
61 | void twoVariables(Test *a, Test *b) { |
62 | use(a.weakProp); // no-warning |
63 | use(b.weakProp); // no-warning |
64 | } |
65 | |
66 | void doubleLevelAccess(Test *a) { |
67 | use(a.strongProp.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times in this function and may be unpredictably set to nil; assign to a strong variable to keep the object alive}} |
68 | use(a.strongProp.weakProp); // expected-note{{also accessed here}} |
69 | } |
70 | |
71 | void doubleLevelAccessIvar(Test *a) { |
72 | use(a.strongProp.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times}} |
73 | use(a.strongProp.weakProp); // expected-note{{also accessed here}} |
74 | } |
75 | |
76 | void implicitProperties(Test *a) { |
77 | use(a.implicitProp); // expected-warning{{weak implicit property 'implicitProp' is accessed multiple times}} |
78 | use(a.implicitProp); // expected-note{{also accessed here}} |
79 | } |
80 | |
81 | void classProperties() { |
82 | use(Test.weakProp); // expected-warning{{weak implicit property 'weakProp' is accessed multiple times}} |
83 | use(Test.weakProp); // expected-note{{also accessed here}} |
84 | } |
85 | |
86 | void classPropertiesAreDifferent(Test *a) { |
87 | use(Test.weakProp); // no-warning |
88 | use(a.weakProp); // no-warning |
89 | use(a.strongProp.weakProp); // no-warning |
90 | } |
91 | |
92 | void ivars(Test *a) { |
93 | use(a->weakIvar); // expected-warning{{weak instance variable 'weakIvar' is accessed multiple times}} |
94 | use(a->weakIvar); // expected-note{{also accessed here}} |
95 | } |
96 | |
97 | void globals() { |
98 | extern __weak id a; |
99 | use(a); // expected-warning{{weak variable 'a' is accessed multiple times}} |
100 | use(a); // expected-note{{also accessed here}} |
101 | } |
102 | |
103 | void messageGetter(Test *a) { |
104 | use([a weakProp]); // expected-warning{{weak property 'weakProp' is accessed multiple times}} |
105 | use([a weakProp]); // expected-note{{also accessed here}} |
106 | } |
107 | |
108 | void messageSetter(Test *a) { |
109 | [a setWeakProp:get()]; // no-warning |
110 | [a setWeakProp:get()]; // no-warning |
111 | } |
112 | |
113 | void messageSetterAndGetter(Test *a) { |
114 | [a setWeakProp:get()]; // expected-note{{also accessed here}} |
115 | use([a weakProp]); // expected-warning{{weak property 'weakProp' is accessed multiple times}} |
116 | } |
117 | |
118 | void mixDotAndMessageSend(Test *a, Test *b) { |
119 | use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}} |
120 | use([a weakProp]); // expected-note{{also accessed here}} |
121 | |
122 | use([b weakProp]); // expected-warning{{weak property 'weakProp' is accessed multiple times}} |
123 | use(b.weakProp); // expected-note{{also accessed here}} |
124 | } |
125 | |
126 | |
127 | void assignToStrongWrongInit(Test *a) { |
128 | id val = a.weakProp; // expected-note{{also accessed here}} |
129 | use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}} |
130 | } |
131 | |
132 | void assignToStrongWrong(Test *a) { |
133 | id val; |
134 | val = a.weakProp; // expected-note{{also accessed here}} |
135 | use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}} |
136 | } |
137 | |
138 | void assignToIvarWrong(Test *a) { |
139 | a->weakIvar = get(); // expected-note{{also accessed here}} |
140 | use(a->weakIvar); // expected-warning{{weak instance variable 'weakIvar' is accessed multiple times}} |
141 | } |
142 | |
143 | void assignToGlobalWrong() { |
144 | extern __weak id a; |
145 | a = get(); // expected-note{{also accessed here}} |
146 | use(a); // expected-warning{{weak variable 'a' is accessed multiple times}} |
147 | } |
148 | |
149 | void assignToStrongOK(Test *a) { |
150 | if (condition()) { |
151 | id val = a.weakProp; // no-warning |
152 | (void)val; |
153 | } else { |
154 | id val; |
155 | val = a.weakProp; // no-warning |
156 | (void)val; |
157 | } |
158 | } |
159 | |
160 | void assignToStrongConditional(Test *a) { |
161 | id val = (condition() ? a.weakProp : a.weakProp); // no-warning |
162 | id val2 = a.implicitProp ?: a.implicitProp; // no-warning |
163 | } |
164 | |
165 | void testBlock(Test *a) { |
166 | use(a.weakProp); // no-warning |
167 | |
168 | use(^{ |
169 | use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times in this block}} |
170 | use(a.weakProp); // expected-note{{also accessed here}} |
171 | }); |
172 | } |
173 | |
174 | void assignToStrongWithCasts(Test *a) { |
175 | if (condition()) { |
176 | Test *val = (Test *)a.weakProp; // no-warning |
177 | (void)val; |
178 | } else { |
179 | id val; |
180 | val = (Test *)a.weakProp; // no-warning |
181 | (void)val; |
182 | } |
183 | } |
184 | |
185 | void assignToStrongWithMessages(Test *a) { |
186 | if (condition()) { |
187 | id val = [a weakProp]; // no-warning |
188 | (void)val; |
189 | } else { |
190 | id val; |
191 | val = [a weakProp]; // no-warning |
192 | (void)val; |
193 | } |
194 | } |
195 | |
196 | |
197 | void assignAfterRead(Test *a) { |
198 | // Special exception for a single read before any writes. |
199 | if (!a.weakProp) // no-warning |
200 | a.weakProp = get(); // no-warning |
201 | } |
202 | |
203 | void readOnceWriteMany(Test *a) { |
204 | if (!a.weakProp) { // no-warning |
205 | a.weakProp = get(); // no-warning |
206 | a.weakProp = get(); // no-warning |
207 | } |
208 | } |
209 | |
210 | void readOnceAfterWrite(Test *a) { |
211 | a.weakProp = get(); // expected-note{{also accessed here}} |
212 | if (!a.weakProp) { // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}} |
213 | a.weakProp = get(); // expected-note{{also accessed here}} |
214 | } |
215 | } |
216 | |
217 | void readOnceWriteManyLoops(Test *a, Test *b, Test *c, Test *d, Test *e) { |
218 | while (condition()) { |
219 | if (!a.weakProp) { // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}} |
220 | a.weakProp = get(); // expected-note{{also accessed here}} |
221 | a.weakProp = get(); // expected-note{{also accessed here}} |
222 | } |
223 | } |
224 | |
225 | do { |
226 | if (!b.weakProp) { // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}} |
227 | b.weakProp = get(); // expected-note{{also accessed here}} |
228 | b.weakProp = get(); // expected-note{{also accessed here}} |
229 | } |
230 | } while (condition()); |
231 | |
232 | for (id x = get(); x; x = get()) { |
233 | if (!c.weakProp) { // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}} |
234 | c.weakProp = get(); // expected-note{{also accessed here}} |
235 | c.weakProp = get(); // expected-note{{also accessed here}} |
236 | } |
237 | } |
238 | |
239 | for (id x in get()) { |
240 | if (!d.weakProp) { // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}} |
241 | d.weakProp = get(); // expected-note{{also accessed here}} |
242 | d.weakProp = get(); // expected-note{{also accessed here}} |
243 | } |
244 | } |
245 | |
246 | int array[] = { 1, 2, 3 }; |
247 | for (int i : array) { |
248 | if (!e.weakProp) { // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}} |
249 | e.weakProp = get(); // expected-note{{also accessed here}} |
250 | e.weakProp = get(); // expected-note{{also accessed here}} |
251 | } |
252 | } |
253 | } |
254 | |
255 | void readOnlyLoop(Test *a) { |
256 | while (condition()) { |
257 | use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}} |
258 | } |
259 | } |
260 | |
261 | void readInIterationLoop() { |
262 | for (Test *a in get()) |
263 | use(a.weakProp); // no-warning |
264 | } |
265 | |
266 | void readDoubleLevelAccessInLoop() { |
267 | for (Test *a in get()) { |
268 | use(a.strongProp.weakProp); // no-warning |
269 | } |
270 | } |
271 | |
272 | void readParameterInLoop(Test *a) { |
273 | for (id unused in get()) { |
274 | use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}} |
275 | (void)unused; |
276 | } |
277 | } |
278 | |
279 | void readGlobalInLoop() { |
280 | static __weak id a; |
281 | for (id unused in get()) { |
282 | use(a); // expected-warning{{weak variable 'a' is accessed multiple times in this function}} |
283 | (void)unused; |
284 | } |
285 | } |
286 | |
287 | void doWhileLoop(Test *a) { |
288 | do { |
289 | use(a.weakProp); // no-warning |
290 | } while(0); |
291 | } |
292 | |
293 | |
294 | @interface Test (Methods) |
295 | @end |
296 | |
297 | @implementation Test (Methods) |
298 | - (void)sanity { |
299 | use(self.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times in this method but may be unpredictably set to nil; assign to a strong variable to keep the object alive}} |
300 | use(self.weakProp); // expected-note{{also accessed here}} |
301 | } |
302 | |
303 | - (void)ivars { |
304 | use(weakIvar); // expected-warning{{weak instance variable 'weakIvar' is accessed multiple times in this method but may be unpredictably set to nil; assign to a strong variable to keep the object alive}} |
305 | use(weakIvar); // expected-note{{also accessed here}} |
306 | } |
307 | |
308 | - (void)doubleLevelAccessForSelf { |
309 | use(self.strongProp.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}} |
310 | use(self.strongProp.weakProp); // expected-note{{also accessed here}} |
311 | |
312 | use(self->ivar.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}} |
313 | use(self->ivar.weakProp); // expected-note{{also accessed here}} |
314 | |
315 | use(self->ivar->weakIvar); // expected-warning{{weak instance variable 'weakIvar' is accessed multiple times}} |
316 | use(self->ivar->weakIvar); // expected-note{{also accessed here}} |
317 | } |
318 | |
319 | - (void)distinctFromOther:(Test *)other { |
320 | use(self.strongProp.weakProp); // no-warning |
321 | use(other.strongProp.weakProp); // no-warning |
322 | |
323 | use(self->ivar.weakProp); // no-warning |
324 | use(other->ivar.weakProp); // no-warning |
325 | |
326 | use(self.strongProp->weakIvar); // no-warning |
327 | use(other.strongProp->weakIvar); // no-warning |
328 | } |
329 | @end |
330 | |
331 | @interface Base1 |
332 | @end |
333 | @interface Sub1 : Base1 |
334 | @end |
335 | @interface Sub1(cat) |
336 | -(id)prop; |
337 | @end |
338 | |
339 | void test1(Sub1 *s) { |
340 | use([s prop]); |
341 | use([s prop]); |
342 | } |
343 | |
344 | @interface Base1(cat) |
345 | @property (weak) id prop; |
346 | @end |
347 | |
348 | void test2(Sub1 *s) { |
349 | // This does not warn because the "prop" in "Base1(cat)" was introduced |
350 | // after the method declaration and we don't find it as overridden. |
351 | // Always looking for overridden methods after the method declaration is expensive |
352 | // and it's not clear it is worth it currently. |
353 | use([s prop]); |
354 | use([s prop]); |
355 | } |
356 | |
357 | |
358 | class Wrapper { |
359 | Test *a; |
360 | |
361 | public: |
362 | void fields() { |
363 | use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times in this function but may be unpredictably set to nil; assign to a strong variable to keep the object alive}} |
364 | use(a.weakProp); // expected-note{{also accessed here}} |
365 | } |
366 | |
367 | void distinctFromOther(Test *b, const Wrapper &w) { |
368 | use(a.weakProp); // no-warning |
369 | use(b.weakProp); // no-warning |
370 | use(w.a.weakProp); // no-warning |
371 | } |
372 | |
373 | static void doubleLevelAccessField(const Wrapper &x, const Wrapper &y) { |
374 | use(x.a.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times}} |
375 | use(y.a.weakProp); // expected-note{{also accessed here}} |
376 | } |
377 | }; |
378 | |
379 | |
380 | // ----------------------- |
381 | // False positives |
382 | // ----------------------- |
383 | |
384 | // Most of these would require flow-sensitive analysis to silence correctly. |
385 | |
386 | void assignNil(Test *a) { |
387 | if (condition()) |
388 | a.weakProp = nil; // expected-note{{also accessed here}} |
389 | |
390 | use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}} |
391 | } |
392 | |
393 | void branch(Test *a) { |
394 | if (condition()) |
395 | use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}} |
396 | else |
397 | use(a.weakProp); // expected-note{{also accessed here}} |
398 | } |
399 | |
400 | void doubleLevelAccess(Test *a, Test *b) { |
401 | use(a.strongProp.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times}} |
402 | use(b.strongProp.weakProp); // expected-note{{also accessed here}} |
403 | |
404 | use(a.weakProp.weakProp); // no-warning |
405 | } |
406 | |
407 | void doubleLevelAccessIvar(Test *a, Test *b) { |
408 | use(a->ivar.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times}} |
409 | use(b->ivar.weakProp); // expected-note{{also accessed here}} |
410 | |
411 | use(a.strongProp.weakProp); // no-warning |
412 | } |
413 | |
414 | // rdar://13942025 |
415 | @interface X |
416 | @end |
417 | |
418 | @implementation X |
419 | - (int) warningAboutWeakVariableInsideTypeof { |
420 | __typeof__(self) __weak weakSelf = self; |
421 | ^(){ |
422 | __typeof__(weakSelf) blockSelf = weakSelf; |
423 | use(blockSelf); |
424 | }(); |
425 | return sizeof(weakSelf); |
426 | } |
427 | @end |
428 | |
429 | // rdar://19053620 |
430 | @interface NSNull |
431 | + (NSNull *)null; |
432 | @end |
433 | |
434 | @interface INTF @end |
435 | |
436 | @implementation INTF |
437 | - (void) Meth : (id) data |
438 | { |
439 | data = data ?: NSNull.null; |
440 | } |
441 | @end |
442 | |
443 | // This used to crash in WeakObjectProfileTy::getBaseInfo when getBase() was |
444 | // called on an ObjCPropertyRefExpr object whose receiver was an interface. |
445 | |
446 | @class NSString; |
447 | @interface NSBundle |
448 | +(NSBundle *)foo; |
449 | @property (class, strong) NSBundle *foo2; |
450 | @property (strong) NSString *prop; |
451 | @property(weak) NSString *weakProp; |
452 | @end |
453 | |
454 | @interface NSBundle2 : NSBundle |
455 | @end |
456 | |
457 | void foo() { |
458 | NSString * t = NSBundle.foo.prop; |
459 | use(NSBundle.foo.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times}} |
460 | use(NSBundle2.foo.weakProp); // expected-note{{also accessed here}} |
461 | |
462 | NSString * t2 = NSBundle.foo2.prop; |
463 | use(NSBundle.foo2.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times}} |
464 | use(NSBundle2.foo2.weakProp); // expected-note{{also accessed here}} |
465 | decltype([NSBundle2.foo2 weakProp]) t3; |
466 | decltype(NSBundle2.foo2.weakProp) t4; |
467 | __typeof__(NSBundle2.foo2.weakProp) t5; |
468 | } |
469 | |
470 | void testAuto() { |
471 | auto __weak wp = NSBundle2.foo2.weakProp; |
472 | } |
473 | |
474 | void testLambdaCaptureInit() { |
475 | [capture(NSBundle2.foo2.weakProp)] {} (); |
476 | } |
477 | |
478 | void testAutoNew() { |
479 | auto p = new auto(NSBundle2.foo2.weakProp); |
480 | } |
481 | |
482 | // This used to crash in the constructor of WeakObjectProfileTy when a |
483 | // DeclRefExpr was passed that didn't reference a VarDecl. |
484 | |
485 | typedef INTF * INTFPtrTy; |
486 | |
487 | enum E { |
488 | e1 |
489 | }; |
490 | |
491 | void foo1() { |
492 | INTFPtrTy tmp = (INTFPtrTy)e1; |
493 | #if __has_feature(objc_arc) |
494 | // expected-error@-2{{cast of 'E' to 'INTFPtrTy' (aka 'INTF *') is disallowed with ARC}} |
495 | #endif |
496 | } |
497 | |
498 | @class NSString; |
499 | static NSString* const kGlobal = @""; |
500 | |