// RUN: %clang_cc1 -analyze -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