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