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 -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