150
|
1 // RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -fblocks -verify -Wno-objc-root-class -Wno-implicit-retain-self %s
|
|
2
|
|
3 void *_Block_copy(const void *block);
|
|
4
|
|
5 @interface Test0
|
|
6 - (void) setBlock: (void(^)(void)) block;
|
|
7 - (void) addBlock: (void(^)(void)) block;
|
|
8 - (void) actNow;
|
|
9 @end
|
|
10 void 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]; };
|
|
29
|
|
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}}
|
|
33 }
|
|
34
|
|
35 @interface BlockOwner
|
|
36 @property (retain) void (^strong)(void); // expected-warning {{retain'ed block property does not copy the block - use copy attribute instead}}
|
|
37 @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
|
|
47 void 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
|
|
85 void 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
|
|
98
|
|
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
|
|
111 void 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) {
|
|
126 doSomething(count); // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}}
|
|
127 }
|
|
128 }];
|
|
129 }
|
|
130 @end
|
|
131
|
|
132
|
|
133 void 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
|
|
158
|
|
159 @interface NSObject
|
|
160 - (id)copy;
|
|
161
|
|
162 - (void (^)(void))someRandomMethodReturningABlock;
|
|
163 @end
|
|
164
|
|
165
|
|
166 void 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
|
|
187 // rdar://16944538
|
|
188 void func(int someCondition) {
|
|
189
|
|
190 __block void(^myBlock)(void) = ^{
|
|
191 if (someCondition) {
|
|
192 doSomething(1);
|
|
193 myBlock();
|
|
194 }
|
|
195 else {
|
|
196 myBlock = ((void*)0);
|
|
197 }
|
|
198 };
|
|
199
|
|
200 }
|
|
201
|
|
202 typedef void (^a_block_t)(void);
|
|
203
|
|
204 @interface HonorNoEscape
|
|
205 - (void)addStuffUsingBlock:(__attribute__((noescape)) a_block_t)block;
|
|
206 @end
|
|
207
|
|
208 void testNoEscape(HonorNoEscape *obj) {
|
|
209 [obj addStuffUsingBlock:^{
|
|
210 (void)obj; // ok.
|
|
211 }];
|
|
212 }
|