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