| // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=dynamic-bifurcate -verify %s |
| |
| #include "InlineObjCInstanceMethod.h" |
| |
| void clang_analyzer_eval(int); |
| |
| PublicSubClass2 *getObj(); |
| |
| @implementation PublicParent |
| - (int) getZeroOverridden { |
| return 1; |
| } |
| - (int) getZero { |
| return 0; |
| } |
| @end |
| |
| @implementation PublicSubClass2 |
| - (int) getZeroOverridden { |
| return 0; |
| } |
| |
| /* Test that we get the right type from call to alloc. */ |
| + (void) testAllocSelf { |
| id a = [self alloc]; |
| clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{TRUE}} |
| } |
| |
| |
| + (void) testAllocClass { |
| id a = [PublicSubClass2 alloc]; |
| clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{TRUE}} |
| } |
| |
| + (void) testAllocSuperOverriden { |
| id a = [super alloc]; |
| // Evaluates to 1 in the parent. |
| clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{FALSE}} |
| } |
| |
| + (void) testAllocSuper { |
| id a = [super alloc]; |
| clang_analyzer_eval([a getZero] == 0); // expected-warning{{TRUE}} |
| } |
| |
| + (void) testAllocInit { |
| id a = [[self alloc] init]; |
| clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{TRUE}} |
| } |
| |
| + (void) testNewSelf { |
| id a = [self new]; |
| clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{TRUE}} |
| } |
| |
| // Casting to parent should not pessimize the dynamic type. |
| + (void) testCastToParent { |
| id a = [[self alloc] init]; |
| PublicParent *p = a; |
| clang_analyzer_eval([p getZeroOverridden] == 0); // expected-warning{{TRUE}} |
| } |
| |
| // The type of parameter gets used. |
| + (void)testTypeFromParam:(PublicParent*) p { |
| clang_analyzer_eval([p getZero] == 0); // expected-warning{{TRUE}} |
| } |
| |
| // Test implicit cast. |
| // Note, in this case, p could also be a subclass of MyParent. |
| + (void) testCastFromId:(id) a { |
| PublicParent *p = a; |
| clang_analyzer_eval([p getZero] == 0); // expected-warning{{TRUE}} |
| } |
| @end |
| |
| // TODO: Would be nice to handle the case of dynamically obtained class info |
| // as well. We need a MemRegion for class types for this. |
| int testDynamicClass(BOOL coin) { |
| Class AllocClass = (coin ? [NSObject class] : [PublicSubClass2 class]); |
| id x = [[AllocClass alloc] init]; |
| if (coin) |
| return [x getZero]; |
| return 1; |
| } |
| |
| @interface UserClass : NSObject |
| - (PublicSubClass2 *) _newPublicSubClass2; |
| - (int) getZero; |
| - (void) callNew; |
| @end |
| |
| @implementation UserClass |
| - (PublicSubClass2 *) _newPublicSubClass2 { |
| return [[PublicSubClass2 alloc] init]; |
| } |
| - (int) getZero { return 5; } |
| - (void) callNew { |
| PublicSubClass2 *x = [self _newPublicSubClass2]; |
| clang_analyzer_eval([x getZero] == 0); //expected-warning{{TRUE}} |
| } |
| @end |