diff options
Diffstat (limited to 'test/Analysis/gcdantipatternchecker_test.m')
-rw-r--r-- | test/Analysis/gcdantipatternchecker_test.m | 345 |
1 files changed, 345 insertions, 0 deletions
diff --git a/test/Analysis/gcdantipatternchecker_test.m b/test/Analysis/gcdantipatternchecker_test.m new file mode 100644 index 000000000000..24ffe8975dd9 --- /dev/null +++ b/test/Analysis/gcdantipatternchecker_test.m @@ -0,0 +1,345 @@ +// 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 +} + |