[Reland][Runtimes] Merge 'compile_commands.json' files from runtimes build (#116303)
[llvm-project.git] / clang / test / SemaObjC / warn-retain-cycle.m
blob174e7deba089bb2518687be51fdf092b384af1e7
1 // RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -fblocks -verify -Wno-objc-root-class -Wno-implicit-retain-self %s
3 void *_Block_copy(const void *block);
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}}
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}}
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]; };
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]; };
30   x.block = ^{ (void)x.actNow; };  // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}} \
31                                    // expected-note {{block will be retained by the captured object}}
34 @interface BlockOwner
35 @property (retain) void (^strong)(void); // expected-warning {{retain'ed block property does not copy the block - use copy attribute instead}}
36 @end
38 @interface Test1 {
39 @public
40   BlockOwner *owner;
42 @property (retain) BlockOwner *owner;
43 @property (assign) __strong BlockOwner *owner2; // expected-error {{unsafe_unretained property 'owner2' may not also be declared __strong}}
44 @property (assign) BlockOwner *owner3;
45 @end
46 void test1(Test1 *x) {
47   x->owner.strong = ^{ (void) x; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
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.owner2.strong = ^{ (void) x; };
50   x.owner3.strong = ^{ (void) x; };
53 @implementation Test1 {
54   BlockOwner * __unsafe_unretained owner3ivar;
55   __weak BlockOwner *weakowner;
57 @dynamic owner;
58 @dynamic owner2;
59 @synthesize owner3 = owner3ivar;
61 - (id) init {
62   self.owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
63   self.owner2.strong = ^{ (void) owner; };
65   // TODO: should we warn here?  What's the story with this kind of mismatch?
66   self.owner3.strong = ^{ (void) owner; };
68   owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
70   owner.strong = ^{ ^{ (void) owner; }(); }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
72   owner.strong = ^{ (void) sizeof(self); // expected-note {{block will be retained by an object strongly retained by the captured object}}
73                     (void) owner; }; // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}}
75   weakowner.strong = ^{ (void) owner; };
77   return self;
79 - (void) foo {
80   owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
82 @end
84 void test2_helper(id);
85 @interface Test2 {
86   void (^block)(void);
87   id x;
89 @end
90 @implementation Test2
91 - (void) test {
92   block = ^{ // expected-note {{block will be retained by an object strongly retained by the captured object}}
93     test2_helper(x); // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}}
94   };
96 @end
99 @interface NSOperationQueue {}
100 - (void)addOperationWithBlock:(void (^)(void))block;
101 - (void)addSomethingElse:(void (^)(void))block;
103 @end
105 @interface Test3 {
106   NSOperationQueue *myOperationQueue;
107   unsigned count;
109 @end
110 void doSomething(unsigned v);
111 @implementation Test3
112 - (void) test {
113   // 'addOperationWithBlock:' is specifically allowlisted.
114   [myOperationQueue addOperationWithBlock:^() { // no-warning
115     if (count > 20) {
116       doSomething(count);
117     }
118   }];
120 - (void) test_positive {
121   // Check that we are really allowlisting 'addOperationWithBlock:' and not doing
122   // something funny.
123   [myOperationQueue addSomethingElse:^() { // expected-note {{block will be retained by an object strongly retained by the captured object}}
124     if (count > 20) {
125       doSomething(count); // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}}
126     }
127   }];
129 @end
132 void testBlockVariable(void) {
133   typedef void (^block_t)(void);
134   
135   // This case will be caught by -Wuninitialized, and does not create a
136   // retain cycle.
137   block_t a1 = ^{
138     a1(); // no-warning
139   };
141   // This case will also be caught by -Wuninitialized.
142   block_t a2;
143   a2 = ^{
144     a2(); // no-warning
145   };
146   
147   __block block_t b1 = ^{ // expected-note{{block will be retained by the captured object}}
148     b1(); // expected-warning{{capturing 'b1' strongly in this block is likely to lead to a retain cycle}}
149   };
151   __block block_t b2;
152   b2 = ^{ // expected-note{{block will be retained by the captured object}}
153     b2(); // expected-warning{{capturing 'b2' strongly in this block is likely to lead to a retain cycle}}
154   };
158 @interface NSObject
159 - (id)copy;
161 - (void (^)(void))someRandomMethodReturningABlock;
162 @end
165 void testCopying(Test0 *obj) {
166   typedef void (^block_t)(void);
168   [obj setBlock:[^{ // expected-note{{block will be retained by the captured object}}
169     [obj actNow]; // expected-warning{{capturing 'obj' strongly in this block is likely to lead to a retain cycle}}
170   } copy]];
172   [obj addBlock:(__bridge_transfer block_t)_Block_copy((__bridge void *)^{ // expected-note{{block will be retained by the captured object}}
173     [obj actNow]; // expected-warning{{capturing 'obj' strongly in this block is likely to lead to a retain cycle}}
174   })];
175   
176   [obj addBlock:[^{
177     [obj actNow]; // no-warning
178   } someRandomMethodReturningABlock]];
179   
180   extern block_t someRandomFunctionReturningABlock(block_t);
181   [obj setBlock:someRandomFunctionReturningABlock(^{
182     [obj actNow]; // no-warning
183   })];
186 void func(int someCondition) {
188 __block void(^myBlock)(void) = ^{
189         if (someCondition) {
190             doSomething(1);
191             myBlock();
192         }
193         else {
194             myBlock = ((void*)0);
195         }
196    };
200 typedef void (^a_block_t)(void);
202 @interface HonorNoEscape
203 - (void)addStuffUsingBlock:(__attribute__((noescape)) a_block_t)block;
204 @end
206 void testNoEscape(HonorNoEscape *obj) {
207   [obj addStuffUsingBlock:^{
208     (void)obj; // ok.
209   }];