summaryrefslogtreecommitdiff
path: root/test/Analysis/inlining/DynDispatchBifurcate.m
blob: ab1dfc5ec14b6aa3bde2111b00ced92c07e35ea0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx -analyzer-config ipa=dynamic-bifurcate -verify %s

#include "InlineObjCInstanceMethod.h"

@interface MyParent : NSObject
- (int)getZero;
@end
@implementation MyParent
- (int)getZero {
    return 0;
}
@end

@interface PublicClass () {
   int value2;
}
@property (readwrite) int value1;
- (void)setValue2:(int)newValue2;
@end

@implementation PublicClass

- (int)getZeroPublic {
    return 0;
}

@synthesize value1;

- (int)value2 {
    return value2;
} 
- (void)setValue2:(int)newValue {
    value2 = newValue;
}

- (int)value3 {
    return value3;
} 
- (void)setValue3:(int)newValue {
    value3 = newValue;
}

@end

@interface MyClassWithPublicParent : PublicClass
- (int)getZeroPublic;
@end
@implementation MyClassWithPublicParent
- (int)getZeroPublic {
    return 0;
}
@end

// Category overrides a public method.
@interface PublicSubClass (PrvateCat)
  - (int) getZeroPublic;
@end
@implementation PublicSubClass (PrvateCat)
- (int)getZeroPublic {
    return 0;
}
@end


@interface MyClass : MyParent {
  int value;
}
- (int)getZero;
@property int value;
@end

// Since class is private, we assume that it cannot be subclassed.
// False negative: this class is "privately subclassed". this is very rare 
// in practice.
@implementation MyClass
+ (int) testTypeFromParam:(MyParent*) p {
  int m = 0;
  int z = [p getZero];
  if (z)
    return 5/m; // false negative
  return 5/[p getZero];// expected-warning {{Division by zero}}
}

// Here only one definition is possible, since the declaration is not visible 
// from outside. 
+ (int) testTypeFromParamPrivateChild:(MyClass*) c {
  int m = 0;
  int z = [c getZero]; // MyClass overrides getZero to return '1'.
  if (z)
    return 5/m; // expected-warning {{Division by zero}}
  return 5/[c getZero];//no warning
}

- (int)getZero {
    return 1;
}

- (int)value {
  return value;
}
 
- (void)setValue:(int)newValue {
  value = newValue;
}

// Test ivar access.
- (int) testIvarInSelf {
  value = 0;
  return 5/value; // expected-warning {{Division by zero}}
}

+ (int) testIvar: (MyClass*) p {
  p.value = 0;
  return 5/p.value; // expected-warning {{Division by zero}}
}

// Test simple property access.
+ (int) testProperty: (MyClass*) p {
  int x= 0;
  [p setValue:0];
  return 5/[p value]; // expected-warning {{Division by zero}}  
}

@end

// The class is prvate and is not subclassed.
int testCallToPublicAPIInParent(MyClassWithPublicParent *p) {
  int m = 0;
  int z = [p getZeroPublic];
  if (z)
    return 5/m; // no warning
  return 5/[p getZeroPublic];// expected-warning {{Division by zero}}  
}

// When the called method is public (due to it being defined outside of main file),
// split the path and analyze both branches.
// In this case, p can be either the object of type MyParent* or MyClass*:
// - If it's MyParent*, getZero returns 0.
// - If it's MyClass*, getZero returns 1 and 'return 5/m' is reachable.
// Declaration is provate, but p can be a subclass (MyClass*).
int testCallToPublicAPI(PublicClass *p) {
  int m = 0;
  int z = [p getZeroPublic];
  if (z)
    return 5/m; // expected-warning {{Division by zero}}
  return 5/[p getZeroPublic];// expected-warning {{Division by zero}}  
}

// Even though the method is privately declared in the category, the parent 
// declares the method as public. Assume the instance can be subclassed.
int testCallToPublicAPICat(PublicSubClass *p) {
  int m = 0;
  int z = [p getZeroPublic];
  if (z)
    return 5/m; // expected-warning {{Division by zero}}
  return 5/[p getZeroPublic];// expected-warning {{Division by zero}}  
}

// Test public property - properties should always be inlined, regardless 
// weither they are "public" or private. 
int testPublicProperty(PublicClass *p) {
  int x = 0;
  p.value3 = 0;
  if (p.value3 != 0)
    return 5/x; 
  return 5/p.value3;// expected-warning {{Division by zero}}
}

int testExtension(PublicClass *p) {
  int x = 0;
  [p setValue2:0];
  if ([p value2] != 0)
    return 5/x; // expected-warning {{Division by zero}}
  return 5/[p value2]; // expected-warning {{Division by zero}}
}

// TODO: we do not handle synthesized properties yet.
int testPropertySynthesized(PublicClass *p) {
  [p setValue1:0];
  return 5/[p value1];  
}

// Test definition not available edge case.
@interface DefNotAvailClass : NSObject
@end
id testDefNotAvailableInlined(DefNotAvailClass *C) {
  return [C mem]; // expected-warning {{instance method '-mem' not found}}
}
id testDefNotAvailable(DefNotAvailClass *C) {
  return testDefNotAvailableInlined(C);
}