blob: 44d450a3101c7f10641c0ba71df885b74d80bd6a [file] [log] [blame]
Patrick Beardb2f68202012-04-06 18:12:22 +00001// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -fblocks -verify -Wno-objc-root-class %s
John McCallf85e1932011-06-15 23:02:42 +00002
3@interface Test0
4- (void) setBlock: (void(^)(void)) block;
5- (void) addBlock: (void(^)(void)) block;
6- (void) actNow;
7@end
8void test0(Test0 *x) {
9 [x setBlock: // expected-note {{block will be retained by the captured object}}
10 ^{ [x actNow]; }]; // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}}
11 x.block = // expected-note {{block will be retained by the captured object}}
12 ^{ [x actNow]; }; // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}}
13
14 [x addBlock: // expected-note {{block will be retained by the captured object}}
15 ^{ [x actNow]; }]; // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}}
16
17 // These actually don't cause retain cycles.
18 __weak Test0 *weakx = x;
19 [x addBlock: ^{ [weakx actNow]; }];
20 [x setBlock: ^{ [weakx actNow]; }];
21 x.block = ^{ [weakx actNow]; };
22
23 // These do cause retain cycles, but we're not clever enough to figure that out.
24 [weakx addBlock: ^{ [x actNow]; }];
25 [weakx setBlock: ^{ [x actNow]; }];
26 weakx.block = ^{ [x actNow]; };
Fariborz Jahanian7e2e4c32012-08-31 20:04:47 +000027
28 // rdar://11702054
29 x.block = ^{ (void)x.actNow; }; // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}} \
30 // expected-note {{block will be retained by the captured object}}
John McCallf85e1932011-06-15 23:02:42 +000031}
32
33@interface BlockOwner
Fariborz Jahanian528a4992011-09-14 18:03:46 +000034@property (retain) void (^strong)(void); // expected-warning {{retain'ed block property does not copy the block - use copy attribute instead}}
John McCallf85e1932011-06-15 23:02:42 +000035@end
36
37@interface Test1 {
38@public
39 BlockOwner *owner;
40};
41@property (retain) BlockOwner *owner;
42@property (assign) __strong BlockOwner *owner2; // expected-error {{unsafe_unretained property 'owner2' may not also be declared __strong}}
43@property (assign) BlockOwner *owner3;
44@end
45void test1(Test1 *x) {
46 x->owner.strong = ^{ (void) x; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
47 x.owner.strong = ^{ (void) x; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
48 x.owner2.strong = ^{ (void) x; };
49 x.owner3.strong = ^{ (void) x; };
50}
51
52@implementation Test1 {
53 BlockOwner * __unsafe_unretained owner3ivar;
54 __weak BlockOwner *weakowner;
55}
56@dynamic owner;
57@dynamic owner2;
58@synthesize owner3 = owner3ivar;
59
60- (id) init {
61 self.owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
62 self.owner2.strong = ^{ (void) owner; };
63
64 // TODO: should we warn here? What's the story with this kind of mismatch?
65 self.owner3.strong = ^{ (void) owner; };
66
67 owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
68
69 owner.strong = ^{ ^{ (void) owner; }(); }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
70
71 owner.strong = ^{ (void) sizeof(self); // expected-note {{block will be retained by an object strongly retained by the captured object}}
72 (void) owner; }; // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}}
73
74 weakowner.strong = ^{ (void) owner; };
75
76 return self;
77}
78- (void) foo {
79 owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
80}
81@end
82
83void test2_helper(id);
84@interface Test2 {
85 void (^block)(void);
86 id x;
87}
88@end
89@implementation Test2
90- (void) test {
91 block = ^{ // expected-note {{block will be retained by an object strongly retained by the captured object}}
92 test2_helper(x); // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}}
93 };
94}
95@end
Ted Kremenek968a0ee2011-12-01 00:59:21 +000096
97
98@interface NSOperationQueue {}
99- (void)addOperationWithBlock:(void (^)(void))block;
100- (void)addSomethingElse:(void (^)(void))block;
101
102@end
103
104@interface Test3 {
105 NSOperationQueue *myOperationQueue;
106 unsigned count;
107}
108@end
109void doSomething(unsigned v);
110@implementation Test3
111- (void) test {
112 // 'addOperationWithBlock:' is specifically whitelisted.
113 [myOperationQueue addOperationWithBlock:^() { // no-warning
114 if (count > 20) {
115 doSomething(count);
116 }
117 }];
118}
119- (void) test_positive {
120 // Sanity check that we are really whitelisting 'addOperationWithBlock:' and not doing
121 // something funny.
122 [myOperationQueue addSomethingElse:^() { // expected-note {{block will be retained by an object strongly retained by the captured object}}
123 if (count > 20) { // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}}
124 doSomething(count);
125 }
126 }];
127}
128@end
129