xref: /aosp_15_r20/external/clang/test/SemaObjC/warn-retain-cycle.m (revision 67e74705e28f6214e480b399dd47ea732279e315)
1*67e74705SXin Li// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -fblocks -verify -Wno-objc-root-class -Wno-implicit-retain-self %s
2*67e74705SXin Li
3*67e74705SXin Livoid *_Block_copy(const void *block);
4*67e74705SXin Li
5*67e74705SXin Li@interface Test0
6*67e74705SXin Li- (void) setBlock: (void(^)(void)) block;
7*67e74705SXin Li- (void) addBlock: (void(^)(void)) block;
8*67e74705SXin Li- (void) actNow;
9*67e74705SXin Li@end
10*67e74705SXin Livoid test0(Test0 *x) {
11*67e74705SXin Li  [x setBlock: // expected-note {{block will be retained by the captured object}}
12*67e74705SXin Li       ^{ [x actNow]; }]; // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}}
13*67e74705SXin Li  x.block = // expected-note {{block will be retained by the captured object}}
14*67e74705SXin Li       ^{ [x actNow]; }; // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}}
15*67e74705SXin Li
16*67e74705SXin Li  [x addBlock: // expected-note {{block will be retained by the captured object}}
17*67e74705SXin Li       ^{ [x actNow]; }]; // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}}
18*67e74705SXin Li
19*67e74705SXin Li  // These actually don't cause retain cycles.
20*67e74705SXin Li  __weak Test0 *weakx = x;
21*67e74705SXin Li  [x addBlock: ^{ [weakx actNow]; }];
22*67e74705SXin Li  [x setBlock: ^{ [weakx actNow]; }];
23*67e74705SXin Li  x.block = ^{ [weakx actNow]; };
24*67e74705SXin Li
25*67e74705SXin Li  // These do cause retain cycles, but we're not clever enough to figure that out.
26*67e74705SXin Li  [weakx addBlock: ^{ [x actNow]; }];
27*67e74705SXin Li  [weakx setBlock: ^{ [x actNow]; }];
28*67e74705SXin Li  weakx.block = ^{ [x actNow]; };
29*67e74705SXin Li
30*67e74705SXin Li  // rdar://11702054
31*67e74705SXin Li  x.block = ^{ (void)x.actNow; };  // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}} \
32*67e74705SXin Li                                   // expected-note {{block will be retained by the captured object}}
33*67e74705SXin Li}
34*67e74705SXin Li
35*67e74705SXin Li@interface BlockOwner
36*67e74705SXin Li@property (retain) void (^strong)(void); // expected-warning {{retain'ed block property does not copy the block - use copy attribute instead}}
37*67e74705SXin Li@end
38*67e74705SXin Li
39*67e74705SXin Li@interface Test1 {
40*67e74705SXin Li@public
41*67e74705SXin Li  BlockOwner *owner;
42*67e74705SXin Li};
43*67e74705SXin Li@property (retain) BlockOwner *owner;
44*67e74705SXin Li@property (assign) __strong BlockOwner *owner2; // expected-error {{unsafe_unretained property 'owner2' may not also be declared __strong}}
45*67e74705SXin Li@property (assign) BlockOwner *owner3;
46*67e74705SXin Li@end
47*67e74705SXin Livoid test1(Test1 *x) {
48*67e74705SXin Li  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*67e74705SXin Li  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*67e74705SXin Li  x.owner2.strong = ^{ (void) x; };
51*67e74705SXin Li  x.owner3.strong = ^{ (void) x; };
52*67e74705SXin Li}
53*67e74705SXin Li
54*67e74705SXin Li@implementation Test1 {
55*67e74705SXin Li  BlockOwner * __unsafe_unretained owner3ivar;
56*67e74705SXin Li  __weak BlockOwner *weakowner;
57*67e74705SXin Li}
58*67e74705SXin Li@dynamic owner;
59*67e74705SXin Li@dynamic owner2;
60*67e74705SXin Li@synthesize owner3 = owner3ivar;
61*67e74705SXin Li
62*67e74705SXin Li- (id) init {
63*67e74705SXin Li  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*67e74705SXin Li  self.owner2.strong = ^{ (void) owner; };
65*67e74705SXin Li
66*67e74705SXin Li  // TODO: should we warn here?  What's the story with this kind of mismatch?
67*67e74705SXin Li  self.owner3.strong = ^{ (void) owner; };
68*67e74705SXin Li
69*67e74705SXin Li  owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
70*67e74705SXin Li
71*67e74705SXin Li  owner.strong = ^{ ^{ (void) owner; }(); }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
72*67e74705SXin Li
73*67e74705SXin Li  owner.strong = ^{ (void) sizeof(self); // expected-note {{block will be retained by an object strongly retained by the captured object}}
74*67e74705SXin Li                    (void) owner; }; // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}}
75*67e74705SXin Li
76*67e74705SXin Li  weakowner.strong = ^{ (void) owner; };
77*67e74705SXin Li
78*67e74705SXin Li  return self;
79*67e74705SXin Li}
80*67e74705SXin Li- (void) foo {
81*67e74705SXin Li  owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
82*67e74705SXin Li}
83*67e74705SXin Li@end
84*67e74705SXin Li
85*67e74705SXin Livoid test2_helper(id);
86*67e74705SXin Li@interface Test2 {
87*67e74705SXin Li  void (^block)(void);
88*67e74705SXin Li  id x;
89*67e74705SXin Li}
90*67e74705SXin Li@end
91*67e74705SXin Li@implementation Test2
92*67e74705SXin Li- (void) test {
93*67e74705SXin Li  block = ^{ // expected-note {{block will be retained by an object strongly retained by the captured object}}
94*67e74705SXin Li    test2_helper(x); // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}}
95*67e74705SXin Li  };
96*67e74705SXin Li}
97*67e74705SXin Li@end
98*67e74705SXin Li
99*67e74705SXin Li
100*67e74705SXin Li@interface NSOperationQueue {}
101*67e74705SXin Li- (void)addOperationWithBlock:(void (^)(void))block;
102*67e74705SXin Li- (void)addSomethingElse:(void (^)(void))block;
103*67e74705SXin Li
104*67e74705SXin Li@end
105*67e74705SXin Li
106*67e74705SXin Li@interface Test3 {
107*67e74705SXin Li  NSOperationQueue *myOperationQueue;
108*67e74705SXin Li  unsigned count;
109*67e74705SXin Li}
110*67e74705SXin Li@end
111*67e74705SXin Livoid doSomething(unsigned v);
112*67e74705SXin Li@implementation Test3
113*67e74705SXin Li- (void) test {
114*67e74705SXin Li  // 'addOperationWithBlock:' is specifically whitelisted.
115*67e74705SXin Li  [myOperationQueue addOperationWithBlock:^() { // no-warning
116*67e74705SXin Li    if (count > 20) {
117*67e74705SXin Li      doSomething(count);
118*67e74705SXin Li    }
119*67e74705SXin Li  }];
120*67e74705SXin Li}
121*67e74705SXin Li- (void) test_positive {
122*67e74705SXin Li  // Sanity check that we are really whitelisting 'addOperationWithBlock:' and not doing
123*67e74705SXin Li  // something funny.
124*67e74705SXin Li  [myOperationQueue addSomethingElse:^() { // expected-note {{block will be retained by an object strongly retained by the captured object}}
125*67e74705SXin Li    if (count > 20) {
126*67e74705SXin Li      doSomething(count); // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}}
127*67e74705SXin Li    }
128*67e74705SXin Li  }];
129*67e74705SXin Li}
130*67e74705SXin Li@end
131*67e74705SXin Li
132*67e74705SXin Li
133*67e74705SXin Livoid testBlockVariable() {
134*67e74705SXin Li  typedef void (^block_t)(void);
135*67e74705SXin Li
136*67e74705SXin Li  // This case will be caught by -Wuninitialized, and does not create a
137*67e74705SXin Li  // retain cycle.
138*67e74705SXin Li  block_t a1 = ^{
139*67e74705SXin Li    a1(); // no-warning
140*67e74705SXin Li  };
141*67e74705SXin Li
142*67e74705SXin Li  // This case will also be caught by -Wuninitialized.
143*67e74705SXin Li  block_t a2;
144*67e74705SXin Li  a2 = ^{
145*67e74705SXin Li    a2(); // no-warning
146*67e74705SXin Li  };
147*67e74705SXin Li
148*67e74705SXin Li  __block block_t b1 = ^{ // expected-note{{block will be retained by the captured object}}
149*67e74705SXin Li    b1(); // expected-warning{{capturing 'b1' strongly in this block is likely to lead to a retain cycle}}
150*67e74705SXin Li  };
151*67e74705SXin Li
152*67e74705SXin Li  __block block_t b2;
153*67e74705SXin Li  b2 = ^{ // expected-note{{block will be retained by the captured object}}
154*67e74705SXin Li    b2(); // expected-warning{{capturing 'b2' strongly in this block is likely to lead to a retain cycle}}
155*67e74705SXin Li  };
156*67e74705SXin Li}
157*67e74705SXin Li
158*67e74705SXin Li
159*67e74705SXin Li@interface NSObject
160*67e74705SXin Li- (id)copy;
161*67e74705SXin Li
162*67e74705SXin Li- (void (^)(void))someRandomMethodReturningABlock;
163*67e74705SXin Li@end
164*67e74705SXin Li
165*67e74705SXin Li
166*67e74705SXin Livoid testCopying(Test0 *obj) {
167*67e74705SXin Li  typedef void (^block_t)(void);
168*67e74705SXin Li
169*67e74705SXin Li  [obj setBlock:[^{ // expected-note{{block will be retained by the captured object}}
170*67e74705SXin Li    [obj actNow]; // expected-warning{{capturing 'obj' strongly in this block is likely to lead to a retain cycle}}
171*67e74705SXin Li  } copy]];
172*67e74705SXin Li
173*67e74705SXin Li  [obj addBlock:(__bridge_transfer block_t)_Block_copy((__bridge void *)^{ // expected-note{{block will be retained by the captured object}}
174*67e74705SXin Li    [obj actNow]; // expected-warning{{capturing 'obj' strongly in this block is likely to lead to a retain cycle}}
175*67e74705SXin Li  })];
176*67e74705SXin Li
177*67e74705SXin Li  [obj addBlock:[^{
178*67e74705SXin Li    [obj actNow]; // no-warning
179*67e74705SXin Li  } someRandomMethodReturningABlock]];
180*67e74705SXin Li
181*67e74705SXin Li  extern block_t someRandomFunctionReturningABlock(block_t);
182*67e74705SXin Li  [obj setBlock:someRandomFunctionReturningABlock(^{
183*67e74705SXin Li    [obj actNow]; // no-warning
184*67e74705SXin Li  })];
185*67e74705SXin Li}
186*67e74705SXin Li
187*67e74705SXin Li// rdar://16944538
188*67e74705SXin Livoid func(int someCondition) {
189*67e74705SXin Li
190*67e74705SXin Li__block void(^myBlock)(void) = ^{
191*67e74705SXin Li        if (someCondition) {
192*67e74705SXin Li            doSomething(1);
193*67e74705SXin Li            myBlock();
194*67e74705SXin Li        }
195*67e74705SXin Li        else {
196*67e74705SXin Li	    myBlock = ((void*)0);
197*67e74705SXin Li        }
198*67e74705SXin Li   };
199*67e74705SXin Li
200*67e74705SXin Li}
201