|  | // RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -fblocks -verify -Wno-objc-root-class -Wno-implicit-retain-self %s | 
|  |  | 
|  | void *_Block_copy(const void *block); | 
|  |  | 
|  | @interface Test0 | 
|  | - (void) setBlock: (void(^)(void)) block; | 
|  | - (void) addBlock: (void(^)(void)) block; | 
|  | - (void) actNow; | 
|  | @end | 
|  | void test0(Test0 *x) { | 
|  | [x setBlock: // expected-note {{block will be retained by the captured object}} | 
|  | ^{ [x actNow]; }]; // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}} | 
|  | x.block = // expected-note {{block will be retained by the captured object}} | 
|  | ^{ [x actNow]; }; // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}} | 
|  |  | 
|  | [x addBlock: // expected-note {{block will be retained by the captured object}} | 
|  | ^{ [x actNow]; }]; // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}} | 
|  |  | 
|  | // These actually don't cause retain cycles. | 
|  | __weak Test0 *weakx = x; | 
|  | [x addBlock: ^{ [weakx actNow]; }]; | 
|  | [x setBlock: ^{ [weakx actNow]; }]; | 
|  | x.block = ^{ [weakx actNow]; }; | 
|  |  | 
|  | // These do cause retain cycles, but we're not clever enough to figure that out. | 
|  | [weakx addBlock: ^{ [x actNow]; }]; | 
|  | [weakx setBlock: ^{ [x actNow]; }]; | 
|  | weakx.block = ^{ [x actNow]; }; | 
|  |  | 
|  | // rdar://11702054 | 
|  | x.block = ^{ (void)x.actNow; };  // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}} \ | 
|  | // expected-note {{block will be retained by the captured object}} | 
|  | } | 
|  |  | 
|  | @interface BlockOwner | 
|  | @property (retain) void (^strong)(void); // expected-warning {{retain'ed block property does not copy the block - use copy attribute instead}} | 
|  | @end | 
|  |  | 
|  | @interface Test1 { | 
|  | @public | 
|  | BlockOwner *owner; | 
|  | }; | 
|  | @property (retain) BlockOwner *owner; | 
|  | @property (assign) __strong BlockOwner *owner2; // expected-error {{unsafe_unretained property 'owner2' may not also be declared __strong}} | 
|  | @property (assign) BlockOwner *owner3; | 
|  | @end | 
|  | void test1(Test1 *x) { | 
|  | x->owner.strong = ^{ (void) x; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}} | 
|  | x.owner.strong = ^{ (void) x; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}} | 
|  | x.owner2.strong = ^{ (void) x; }; | 
|  | x.owner3.strong = ^{ (void) x; }; | 
|  | } | 
|  |  | 
|  | @implementation Test1 { | 
|  | BlockOwner * __unsafe_unretained owner3ivar; | 
|  | __weak BlockOwner *weakowner; | 
|  | } | 
|  | @dynamic owner; | 
|  | @dynamic owner2; | 
|  | @synthesize owner3 = owner3ivar; | 
|  |  | 
|  | - (id) init { | 
|  | self.owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}} | 
|  | self.owner2.strong = ^{ (void) owner; }; | 
|  |  | 
|  | // TODO: should we warn here?  What's the story with this kind of mismatch? | 
|  | self.owner3.strong = ^{ (void) owner; }; | 
|  |  | 
|  | owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}} | 
|  |  | 
|  | owner.strong = ^{ ^{ (void) owner; }(); }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}} | 
|  |  | 
|  | owner.strong = ^{ (void) sizeof(self); // expected-note {{block will be retained by an object strongly retained by the captured object}} | 
|  | (void) owner; }; // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}} | 
|  |  | 
|  | weakowner.strong = ^{ (void) owner; }; | 
|  |  | 
|  | return self; | 
|  | } | 
|  | - (void) foo { | 
|  | owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}} | 
|  | } | 
|  | @end | 
|  |  | 
|  | void test2_helper(id); | 
|  | @interface Test2 { | 
|  | void (^block)(void); | 
|  | id x; | 
|  | } | 
|  | @end | 
|  | @implementation Test2 | 
|  | - (void) test { | 
|  | block = ^{ // expected-note {{block will be retained by an object strongly retained by the captured object}} | 
|  | test2_helper(x); // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}} | 
|  | }; | 
|  | } | 
|  | @end | 
|  |  | 
|  |  | 
|  | @interface NSOperationQueue {} | 
|  | - (void)addOperationWithBlock:(void (^)(void))block; | 
|  | - (void)addSomethingElse:(void (^)(void))block; | 
|  |  | 
|  | @end | 
|  |  | 
|  | @interface Test3 { | 
|  | NSOperationQueue *myOperationQueue; | 
|  | unsigned count; | 
|  | } | 
|  | @end | 
|  | void doSomething(unsigned v); | 
|  | @implementation Test3 | 
|  | - (void) test { | 
|  | // 'addOperationWithBlock:' is specifically whitelisted. | 
|  | [myOperationQueue addOperationWithBlock:^() { // no-warning | 
|  | if (count > 20) { | 
|  | doSomething(count); | 
|  | } | 
|  | }]; | 
|  | } | 
|  | - (void) test_positive { | 
|  | // Sanity check that we are really whitelisting 'addOperationWithBlock:' and not doing | 
|  | // something funny. | 
|  | [myOperationQueue addSomethingElse:^() { // expected-note {{block will be retained by an object strongly retained by the captured object}} | 
|  | if (count > 20) { | 
|  | doSomething(count); // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}} | 
|  | } | 
|  | }]; | 
|  | } | 
|  | @end | 
|  |  | 
|  |  | 
|  | void testBlockVariable() { | 
|  | typedef void (^block_t)(void); | 
|  |  | 
|  | // This case will be caught by -Wuninitialized, and does not create a | 
|  | // retain cycle. | 
|  | block_t a1 = ^{ | 
|  | a1(); // no-warning | 
|  | }; | 
|  |  | 
|  | // This case will also be caught by -Wuninitialized. | 
|  | block_t a2; | 
|  | a2 = ^{ | 
|  | a2(); // no-warning | 
|  | }; | 
|  |  | 
|  | __block block_t b1 = ^{ // expected-note{{block will be retained by the captured object}} | 
|  | b1(); // expected-warning{{capturing 'b1' strongly in this block is likely to lead to a retain cycle}} | 
|  | }; | 
|  |  | 
|  | __block block_t b2; | 
|  | b2 = ^{ // expected-note{{block will be retained by the captured object}} | 
|  | b2(); // expected-warning{{capturing 'b2' strongly in this block is likely to lead to a retain cycle}} | 
|  | }; | 
|  | } | 
|  |  | 
|  |  | 
|  | @interface NSObject | 
|  | - (id)copy; | 
|  |  | 
|  | - (void (^)(void))someRandomMethodReturningABlock; | 
|  | @end | 
|  |  | 
|  |  | 
|  | void testCopying(Test0 *obj) { | 
|  | typedef void (^block_t)(void); | 
|  |  | 
|  | [obj setBlock:[^{ // expected-note{{block will be retained by the captured object}} | 
|  | [obj actNow]; // expected-warning{{capturing 'obj' strongly in this block is likely to lead to a retain cycle}} | 
|  | } copy]]; | 
|  |  | 
|  | [obj addBlock:(__bridge_transfer block_t)_Block_copy((__bridge void *)^{ // expected-note{{block will be retained by the captured object}} | 
|  | [obj actNow]; // expected-warning{{capturing 'obj' strongly in this block is likely to lead to a retain cycle}} | 
|  | })]; | 
|  |  | 
|  | [obj addBlock:[^{ | 
|  | [obj actNow]; // no-warning | 
|  | } someRandomMethodReturningABlock]]; | 
|  |  | 
|  | extern block_t someRandomFunctionReturningABlock(block_t); | 
|  | [obj setBlock:someRandomFunctionReturningABlock(^{ | 
|  | [obj actNow]; // no-warning | 
|  | })]; | 
|  | } | 
|  |  | 
|  | // rdar://16944538 | 
|  | void func(int someCondition) { | 
|  |  | 
|  | __block void(^myBlock)(void) = ^{ | 
|  | if (someCondition) { | 
|  | doSomething(1); | 
|  | myBlock(); | 
|  | } | 
|  | else { | 
|  | myBlock = ((void*)0); | 
|  | } | 
|  | }; | 
|  |  | 
|  | } |