1 | // RUN: %clang_analyze_cc1 -analyzer-checker=core,osx -analyzer-config 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. |
127 | int 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*). |
141 | int 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. |
151 | int 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. |
161 | int testPublicProperty(PublicClass *p) { |
162 | int x = 0; |
163 | p.value3 = 0; |
164 | if (p.value3 != 0) |
165 | return 5/x; |
166 | return 5/p.value3;// expected-warning {{Division by zero}} |
167 | } |
168 | |
169 | int 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}} |
174 | return 5/[p value2]; // expected-warning {{Division by zero}} |
175 | } |
176 | |
177 | // TODO: we do not handle synthesized properties yet. |
178 | int testPropertySynthesized(PublicClass *p) { |
179 | [p setValue1:0]; |
180 | return 5/[p value1]; |
181 | } |
182 | |
183 | // Test definition not available edge case. |
184 | @interface DefNotAvailClass : NSObject // expected-note {{receiver is instance of class declared here}} |
185 | @end |
186 | id testDefNotAvailableInlined(DefNotAvailClass *C) { |
187 | return [C mem]; // expected-warning {{instance method '-mem' not found}} |
188 | } |
189 | id testDefNotAvailable(DefNotAvailClass *C) { |
190 | return testDefNotAvailableInlined(C); |
191 | } |
192 | |