Home | History | Annotate | Download | only in SemaObjC
      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