1 // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=dynamic-bifurcate -verify %s 2 3 #include "InlineObjCInstanceMethod.h" 4 5 void clang_analyzer_eval(int); 6 7 PublicSubClass2 *getObj(); 8 9 @implementation PublicParent 10 - (int) getZeroOverridden { 11 return 1; 12 } 13 - (int) getZero { 14 return 0; 15 } 16 @end 17 18 @implementation PublicSubClass2 19 - (int) getZeroOverridden { 20 return 0; 21 } 22 23 /* Test that we get the right type from call to alloc. */ 24 + (void) testAllocSelf { 25 id a = [self alloc]; 26 clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{TRUE}} 27 } 28 29 30 + (void) testAllocClass { 31 id a = [PublicSubClass2 alloc]; 32 clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{TRUE}} 33 } 34 35 + (void) testAllocSuperOverriden { 36 id a = [super alloc]; 37 // Evaluates to 1 in the parent. 38 clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{FALSE}} 39 } 40 41 + (void) testAllocSuper { 42 id a = [super alloc]; 43 clang_analyzer_eval([a getZero] == 0); // expected-warning{{TRUE}} 44 } 45 46 + (void) testAllocInit { 47 id a = [[self alloc] init]; 48 clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{TRUE}} 49 } 50 51 + (void) testNewSelf { 52 id a = [self new]; 53 clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{TRUE}} 54 } 55 56 // Casting to parent should not pessimize the dynamic type. 57 + (void) testCastToParent { 58 id a = [[self alloc] init]; 59 PublicParent *p = a; 60 clang_analyzer_eval([p getZeroOverridden] == 0); // expected-warning{{TRUE}} 61 } 62 63 // The type of parameter gets used. 64 + (void)testTypeFromParam:(PublicParent*) p { 65 clang_analyzer_eval([p getZero] == 0); // expected-warning{{TRUE}} 66 } 67 68 // Test implicit cast. 69 // Note, in this case, p could also be a subclass of MyParent. 70 + (void) testCastFromId:(id) a { 71 PublicParent *p = a; 72 clang_analyzer_eval([p getZero] == 0); // expected-warning{{TRUE}} 73 } 74 @end 75 76 // TODO: Would be nice to handle the case of dynamically obtained class info 77 // as well. We need a MemRegion for class types for this. 78 int testDynamicClass(BOOL coin) { 79 Class AllocClass = (coin ? [NSObject class] : [PublicSubClass2 class]); 80 id x = [[AllocClass alloc] init]; 81 if (coin) 82 return [x getZero]; 83 return 1; 84 } 85 86 @interface UserClass : NSObject 87 - (PublicSubClass2 *) _newPublicSubClass2; 88 - (int) getZero; 89 - (void) callNew; 90 @end 91 92 @implementation UserClass 93 - (PublicSubClass2 *) _newPublicSubClass2 { 94 return [[PublicSubClass2 alloc] init]; 95 } 96 - (int) getZero { return 5; } 97 - (void) callNew { 98 PublicSubClass2 *x = [self _newPublicSubClass2]; 99 clang_analyzer_eval([x getZero] == 0); //expected-warning{{TRUE}} 100 } 101 @end