blob: eb4e966c772665ba53d74a095035aad50d009f78 [file] [log] [blame]
Fariborz Jahanian3f001ff2012-10-03 17:55:29 +00001// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -fblocks -verify -Wno-objc-root-class -Wno-implicit-retain-self %s
John McCallf85e1932011-06-15 23:02:42 +00002
Jordan Rose1fac58a2012-09-17 17:54:30 +00003void *_Block_copy(const void *block);
4
John McCallf85e1932011-06-15 23:02:42 +00005@interface Test0
6- (void) setBlock: (void(^)(void)) block;
7- (void) addBlock: (void(^)(void)) block;
8- (void) actNow;
9@end
10void test0(Test0 *x) {
11 [x setBlock: // 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 x.block = // expected-note {{block will be retained by the captured object}}
14 ^{ [x actNow]; }; // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}}
15
16 [x addBlock: // expected-note {{block will be retained by the captured object}}
17 ^{ [x actNow]; }]; // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}}
18
19 // These actually don't cause retain cycles.
20 __weak Test0 *weakx = x;
21 [x addBlock: ^{ [weakx actNow]; }];
22 [x setBlock: ^{ [weakx actNow]; }];
23 x.block = ^{ [weakx actNow]; };
24
25 // These do cause retain cycles, but we're not clever enough to figure that out.
26 [weakx addBlock: ^{ [x actNow]; }];
27 [weakx setBlock: ^{ [x actNow]; }];
28 weakx.block = ^{ [x actNow]; };
Fariborz Jahanian7e2e4c32012-08-31 20:04:47 +000029
30 // rdar://11702054
31 x.block = ^{ (void)x.actNow; }; // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}} \
32 // expected-note {{block will be retained by the captured object}}
John McCallf85e1932011-06-15 23:02:42 +000033}
34
35@interface BlockOwner
Fariborz Jahanian528a4992011-09-14 18:03:46 +000036@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 +000037@end
38
39@interface Test1 {
40@public
41 BlockOwner *owner;
42};
43@property (retain) BlockOwner *owner;
44@property (assign) __strong BlockOwner *owner2; // expected-error {{unsafe_unretained property 'owner2' may not also be declared __strong}}
45@property (assign) BlockOwner *owner3;
46@end
47void test1(Test1 *x) {
48 x->owner.strong = ^{ (void) x; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
49 x.owner.strong = ^{ (void) x; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
50 x.owner2.strong = ^{ (void) x; };
51 x.owner3.strong = ^{ (void) x; };
52}
53
54@implementation Test1 {
55 BlockOwner * __unsafe_unretained owner3ivar;
56 __weak BlockOwner *weakowner;
57}
58@dynamic owner;
59@dynamic owner2;
60@synthesize owner3 = owner3ivar;
61
62- (id) init {
63 self.owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
64 self.owner2.strong = ^{ (void) owner; };
65
66 // TODO: should we warn here? What's the story with this kind of mismatch?
67 self.owner3.strong = ^{ (void) owner; };
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) owner; }(); }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
72
73 owner.strong = ^{ (void) sizeof(self); // expected-note {{block will be retained by an object strongly retained by the captured object}}
74 (void) owner; }; // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}}
75
76 weakowner.strong = ^{ (void) owner; };
77
78 return self;
79}
80- (void) foo {
81 owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
82}
83@end
84
85void test2_helper(id);
86@interface Test2 {
87 void (^block)(void);
88 id x;
89}
90@end
91@implementation Test2
92- (void) test {
93 block = ^{ // expected-note {{block will be retained by an object strongly retained by the captured object}}
94 test2_helper(x); // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}}
95 };
96}
97@end
Ted Kremenek968a0ee2011-12-01 00:59:21 +000098
99
100@interface NSOperationQueue {}
101- (void)addOperationWithBlock:(void (^)(void))block;
102- (void)addSomethingElse:(void (^)(void))block;
103
104@end
105
106@interface Test3 {
107 NSOperationQueue *myOperationQueue;
108 unsigned count;
109}
110@end
111void doSomething(unsigned v);
112@implementation Test3
113- (void) test {
114 // 'addOperationWithBlock:' is specifically whitelisted.
115 [myOperationQueue addOperationWithBlock:^() { // no-warning
116 if (count > 20) {
117 doSomething(count);
118 }
119 }];
120}
121- (void) test_positive {
122 // Sanity check that we are really whitelisting 'addOperationWithBlock:' and not doing
123 // something funny.
124 [myOperationQueue addSomethingElse:^() { // expected-note {{block will be retained by an object strongly retained by the captured object}}
125 if (count > 20) { // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}}
126 doSomething(count);
127 }
128 }];
129}
130@end
131
Jordan Rosee10f4d32012-09-15 02:48:31 +0000132
133void testBlockVariable() {
134 typedef void (^block_t)(void);
135
136 // This case will be caught by -Wuninitialized, and does not create a
137 // retain cycle.
138 block_t a1 = ^{
139 a1(); // no-warning
140 };
141
142 // This case will also be caught by -Wuninitialized.
143 block_t a2;
144 a2 = ^{
145 a2(); // no-warning
146 };
147
148 __block block_t b1 = ^{ // expected-note{{block will be retained by the captured object}}
149 b1(); // expected-warning{{capturing 'b1' strongly in this block is likely to lead to a retain cycle}}
150 };
151
152 __block block_t b2;
153 b2 = ^{ // expected-note{{block will be retained by the captured object}}
154 b2(); // expected-warning{{capturing 'b2' strongly in this block is likely to lead to a retain cycle}}
155 };
156}
157
Jordan Rose1fac58a2012-09-17 17:54:30 +0000158
159@interface NSObject
160- (id)copy;
161
162- (void (^)(void))someRandomMethodReturningABlock;
163@end
164
165
166void testCopying(Test0 *obj) {
167 typedef void (^block_t)(void);
168
169 [obj setBlock:[^{ // expected-note{{block will be retained by the captured object}}
170 [obj actNow]; // expected-warning{{capturing 'obj' strongly in this block is likely to lead to a retain cycle}}
171 } copy]];
172
173 [obj addBlock:(__bridge_transfer block_t)_Block_copy((__bridge void *)^{ // expected-note{{block will be retained by the captured object}}
174 [obj actNow]; // expected-warning{{capturing 'obj' strongly in this block is likely to lead to a retain cycle}}
175 })];
176
177 [obj addBlock:[^{
178 [obj actNow]; // no-warning
179 } someRandomMethodReturningABlock]];
180
181 extern block_t someRandomFunctionReturningABlock(block_t);
182 [obj setBlock:someRandomFunctionReturningABlock(^{
183 [obj actNow]; // no-warning
184 })];
185}
186