1 // RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -fblocks -verify -Wno-objc-root-class %s 2 3 @interface Test0 4 - (void) setBlock: (void(^)(void)) block; 5 - (void) addBlock: (void(^)(void)) block; 6 - (void) actNow; 7 @end 8 void 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]; }; 27 } 28 29 @interface BlockOwner 30 @property (retain) void (^strong)(void); // expected-warning {{retain'ed block property does not copy the block - use copy attribute instead}} 31 @end 32 33 @interface Test1 { 34 @public 35 BlockOwner *owner; 36 }; 37 @property (retain) BlockOwner *owner; 38 @property (assign) __strong BlockOwner *owner2; // expected-error {{unsafe_unretained property 'owner2' may not also be declared __strong}} 39 @property (assign) BlockOwner *owner3; 40 @end 41 void test1(Test1 *x) { 42 x->owner.strong = ^{ (void) x; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}} 43 x.owner.strong = ^{ (void) x; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}} 44 x.owner2.strong = ^{ (void) x; }; 45 x.owner3.strong = ^{ (void) x; }; 46 } 47 48 @implementation Test1 { 49 BlockOwner * __unsafe_unretained owner3ivar; 50 __weak BlockOwner *weakowner; 51 } 52 @dynamic owner; 53 @dynamic owner2; 54 @synthesize owner3 = owner3ivar; 55 56 - (id) init { 57 self.owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}} 58 self.owner2.strong = ^{ (void) owner; }; 59 60 // TODO: should we warn here? What's the story with this kind of mismatch? 61 self.owner3.strong = ^{ (void) owner; }; 62 63 owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}} 64 65 owner.strong = ^{ ^{ (void) owner; }(); }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}} 66 67 owner.strong = ^{ (void) sizeof(self); // expected-note {{block will be retained by an object strongly retained by the captured object}} 68 (void) owner; }; // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}} 69 70 weakowner.strong = ^{ (void) owner; }; 71 72 return self; 73 } 74 - (void) foo { 75 owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}} 76 } 77 @end 78 79 void test2_helper(id); 80 @interface Test2 { 81 void (^block)(void); 82 id x; 83 } 84 @end 85 @implementation Test2 86 - (void) test { 87 block = ^{ // expected-note {{block will be retained by an object strongly retained by the captured object}} 88 test2_helper(x); // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}} 89 }; 90 } 91 @end 92 93 94 @interface NSOperationQueue {} 95 - (void)addOperationWithBlock:(void (^)(void))block; 96 - (void)addSomethingElse:(void (^)(void))block; 97 98 @end 99 100 @interface Test3 { 101 NSOperationQueue *myOperationQueue; 102 unsigned count; 103 } 104 @end 105 void doSomething(unsigned v); 106 @implementation Test3 107 - (void) test { 108 // 'addOperationWithBlock:' is specifically whitelisted. 109 [myOperationQueue addOperationWithBlock:^() { // no-warning 110 if (count > 20) { 111 doSomething(count); 112 } 113 }]; 114 } 115 - (void) test_positive { 116 // Sanity check that we are really whitelisting 'addOperationWithBlock:' and not doing 117 // something funny. 118 [myOperationQueue addSomethingElse:^() { // expected-note {{block will be retained by an object strongly retained by the captured object}} 119 if (count > 20) { // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}} 120 doSomething(count); 121 } 122 }]; 123 } 124 @end 125 126