1// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=dynamic-bifurcate -verify %s 2 3#include "InlineObjCInstanceMethod.h" 4 5void clang_analyzer_eval(int); 6 7PublicSubClass2 *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. 78int 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