blob: 24ffe8975dd9e480460343979c2f79e734d73292 [file] [log] [blame]
// RUN: %clang_analyze_cc1 -analyzer-checker=core,optin.performance.GCDAntipattern %s -fblocks -verify
typedef signed char BOOL;
@protocol NSObject - (BOOL)isEqual:(id)object; @end
@interface NSObject <NSObject> {}
+(id)alloc;
-(id)init;
-(id)autorelease;
-(id)copy;
-(id)retain;
@end
typedef int dispatch_semaphore_t;
typedef int dispatch_group_t;
typedef void (^block_t)();
dispatch_semaphore_t dispatch_semaphore_create(int);
dispatch_group_t dispatch_group_create();
void dispatch_group_enter(dispatch_group_t);
void dispatch_group_leave(dispatch_group_t);
void dispatch_group_wait(dispatch_group_t, int);
void dispatch_semaphore_wait(dispatch_semaphore_t, int);
void dispatch_semaphore_signal(dispatch_semaphore_t);
void func(void (^)(void));
void func_w_typedef(block_t);
int coin();
void use_semaphor_antipattern() {
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
func(^{
dispatch_semaphore_signal(sema);
});
dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback using a semaphore}}
}
// It's OK to use pattern in tests.
// We simply match the containing function name against ^test.
void test_no_warning() {
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
func(^{
dispatch_semaphore_signal(sema);
});
dispatch_semaphore_wait(sema, 100);
}
void use_semaphor_antipattern_multiple_times() {
dispatch_semaphore_t sema1 = dispatch_semaphore_create(0);
func(^{
dispatch_semaphore_signal(sema1);
});
dispatch_semaphore_wait(sema1, 100); // expected-warning{{Waiting on a callback using a semaphore}}
dispatch_semaphore_t sema2 = dispatch_semaphore_create(0);
func(^{
dispatch_semaphore_signal(sema2);
});
dispatch_semaphore_wait(sema2, 100); // expected-warning{{Waiting on a callback using a semaphore}}
}
void use_semaphor_antipattern_multiple_wait() {
dispatch_semaphore_t sema1 = dispatch_semaphore_create(0);
func(^{
dispatch_semaphore_signal(sema1);
});
// FIXME: multiple waits on same semaphor should not raise a warning.
dispatch_semaphore_wait(sema1, 100); // expected-warning{{Waiting on a callback using a semaphore}}
dispatch_semaphore_wait(sema1, 100); // expected-warning{{Waiting on a callback using a semaphore}}
}
void warn_incorrect_order() {
// FIXME: ASTMatchers do not allow ordered matching, so would match even
// if out of order.
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback}}
func(^{
dispatch_semaphore_signal(sema);
});
}
void warn_w_typedef() {
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
func_w_typedef(^{
dispatch_semaphore_signal(sema);
});
dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback using a semaphore}}
}
void warn_nested_ast() {
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
if (coin()) {
func(^{
dispatch_semaphore_signal(sema);
});
} else {
func(^{
dispatch_semaphore_signal(sema);
});
}
dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback using a semaphore}}
}
void use_semaphore_assignment() {
dispatch_semaphore_t sema;
sema = dispatch_semaphore_create(0);
func(^{
dispatch_semaphore_signal(sema);
});
dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback using a semaphore}}
}
void use_semaphore_assignment_init() {
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
sema = dispatch_semaphore_create(1);
func(^{
dispatch_semaphore_signal(sema);
});
dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback using a semaphore}}
}
void differentsemaphoreok() {
dispatch_semaphore_t sema1 = dispatch_semaphore_create(0);
dispatch_semaphore_t sema2 = dispatch_semaphore_create(0);
func(^{
dispatch_semaphore_signal(sema1);
});
dispatch_semaphore_wait(sema2, 100); // no-warning
}
void nosignalok() {
dispatch_semaphore_t sema1 = dispatch_semaphore_create(0);
dispatch_semaphore_wait(sema1, 100);
}
void nowaitok() {
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
func(^{
dispatch_semaphore_signal(sema);
});
}
void noblockok() {
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
dispatch_semaphore_signal(sema);
dispatch_semaphore_wait(sema, 100);
}
void storedblockok() {
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
block_t b = ^{
dispatch_semaphore_signal(sema);
};
dispatch_semaphore_wait(sema, 100);
}
void passed_semaphore_ok(dispatch_semaphore_t sema) {
func(^{
dispatch_semaphore_signal(sema);
});
dispatch_semaphore_wait(sema, 100);
}
void warn_with_cast() {
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
func(^{
dispatch_semaphore_signal((int)sema);
});
dispatch_semaphore_wait((int)sema, 100); // expected-warning{{Waiting on a callback using a semaphore}}
}
@interface MyInterface1 : NSObject
-(void)use_method_warn;
-(void) pass_block_as_second_param_warn;
-(void)use_objc_callback_warn;
-(void) use_dispatch_group;
-(void)testNoWarn;
-(void)acceptBlock:(block_t)callback;
-(void)flag:(int)flag acceptBlock:(block_t)callback;
@end
@implementation MyInterface1
-(void)use_method_warn {
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
func(^{
dispatch_semaphore_signal(sema);
});
dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback}}
}
-(void) pass_block_as_second_param_warn {
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
[self flag:1 acceptBlock:^{
dispatch_semaphore_signal(sema);
}];
dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback}}
}
-(void)testNoWarn {
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
func(^{
dispatch_semaphore_signal(sema);
});
dispatch_semaphore_wait(sema, 100);
}
-(void)acceptBlock:(block_t) callback {
callback();
}
-(void)flag:(int)flag acceptBlock:(block_t)callback {
callback();
}
-(void)use_objc_callback_warn {
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
[self acceptBlock:^{
dispatch_semaphore_signal(sema);
}];
dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback}}
}
-(void)use_dispatch_group {
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
[self acceptBlock:^{
dispatch_group_leave(group);
}];
dispatch_group_wait(group, 100); // expected-warning{{Waiting on a callback using a group}}
}
void use_objc_and_c_callback(MyInterface1 *t) {
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
func(^{
dispatch_semaphore_signal(sema);
});
dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback using a semaphore}}
dispatch_semaphore_t sema1 = dispatch_semaphore_create(0);
[t acceptBlock:^{
dispatch_semaphore_signal(sema1);
}];
dispatch_semaphore_wait(sema1, 100); // expected-warning{{Waiting on a callback}}
}
@end
// No warnings: class name contains "test"
@interface Test1 : NSObject
-(void)use_method_warn;
@end
@implementation Test1
-(void)use_method_warn {
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
func(^{
dispatch_semaphore_signal(sema);
});
dispatch_semaphore_wait(sema, 100);
}
@end
// No warnings: class name contains "mock"
@interface Mock1 : NSObject
-(void)use_method_warn;
@end
@implementation Mock1
-(void)use_method_warn {
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
func(^{
dispatch_semaphore_signal(sema);
});
dispatch_semaphore_wait(sema, 100);
}
@end
void dispatch_group_wait_func(MyInterface1 *M) {
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
func(^{
dispatch_group_leave(group);
});
dispatch_group_wait(group, 100); // expected-warning{{Waiting on a callback using a group}}
}
void dispatch_group_wait_cfunc(MyInterface1 *M) {
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
[M acceptBlock:^{
dispatch_group_leave(group);
}];
dispatch_group_wait(group, 100); // expected-warning{{Waiting on a callback using a group}}
}
void dispatch_group_and_semaphore_use(MyInterface1 *M) {
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
[M acceptBlock:^{
dispatch_group_leave(group);
}];
dispatch_group_wait(group, 100); // expected-warning{{Waiting on a callback using a group}}
dispatch_semaphore_t sema1 = dispatch_semaphore_create(0);
[M acceptBlock:^{
dispatch_semaphore_signal(sema1);
}];
dispatch_semaphore_wait(sema1, 100); // expected-warning{{Waiting on a callback using a semaphore}}
}
void no_warn_on_nonzero_semaphore(MyInterface1 *M) {
dispatch_semaphore_t sema1 = dispatch_semaphore_create(1);
[M acceptBlock:^{
dispatch_semaphore_signal(sema1);
}];
dispatch_semaphore_wait(sema1, 100); // no-warning
}