blob: 14cfb67e986a80a148ed56871adaeca5a5d978bc [file] [log] [blame]
Gabor Horvathdfedc0f2015-09-14 18:48:55 +00001// RUN: %clang_cc1 -analyze -analyzer-checker=core,nullability -verify %s
Gabor Horvath28690922015-08-26 23:17:43 +00002
3#define nil 0
4#define BOOL int
5
6@protocol NSObject
7+ (id)alloc;
8- (id)init;
9@end
10
11@protocol NSCopying
12@end
13
14__attribute__((objc_root_class))
15@interface
16NSObject<NSObject>
17@end
18
19@interface NSString : NSObject<NSCopying>
20- (BOOL)isEqualToString : (NSString *_Nonnull)aString;
21- (NSString *)stringByAppendingString:(NSString *_Nonnull)aString;
22@end
23
24@interface TestObject : NSObject
25- (int *_Nonnull)returnsNonnull;
26- (int *_Nullable)returnsNullable;
27- (int *)returnsUnspecified;
28- (void)takesNonnull:(int *_Nonnull)p;
29- (void)takesNullable:(int *_Nullable)p;
30- (void)takesUnspecified:(int *)p;
31@property(readonly, strong) NSString *stuff;
32@end
33
34TestObject * getUnspecifiedTestObject();
35TestObject *_Nonnull getNonnullTestObject();
36TestObject *_Nullable getNullableTestObject();
37
38int getRandom();
39
40typedef struct Dummy { int val; } Dummy;
41
42void takesNullable(Dummy *_Nullable);
43void takesNonnull(Dummy *_Nonnull);
44void takesUnspecified(Dummy *);
45
46Dummy *_Nullable returnsNullable();
47Dummy *_Nonnull returnsNonnull();
48Dummy *returnsUnspecified();
49int *_Nullable returnsNullableInt();
50
51template <typename T> T *eraseNullab(T *p) { return p; }
52
Gabor Horvath8d3ad6b2015-08-27 18:49:07 +000053void takesAttrNonnull(Dummy *p) __attribute((nonnull(1)));
54
Gabor Horvath28690922015-08-26 23:17:43 +000055void testBasicRules() {
56 Dummy *p = returnsNullable();
57 int *ptr = returnsNullableInt();
58 // Make every dereference a different path to avoid sinks after errors.
59 switch (getRandom()) {
60 case 0: {
61 Dummy &r = *p; // expected-warning {{}}
62 } break;
63 case 1: {
64 int b = p->val; // expected-warning {{}}
65 } break;
66 case 2: {
67 int stuff = *ptr; // expected-warning {{}}
68 } break;
69 case 3:
70 takesNonnull(p); // expected-warning {{}}
71 break;
72 case 4: {
73 Dummy d;
74 takesNullable(&d);
75 Dummy dd(d);
76 break;
77 }
Gabor Horvath8d3ad6b2015-08-27 18:49:07 +000078 case 5: takesAttrNonnull(p); break; // expected-warning {{Nullable pointer is passed to}}
79 default: { Dummy d = *p; } break; // expected-warning {{Nullable pointer is dereferenced}}
Gabor Horvath28690922015-08-26 23:17:43 +000080 }
81 if (p) {
82 takesNonnull(p);
83 if (getRandom()) {
84 Dummy &r = *p;
85 } else {
86 int b = p->val;
87 }
88 }
89 Dummy *q = 0;
90 if (getRandom()) {
91 takesNullable(q);
92 takesNonnull(q); // expected-warning {{}}
93 }
94 Dummy a;
95 Dummy *_Nonnull nonnull = &a;
96 nonnull = q; // expected-warning {{}}
97 q = &a;
98 takesNullable(q);
99 takesNonnull(q);
100}
101
102void testMultiParamChecking(Dummy *_Nonnull a, Dummy *_Nullable b,
103 Dummy *_Nonnull c);
104
105void testArgumentTracking(Dummy *_Nonnull nonnull, Dummy *_Nullable nullable) {
106 Dummy *p = nullable;
107 Dummy *q = nonnull;
108 switch(getRandom()) {
109 case 1: nonnull = p; break; // expected-warning {{}}
110 case 2: p = 0; break;
111 case 3: q = p; break;
112 case 4: testMultiParamChecking(nonnull, nullable, nonnull); break;
113 case 5: testMultiParamChecking(nonnull, nonnull, nonnull); break;
114 case 6: testMultiParamChecking(nonnull, nullable, nullable); break; // expected-warning {{}}
115 case 7: testMultiParamChecking(nullable, nullable, nonnull); // expected-warning {{}}
116 case 8: testMultiParamChecking(nullable, nullable, nullable); // expected-warning {{}}
117 case 9: testMultiParamChecking((Dummy *_Nonnull)0, nullable, nonnull); break;
118 }
119}
120
121Dummy *_Nonnull testNullableReturn(Dummy *_Nullable a) {
122 Dummy *p = a;
123 return p; // expected-warning {{}}
124}
125
126Dummy *_Nonnull testNullReturn() {
127 Dummy *p = 0;
128 return p; // expected-warning {{}}
129}
130
131void testObjCMessageResultNullability() {
132 // The expected result: the most nullable of self and method return type.
133 TestObject *o = getUnspecifiedTestObject();
134 int *shouldBeNullable = [eraseNullab(getNullableTestObject()) returnsNonnull];
135 switch (getRandom()) {
136 case 0:
137 // The core analyzer assumes that the receiver is non-null after a message
138 // send. This is to avoid some false positives, and increase performance
139 // but it also reduces the coverage and makes this checker unable to reason
140 // about the nullness of the receiver.
141 [o takesNonnull:shouldBeNullable]; // No warning expected.
142 break;
143 case 1:
144 shouldBeNullable =
145 [eraseNullab(getNullableTestObject()) returnsUnspecified];
146 [o takesNonnull:shouldBeNullable]; // No warning expected.
147 break;
148 case 3:
149 shouldBeNullable = [eraseNullab(getNullableTestObject()) returnsNullable];
150 [o takesNonnull:shouldBeNullable]; // expected-warning {{}}
151 break;
152 case 4:
153 shouldBeNullable = [eraseNullab(getNonnullTestObject()) returnsNullable];
154 [o takesNonnull:shouldBeNullable]; // expected-warning {{}}
155 break;
156 case 5:
157 shouldBeNullable =
158 [eraseNullab(getUnspecifiedTestObject()) returnsNullable];
159 [o takesNonnull:shouldBeNullable]; // expected-warning {{}}
160 break;
161 case 6:
162 shouldBeNullable = [eraseNullab(getNullableTestObject()) returnsNullable];
163 [o takesNonnull:shouldBeNullable]; // expected-warning {{}}
164 break;
165 case 7: {
166 int *shouldBeNonnull = [eraseNullab(getNonnullTestObject()) returnsNonnull];
167 [o takesNonnull:shouldBeNonnull];
168 } break;
169 }
170}
171
172void testCast() {
173 Dummy *p = (Dummy * _Nonnull)returnsNullable();
174 takesNonnull(p);
175}
176
177void testInvalidPropagation() {
178 Dummy *p = returnsUnspecified();
179 takesNullable(p);
180 takesNonnull(p);
181}
Gabor Horvathb47128a2015-09-03 23:16:21 +0000182
183void onlyReportFirstPreconditionViolationOnPath() {
184 Dummy *p = returnsNullable();
185 takesNonnull(p); // expected-warning {{}}
186 takesNonnull(p); // No warning.
187 // The first warning was not a sink. The analysis expected to continue.
188 int i = 0;
189 i = 5 / i; // expected-warning {{Division by zero}}
190 (void)i;
191}
192
193Dummy *_Nonnull doNotWarnWhenPreconditionIsViolatedInTopFunc(
194 Dummy *_Nonnull p) {
195 if (!p) {
196 Dummy *ret =
197 0; // avoid compiler warning (which is not generated by the analyzer)
198 if (getRandom())
199 return ret; // no warning
200 else
201 return p; // no warning
202 } else {
203 return p;
204 }
205}
206
207Dummy *_Nonnull doNotWarnWhenPreconditionIsViolated(Dummy *_Nonnull p) {
208 if (!p) {
209 Dummy *ret =
210 0; // avoid compiler warning (which is not generated by the analyzer)
211 if (getRandom())
212 return ret; // no warning
213 else
214 return p; // no warning
215 } else {
216 return p;
217 }
218}
219
220void testPreconditionViolationInInlinedFunction(Dummy *p) {
221 doNotWarnWhenPreconditionIsViolated(p);
222}
223
224void inlinedNullable(Dummy *_Nullable p) {
225 if (p) return;
226}
227void inlinedNonnull(Dummy *_Nonnull p) {
228 if (p) return;
229}
230void inlinedUnspecified(Dummy *p) {
231 if (p) return;
232}
233
234Dummy *_Nonnull testDefensiveInlineChecks(Dummy * p) {
235 switch (getRandom()) {
236 case 1: inlinedNullable(p); break;
237 case 2: inlinedNonnull(p); break;
238 case 3: inlinedUnspecified(p); break;
239 }
240 if (getRandom())
241 takesNonnull(p);
242 return p;
243}