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