DynDispatchBifurcate.m revision 5498e3a01be0446f38c102278847566176f6507f
1// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=dynamic-bifurcate -verify %s
2
3#include "InlineObjCInstanceMethod.h"
4
5@interface MyParent : NSObject
6- (int)getZero;
7@end
8@implementation MyParent
9- (int)getZero {
10    return 0;
11}
12@end
13
14@interface PublicClass () {
15   int value2;
16}
17@property (readwrite) int value1;
18- (void)setValue2:(int)newValue2;
19@end
20
21@implementation PublicClass
22
23- (int)getZeroPublic {
24    return 0;
25}
26
27@synthesize value1;
28
29- (int)value2 {
30    return value2;
31} 
32- (void)setValue2:(int)newValue {
33    value2 = newValue;
34}
35
36- (int)value3 {
37    return value3;
38} 
39- (void)setValue3:(int)newValue {
40    value3 = newValue;
41}
42
43@end
44
45@interface MyClassWithPublicParent : PublicClass
46- (int)getZeroPublic;
47@end
48@implementation MyClassWithPublicParent
49- (int)getZeroPublic {
50    return 0;
51}
52@end
53
54// Category overrides a public method.
55@interface PublicSubClass (PrvateCat)
56  - (int) getZeroPublic;
57@end
58@implementation PublicSubClass (PrvateCat)
59- (int)getZeroPublic {
60    return 0;
61}
62@end
63
64
65@interface MyClass : MyParent {
66  int value;
67}
68- (int)getZero;
69@property int value;
70@end
71
72// Since class is private, we assume that it cannot be subclassed.
73// False negative: this class is "privately subclassed". this is very rare 
74// in practice.
75@implementation MyClass
76+ (int) testTypeFromParam:(MyParent*) p {
77  int m = 0;
78  int z = [p getZero];
79  if (z)
80    return 5/m; // false negative
81  return 5/[p getZero];// expected-warning {{Division by zero}}
82}
83
84// Here only one definition is possible, since the declaration is not visible 
85// from outside. 
86+ (int) testTypeFromParamPrivateChild:(MyClass*) c {
87  int m = 0;
88  int z = [c getZero]; // MyClass overrides getZero to return '1'.
89  if (z)
90    return 5/m; // expected-warning {{Division by zero}}
91  return 5/[c getZero];//no warning
92}
93
94- (int)getZero {
95    return 1;
96}
97
98- (int)value {
99  return value;
100}
101 
102- (void)setValue:(int)newValue {
103  value = newValue;
104}
105
106// Test ivar access.
107- (int) testIvarInSelf {
108  value = 0;
109  return 5/value; // expected-warning {{Division by zero}}
110}
111
112+ (int) testIvar: (MyClass*) p {
113  p.value = 0;
114  return 5/p.value; // expected-warning {{Division by zero}}
115}
116
117// Test simple property access.
118+ (int) testProperty: (MyClass*) p {
119  int x= 0;
120  [p setValue:0];
121  return 5/[p value]; // expected-warning {{Division by zero}}  
122}
123
124@end
125
126// The class is prvate and is not subclassed.
127int testCallToPublicAPIInParent(MyClassWithPublicParent *p) {
128  int m = 0;
129  int z = [p getZeroPublic];
130  if (z)
131    return 5/m; // no warning
132  return 5/[p getZeroPublic];// expected-warning {{Division by zero}}  
133}
134
135// When the called method is public (due to it being defined outside of main file),
136// split the path and analyze both branches.
137// In this case, p can be either the object of type MyParent* or MyClass*:
138// - If it's MyParent*, getZero returns 0.
139// - If it's MyClass*, getZero returns 1 and 'return 5/m' is reachable.
140// Declaration is provate, but p can be a subclass (MyClass*).
141int testCallToPublicAPI(PublicClass *p) {
142  int m = 0;
143  int z = [p getZeroPublic];
144  if (z)
145    return 5/m; // expected-warning {{Division by zero}}
146  return 5/[p getZeroPublic];// expected-warning {{Division by zero}}  
147}
148
149// Even though the method is privately declared in the category, the parent 
150// declares the method as public. Assume the instance can be subclassed.
151int testCallToPublicAPICat(PublicSubClass *p) {
152  int m = 0;
153  int z = [p getZeroPublic];
154  if (z)
155    return 5/m; // expected-warning {{Division by zero}}
156  return 5/[p getZeroPublic];// expected-warning {{Division by zero}}  
157}
158
159// Test public property - properties should always be inlined, regardless 
160// weither they are "public" or private. 
161int testPublicProperty(PublicClass *p) {
162  int x = 0;
163  [p setValue3:0];
164  if ([p value3] != 0)
165    return 5/x; // expected-warning {{Division by zero}} // TODO: no warning, we should always inline the property.
166  return 5/[p value3];// expected-warning {{Division by zero}}
167}
168
169int testExtension(PublicClass *p) {
170  int x = 0;
171  [p setValue2:0];
172  if ([p value2] != 0)
173    return 5/x; // expected-warning {{Division by zero}} // TODO: no warning, we should always inline the property.
174  return 5/[p value2]; // expected-warning {{Division by zero}}
175}
176
177// TODO: we do not handle synthesized properties yet.
178int testPropertySynthesized(PublicClass *p) {
179  [p setValue1:0];
180  return 5/[p value1];  
181}
182