1// RUN: %clang_analyze_cc1 -analyzer-checker=core,optin.performance.GCDAntipattern %s -fblocks -verify
2typedef signed char BOOL;
3@protocol NSObject  - (BOOL)isEqual:(id)object; @end
4@interface NSObject <NSObject> {}
5+(id)alloc;
6-(id)init;
7-(id)autorelease;
8-(id)copy;
9-(id)retain;
10@end
11
12typedef int dispatch_semaphore_t;
13typedef int dispatch_group_t;
14typedef void (^block_t)();
15
16dispatch_semaphore_t dispatch_semaphore_create(int);
17dispatch_group_t dispatch_group_create();
18void dispatch_group_enter(dispatch_group_t);
19void dispatch_group_leave(dispatch_group_t);
20void dispatch_group_wait(dispatch_group_t, int);
21
22
23void dispatch_semaphore_wait(dispatch_semaphore_t, int);
24void dispatch_semaphore_signal(dispatch_semaphore_t);
25
26void func(void (^)(void));
27void func_w_typedef(block_t);
28
29int coin();
30
31void use_semaphor_antipattern() {
32  dispatch_semaphore_t sema = dispatch_semaphore_create(0);
33
34  func(^{
35      dispatch_semaphore_signal(sema);
36  });
37  dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback using a semaphore}}
38}
39
40// It's OK to use pattern in tests.
41// We simply match the containing function name against ^test.
42void test_no_warning() {
43  dispatch_semaphore_t sema = dispatch_semaphore_create(0);
44
45  func(^{
46      dispatch_semaphore_signal(sema);
47  });
48  dispatch_semaphore_wait(sema, 100);
49}
50
51void use_semaphor_antipattern_multiple_times() {
52  dispatch_semaphore_t sema1 = dispatch_semaphore_create(0);
53
54  func(^{
55      dispatch_semaphore_signal(sema1);
56  });
57  dispatch_semaphore_wait(sema1, 100); // expected-warning{{Waiting on a callback using a semaphore}}
58
59  dispatch_semaphore_t sema2 = dispatch_semaphore_create(0);
60
61  func(^{
62      dispatch_semaphore_signal(sema2);
63  });
64  dispatch_semaphore_wait(sema2, 100); // expected-warning{{Waiting on a callback using a semaphore}}
65}
66
67void use_semaphor_antipattern_multiple_wait() {
68  dispatch_semaphore_t sema1 = dispatch_semaphore_create(0);
69
70  func(^{
71      dispatch_semaphore_signal(sema1);
72  });
73  // FIXME: multiple waits on same semaphor should not raise a warning.
74  dispatch_semaphore_wait(sema1, 100); // expected-warning{{Waiting on a callback using a semaphore}}
75  dispatch_semaphore_wait(sema1, 100); // expected-warning{{Waiting on a callback using a semaphore}}
76}
77
78void warn_incorrect_order() {
79  // FIXME: ASTMatchers do not allow ordered matching, so would match even
80  // if out of order.
81  dispatch_semaphore_t sema = dispatch_semaphore_create(0);
82
83  dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback}}
84  func(^{
85      dispatch_semaphore_signal(sema);
86  });
87}
88
89void warn_w_typedef() {
90  dispatch_semaphore_t sema = dispatch_semaphore_create(0);
91
92  func_w_typedef(^{
93      dispatch_semaphore_signal(sema);
94  });
95  dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback using a semaphore}}
96}
97
98void warn_nested_ast() {
99  dispatch_semaphore_t sema = dispatch_semaphore_create(0);
100
101  if (coin()) {
102    func(^{
103         dispatch_semaphore_signal(sema);
104         });
105  } else {
106    func(^{
107         dispatch_semaphore_signal(sema);
108         });
109  }
110  dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback using a semaphore}}
111}
112
113void use_semaphore_assignment() {
114  dispatch_semaphore_t sema;
115  sema = dispatch_semaphore_create(0);
116
117  func(^{
118      dispatch_semaphore_signal(sema);
119  });
120  dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback using a semaphore}}
121}
122
123void use_semaphore_assignment_init() {
124  dispatch_semaphore_t sema = dispatch_semaphore_create(0);
125  sema = dispatch_semaphore_create(1);
126
127  func(^{
128      dispatch_semaphore_signal(sema);
129  });
130  dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback using a semaphore}}
131}
132
133void differentsemaphoreok() {
134  dispatch_semaphore_t sema1 = dispatch_semaphore_create(0);
135  dispatch_semaphore_t sema2 = dispatch_semaphore_create(0);
136
137  func(^{
138      dispatch_semaphore_signal(sema1);
139  });
140  dispatch_semaphore_wait(sema2, 100); // no-warning
141}
142
143void nosignalok() {
144  dispatch_semaphore_t sema1 = dispatch_semaphore_create(0);
145  dispatch_semaphore_wait(sema1, 100);
146}
147
148void nowaitok() {
149  dispatch_semaphore_t sema = dispatch_semaphore_create(0);
150  func(^{
151      dispatch_semaphore_signal(sema);
152  });
153}
154
155void noblockok() {
156  dispatch_semaphore_t sema = dispatch_semaphore_create(0);
157  dispatch_semaphore_signal(sema);
158  dispatch_semaphore_wait(sema, 100);
159}
160
161void storedblockok() {
162  dispatch_semaphore_t sema = dispatch_semaphore_create(0);
163  block_t b = ^{
164      dispatch_semaphore_signal(sema);
165  };
166  dispatch_semaphore_wait(sema, 100);
167}
168
169void passed_semaphore_ok(dispatch_semaphore_t sema) {
170  func(^{
171      dispatch_semaphore_signal(sema);
172  });
173  dispatch_semaphore_wait(sema, 100);
174}
175
176void warn_with_cast() {
177  dispatch_semaphore_t sema = dispatch_semaphore_create(0);
178
179  func(^{
180      dispatch_semaphore_signal((int)sema);
181  });
182  dispatch_semaphore_wait((int)sema, 100); // expected-warning{{Waiting on a callback using a semaphore}}
183}
184
185@interface MyInterface1 : NSObject
186-(void)use_method_warn;
187-(void) pass_block_as_second_param_warn;
188-(void)use_objc_callback_warn;
189-(void) use_dispatch_group;
190-(void)testNoWarn;
191-(void)acceptBlock:(block_t)callback;
192-(void)flag:(int)flag acceptBlock:(block_t)callback;
193@end
194
195@implementation MyInterface1
196
197-(void)use_method_warn {
198  dispatch_semaphore_t sema = dispatch_semaphore_create(0);
199
200  func(^{
201      dispatch_semaphore_signal(sema);
202  });
203  dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback}}
204}
205
206-(void) pass_block_as_second_param_warn {
207  dispatch_semaphore_t sema = dispatch_semaphore_create(0);
208
209  [self flag:1 acceptBlock:^{
210      dispatch_semaphore_signal(sema);
211  }];
212  dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback}}
213}
214
215-(void)testNoWarn {
216  dispatch_semaphore_t sema = dispatch_semaphore_create(0);
217
218  func(^{
219      dispatch_semaphore_signal(sema);
220  });
221  dispatch_semaphore_wait(sema, 100);
222}
223
224-(void)acceptBlock:(block_t) callback {
225  callback();
226}
227
228-(void)flag:(int)flag acceptBlock:(block_t)callback {
229  callback();
230}
231
232-(void)use_objc_callback_warn {
233  dispatch_semaphore_t sema = dispatch_semaphore_create(0);
234
235  [self acceptBlock:^{
236      dispatch_semaphore_signal(sema);
237  }];
238  dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback}}
239}
240
241-(void)use_dispatch_group {
242  dispatch_group_t group = dispatch_group_create();
243  dispatch_group_enter(group);
244  [self acceptBlock:^{
245    dispatch_group_leave(group);
246  }];
247  dispatch_group_wait(group, 100); // expected-warning{{Waiting on a callback using a group}}
248
249}
250
251void use_objc_and_c_callback(MyInterface1 *t) {
252  dispatch_semaphore_t sema = dispatch_semaphore_create(0);
253
254  func(^{
255      dispatch_semaphore_signal(sema);
256  });
257  dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback using a semaphore}}
258
259  dispatch_semaphore_t sema1 = dispatch_semaphore_create(0);
260
261  [t acceptBlock:^{
262      dispatch_semaphore_signal(sema1);
263  }];
264  dispatch_semaphore_wait(sema1, 100); // expected-warning{{Waiting on a callback}}
265}
266@end
267
268// No warnings: class name contains "test"
269@interface Test1 : NSObject
270-(void)use_method_warn;
271@end
272
273@implementation Test1
274-(void)use_method_warn {
275  dispatch_semaphore_t sema = dispatch_semaphore_create(0);
276
277  func(^{
278      dispatch_semaphore_signal(sema);
279  });
280  dispatch_semaphore_wait(sema, 100);
281}
282@end
283
284
285// No warnings: class name contains "mock"
286@interface Mock1 : NSObject
287-(void)use_method_warn;
288@end
289
290@implementation Mock1
291-(void)use_method_warn {
292  dispatch_semaphore_t sema = dispatch_semaphore_create(0);
293
294  func(^{
295      dispatch_semaphore_signal(sema);
296  });
297  dispatch_semaphore_wait(sema, 100);
298}
299@end
300
301void dispatch_group_wait_func(MyInterface1 *M) {
302  dispatch_group_t group = dispatch_group_create();
303  dispatch_group_enter(group);
304
305  func(^{
306      dispatch_group_leave(group);
307  });
308  dispatch_group_wait(group, 100); // expected-warning{{Waiting on a callback using a group}}
309}
310
311
312void dispatch_group_wait_cfunc(MyInterface1 *M) {
313  dispatch_group_t group = dispatch_group_create();
314  dispatch_group_enter(group);
315  [M acceptBlock:^{
316    dispatch_group_leave(group);
317  }];
318  dispatch_group_wait(group, 100); // expected-warning{{Waiting on a callback using a group}}
319}
320
321void dispatch_group_and_semaphore_use(MyInterface1 *M) {
322  dispatch_group_t group = dispatch_group_create();
323  dispatch_group_enter(group);
324  [M acceptBlock:^{
325    dispatch_group_leave(group);
326  }];
327  dispatch_group_wait(group, 100); // expected-warning{{Waiting on a callback using a group}}
328
329  dispatch_semaphore_t sema1 = dispatch_semaphore_create(0);
330
331  [M acceptBlock:^{
332      dispatch_semaphore_signal(sema1);
333  }];
334  dispatch_semaphore_wait(sema1, 100); // expected-warning{{Waiting on a callback using a semaphore}}
335}
336
337void no_warn_on_nonzero_semaphore(MyInterface1 *M) {
338  dispatch_semaphore_t sema1 = dispatch_semaphore_create(1);
339
340  [M acceptBlock:^{
341      dispatch_semaphore_signal(sema1);
342  }];
343  dispatch_semaphore_wait(sema1, 100); // no-warning
344}
345
346