[clang] Handle __declspec() attributes in using
[llvm-project.git] / clang / test / SemaObjC / warn-retain-cycle.m
blob88cf2c26b62b53275fd32750d9ef3a52f0cae546
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   // 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}}
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
39 @interface Test1 {
40 @public
41   BlockOwner *owner;
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; };
54 @implementation Test1 {
55   BlockOwner * __unsafe_unretained owner3ivar;
56   __weak BlockOwner *weakowner;
58 @dynamic owner;
59 @dynamic owner2;
60 @synthesize owner3 = owner3ivar;
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; };
66   // TODO: should we warn here?  What's the story with this kind of mismatch?
67   self.owner3.strong = ^{ (void) owner; };
69   owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
71   owner.strong = ^{ ^{ (void) owner; }(); }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
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}}
76   weakowner.strong = ^{ (void) owner; };
78   return self;
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}}
83 @end
85 void test2_helper(id);
86 @interface Test2 {
87   void (^block)(void);
88   id x;
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   };
97 @end
100 @interface NSOperationQueue {}
101 - (void)addOperationWithBlock:(void (^)(void))block;
102 - (void)addSomethingElse:(void (^)(void))block;
104 @end
106 @interface Test3 {
107   NSOperationQueue *myOperationQueue;
108   unsigned count;
110 @end
111 void doSomething(unsigned v);
112 @implementation Test3
113 - (void) test {
114   // 'addOperationWithBlock:' is specifically allowlisted.
115   [myOperationQueue addOperationWithBlock:^() { // no-warning
116     if (count > 20) {
117       doSomething(count);
118     }
119   }];
121 - (void) test_positive {
122   // Check that we are really allowlisting '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   }];
130 @end
133 void testBlockVariable(void) {
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   };
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   };
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   };
159 @interface NSObject
160 - (id)copy;
162 - (void (^)(void))someRandomMethodReturningABlock;
163 @end
166 void testCopying(Test0 *obj) {
167   typedef void (^block_t)(void);
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]];
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   })];
187 // rdar://16944538
188 void func(int someCondition) {
190 __block void(^myBlock)(void) = ^{
191         if (someCondition) {
192             doSomething(1);
193             myBlock();
194         }
195         else {
196             myBlock = ((void*)0);
197         }
198    };
202 typedef void (^a_block_t)(void);
204 @interface HonorNoEscape
205 - (void)addStuffUsingBlock:(__attribute__((noescape)) a_block_t)block;
206 @end
208 void testNoEscape(HonorNoEscape *obj) {
209   [obj addStuffUsingBlock:^{
210     (void)obj; // ok.
211   }];