1// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -fblocks -verify -Wno-objc-root-class -Wno-implicit-retain-self %s
2
3void *_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
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]; };
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
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
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
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) {
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
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
158
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
187// rdar://16944538
188void 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
202typedef void (^a_block_t)(void);
203
204@interface HonorNoEscape
205- (void)addStuffUsingBlock:(__attribute__((noescape)) a_block_t)block;
206@end
207
208void testNoEscape(HonorNoEscape *obj) {
209  [obj addStuffUsingBlock:^{
210    (void)obj; // ok.
211  }];
212}
213