blob: cdc798d976b0467ee05bdad5f9436a815f5f91ca [file] [log] [blame]
Devin Coughlin3ab8b2e72015-12-29 23:44:19 +00001// RUN: %clang_cc1 -fobjc-arc -analyze -analyzer-checker=core,nullability -verify %s
Devin Coughlin4a330202016-01-22 01:01:11 +00002// RUN: %clang_cc1 -analyze -analyzer-checker=core,nullability -verify %s
Gabor Horvath28690922015-08-26 23:17:43 +00003
4#define nil 0
5#define BOOL int
6
Devin Coughlinde217672016-01-28 22:23:34 +00007#define NS_ASSUME_NONNULL_BEGIN _Pragma("clang assume_nonnull begin")
8#define NS_ASSUME_NONNULL_END _Pragma("clang assume_nonnull end")
9
10typedef struct _NSZone NSZone;
11
Gabor Horvath28690922015-08-26 23:17:43 +000012@protocol NSObject
13+ (id)alloc;
14- (id)init;
15@end
16
Devin Coughlinde217672016-01-28 22:23:34 +000017NS_ASSUME_NONNULL_BEGIN
Gabor Horvath28690922015-08-26 23:17:43 +000018@protocol NSCopying
Devin Coughlinde217672016-01-28 22:23:34 +000019- (id)copyWithZone:(nullable NSZone *)zone;
20
Gabor Horvath28690922015-08-26 23:17:43 +000021@end
22
Devin Coughlinde217672016-01-28 22:23:34 +000023@protocol NSMutableCopying
24- (id)mutableCopyWithZone:(nullable NSZone *)zone;
25@end
26NS_ASSUME_NONNULL_END
27
Gabor Horvath28690922015-08-26 23:17:43 +000028__attribute__((objc_root_class))
29@interface
30NSObject<NSObject>
31@end
32
33@interface NSString : NSObject<NSCopying>
34- (BOOL)isEqualToString : (NSString *_Nonnull)aString;
35- (NSString *)stringByAppendingString:(NSString *_Nonnull)aString;
36@end
37
38@interface TestObject : NSObject
39- (int *_Nonnull)returnsNonnull;
40- (int *_Nullable)returnsNullable;
41- (int *)returnsUnspecified;
42- (void)takesNonnull:(int *_Nonnull)p;
43- (void)takesNullable:(int *_Nullable)p;
44- (void)takesUnspecified:(int *)p;
45@property(readonly, strong) NSString *stuff;
46@end
47
48TestObject * getUnspecifiedTestObject();
49TestObject *_Nonnull getNonnullTestObject();
50TestObject *_Nullable getNullableTestObject();
51
52int getRandom();
53
54typedef struct Dummy { int val; } Dummy;
55
56void takesNullable(Dummy *_Nullable);
57void takesNonnull(Dummy *_Nonnull);
58void takesUnspecified(Dummy *);
59
60Dummy *_Nullable returnsNullable();
61Dummy *_Nonnull returnsNonnull();
62Dummy *returnsUnspecified();
63int *_Nullable returnsNullableInt();
64
65template <typename T> T *eraseNullab(T *p) { return p; }
66
Gabor Horvath8d3ad6b2015-08-27 18:49:07 +000067void takesAttrNonnull(Dummy *p) __attribute((nonnull(1)));
68
Gabor Horvath28690922015-08-26 23:17:43 +000069void testBasicRules() {
70 Dummy *p = returnsNullable();
71 int *ptr = returnsNullableInt();
72 // Make every dereference a different path to avoid sinks after errors.
73 switch (getRandom()) {
74 case 0: {
75 Dummy &r = *p; // expected-warning {{}}
76 } break;
77 case 1: {
78 int b = p->val; // expected-warning {{}}
79 } break;
80 case 2: {
81 int stuff = *ptr; // expected-warning {{}}
82 } break;
83 case 3:
84 takesNonnull(p); // expected-warning {{}}
85 break;
86 case 4: {
87 Dummy d;
88 takesNullable(&d);
89 Dummy dd(d);
90 break;
91 }
Gabor Horvath8d3ad6b2015-08-27 18:49:07 +000092 case 5: takesAttrNonnull(p); break; // expected-warning {{Nullable pointer is passed to}}
93 default: { Dummy d = *p; } break; // expected-warning {{Nullable pointer is dereferenced}}
Gabor Horvath28690922015-08-26 23:17:43 +000094 }
95 if (p) {
96 takesNonnull(p);
97 if (getRandom()) {
98 Dummy &r = *p;
99 } else {
100 int b = p->val;
101 }
102 }
103 Dummy *q = 0;
104 if (getRandom()) {
105 takesNullable(q);
106 takesNonnull(q); // expected-warning {{}}
107 }
108 Dummy a;
109 Dummy *_Nonnull nonnull = &a;
110 nonnull = q; // expected-warning {{}}
111 q = &a;
112 takesNullable(q);
113 takesNonnull(q);
114}
115
116void testMultiParamChecking(Dummy *_Nonnull a, Dummy *_Nullable b,
117 Dummy *_Nonnull c);
118
119void testArgumentTracking(Dummy *_Nonnull nonnull, Dummy *_Nullable nullable) {
120 Dummy *p = nullable;
121 Dummy *q = nonnull;
122 switch(getRandom()) {
123 case 1: nonnull = p; break; // expected-warning {{}}
124 case 2: p = 0; break;
125 case 3: q = p; break;
126 case 4: testMultiParamChecking(nonnull, nullable, nonnull); break;
127 case 5: testMultiParamChecking(nonnull, nonnull, nonnull); break;
128 case 6: testMultiParamChecking(nonnull, nullable, nullable); break; // expected-warning {{}}
129 case 7: testMultiParamChecking(nullable, nullable, nonnull); // expected-warning {{}}
130 case 8: testMultiParamChecking(nullable, nullable, nullable); // expected-warning {{}}
131 case 9: testMultiParamChecking((Dummy *_Nonnull)0, nullable, nonnull); break;
132 }
133}
134
135Dummy *_Nonnull testNullableReturn(Dummy *_Nullable a) {
136 Dummy *p = a;
Devin Coughlin5a3843e2016-01-18 18:53:33 +0000137 return p; // expected-warning {{Nullable pointer is returned from a function that is expected to return a non-null value}}
Gabor Horvath28690922015-08-26 23:17:43 +0000138}
139
140Dummy *_Nonnull testNullReturn() {
141 Dummy *p = 0;
Devin Coughlin5a3843e2016-01-18 18:53:33 +0000142 return p; // expected-warning {{Null is returned from a function that is expected to return a non-null value}}
Gabor Horvath28690922015-08-26 23:17:43 +0000143}
144
145void testObjCMessageResultNullability() {
146 // The expected result: the most nullable of self and method return type.
147 TestObject *o = getUnspecifiedTestObject();
148 int *shouldBeNullable = [eraseNullab(getNullableTestObject()) returnsNonnull];
149 switch (getRandom()) {
150 case 0:
151 // The core analyzer assumes that the receiver is non-null after a message
152 // send. This is to avoid some false positives, and increase performance
153 // but it also reduces the coverage and makes this checker unable to reason
154 // about the nullness of the receiver.
155 [o takesNonnull:shouldBeNullable]; // No warning expected.
156 break;
157 case 1:
158 shouldBeNullable =
159 [eraseNullab(getNullableTestObject()) returnsUnspecified];
160 [o takesNonnull:shouldBeNullable]; // No warning expected.
161 break;
162 case 3:
163 shouldBeNullable = [eraseNullab(getNullableTestObject()) returnsNullable];
164 [o takesNonnull:shouldBeNullable]; // expected-warning {{}}
165 break;
166 case 4:
167 shouldBeNullable = [eraseNullab(getNonnullTestObject()) returnsNullable];
168 [o takesNonnull:shouldBeNullable]; // expected-warning {{}}
169 break;
170 case 5:
171 shouldBeNullable =
172 [eraseNullab(getUnspecifiedTestObject()) returnsNullable];
173 [o takesNonnull:shouldBeNullable]; // expected-warning {{}}
174 break;
175 case 6:
176 shouldBeNullable = [eraseNullab(getNullableTestObject()) returnsNullable];
177 [o takesNonnull:shouldBeNullable]; // expected-warning {{}}
178 break;
179 case 7: {
180 int *shouldBeNonnull = [eraseNullab(getNonnullTestObject()) returnsNonnull];
181 [o takesNonnull:shouldBeNonnull];
182 } break;
183 }
184}
185
Devin Coughlin755baa42015-12-29 17:40:49 +0000186Dummy * _Nonnull testDirectCastNullableToNonnull() {
187 Dummy *p = returnsNullable();
188 takesNonnull((Dummy * _Nonnull)p); // no-warning
189 return (Dummy * _Nonnull)p; // no-warning
190}
191
192Dummy * _Nonnull testIndirectCastNullableToNonnull() {
Gabor Horvath28690922015-08-26 23:17:43 +0000193 Dummy *p = (Dummy * _Nonnull)returnsNullable();
Devin Coughlin755baa42015-12-29 17:40:49 +0000194 takesNonnull(p); // no-warning
195 return p; // no-warning
196}
197
198Dummy * _Nonnull testDirectCastNilToNonnull() {
199 takesNonnull((Dummy * _Nonnull)0); // no-warning
200 return (Dummy * _Nonnull)0; // no-warning
201}
202
203void testIndirectCastNilToNonnullAndPass() {
204 Dummy *p = (Dummy * _Nonnull)0;
205 // FIXME: Ideally the cast above would suppress this warning.
206 takesNonnull(p); // expected-warning {{Null passed to a callee that requires a non-null argument}}
207}
208
209Dummy * _Nonnull testIndirectCastNilToNonnullAndReturn() {
210 Dummy *p = (Dummy * _Nonnull)0;
211 // FIXME: Ideally the cast above would suppress this warning.
212 return p; // expected-warning {{Null is returned from a function that is expected to return a non-null value}}
Gabor Horvath28690922015-08-26 23:17:43 +0000213}
214
215void testInvalidPropagation() {
216 Dummy *p = returnsUnspecified();
217 takesNullable(p);
218 takesNonnull(p);
219}
Gabor Horvathb47128a2015-09-03 23:16:21 +0000220
221void onlyReportFirstPreconditionViolationOnPath() {
222 Dummy *p = returnsNullable();
223 takesNonnull(p); // expected-warning {{}}
224 takesNonnull(p); // No warning.
225 // The first warning was not a sink. The analysis expected to continue.
226 int i = 0;
227 i = 5 / i; // expected-warning {{Division by zero}}
228 (void)i;
229}
230
231Dummy *_Nonnull doNotWarnWhenPreconditionIsViolatedInTopFunc(
232 Dummy *_Nonnull p) {
233 if (!p) {
234 Dummy *ret =
235 0; // avoid compiler warning (which is not generated by the analyzer)
236 if (getRandom())
237 return ret; // no warning
238 else
239 return p; // no warning
240 } else {
241 return p;
242 }
243}
244
245Dummy *_Nonnull doNotWarnWhenPreconditionIsViolated(Dummy *_Nonnull p) {
246 if (!p) {
247 Dummy *ret =
248 0; // avoid compiler warning (which is not generated by the analyzer)
249 if (getRandom())
250 return ret; // no warning
251 else
252 return p; // no warning
253 } else {
254 return p;
255 }
256}
257
258void testPreconditionViolationInInlinedFunction(Dummy *p) {
259 doNotWarnWhenPreconditionIsViolated(p);
260}
261
262void inlinedNullable(Dummy *_Nullable p) {
263 if (p) return;
264}
265void inlinedNonnull(Dummy *_Nonnull p) {
266 if (p) return;
267}
268void inlinedUnspecified(Dummy *p) {
269 if (p) return;
270}
271
272Dummy *_Nonnull testDefensiveInlineChecks(Dummy * p) {
273 switch (getRandom()) {
274 case 1: inlinedNullable(p); break;
275 case 2: inlinedNonnull(p); break;
276 case 3: inlinedUnspecified(p); break;
277 }
278 if (getRandom())
Devin Coughlinc1986632015-11-24 19:15:11 +0000279 takesNonnull(p); // no-warning
280
281 if (getRandom()) {
282 Dummy *_Nonnull varWithInitializer = p; // no-warning
283
284 Dummy *_Nonnull var1WithInitializer = p, // no-warning
285 *_Nonnull var2WithInitializer = p; // no-warning
286 }
287
288 if (getRandom()) {
289 Dummy *_Nonnull varWithoutInitializer;
290 varWithoutInitializer = p; // no-warning
291 }
292
Gabor Horvathb47128a2015-09-03 23:16:21 +0000293 return p;
294}
Devin Coughlin3ab8b2e72015-12-29 23:44:19 +0000295
Devin Coughlin4a330202016-01-22 01:01:11 +0000296
297@interface SomeClass : NSObject {
298 int instanceVar;
299}
Devin Coughlin5a3843e2016-01-18 18:53:33 +0000300@end
301
302@implementation SomeClass (MethodReturn)
Devin Coughlin4a330202016-01-22 01:01:11 +0000303- (id)initWithSomething:(int)i {
304 if (self = [super init]) {
305 instanceVar = i;
306 }
307
308 return self;
309}
310
Devin Coughlin5a3843e2016-01-18 18:53:33 +0000311- (TestObject * _Nonnull)testReturnsNullableInNonnullIndirectly {
312 TestObject *local = getNullableTestObject();
313 return local; // expected-warning {{Nullable pointer is returned from a function that is expected to return a non-null value}}
Devin Coughlin3ab8b2e72015-12-29 23:44:19 +0000314}
315
Devin Coughlin5a3843e2016-01-18 18:53:33 +0000316- (TestObject * _Nonnull)testReturnsCastSuppressedNullableInNonnullIndirectly {
317 TestObject *local = getNullableTestObject();
318 return (TestObject * _Nonnull)local; // no-warning
Devin Coughlin3ab8b2e72015-12-29 23:44:19 +0000319}
Devin Coughlin5a3843e2016-01-18 18:53:33 +0000320
321- (TestObject * _Nonnull)testReturnsNullableInNonnullWhenPreconditionViolated:(TestObject * _Nonnull) p {
322 TestObject *local = getNullableTestObject();
323 if (!p) // Pre-condition violated here.
324 return local; // no-warning
325 else
326 return p; // no-warning
327}
328@end
Devin Coughlin4a330202016-01-22 01:01:11 +0000329
330@interface ClassWithInitializers : NSObject
331@end
332
333@implementation ClassWithInitializers
334- (instancetype _Nonnull)initWithNonnullReturnAndSelfCheckingIdiom {
335 // This defensive check is a common-enough idiom that we filter don't want
336 // to issue a diagnostic for it,
337 if (self = [super init]) {
338 }
339
340 return self; // no-warning
341}
342
343- (instancetype _Nonnull)initWithNonnullReturnAndNilReturnViaLocal {
344 self = [super init];
345 // This leaks, but we're not checking for that here.
346
347 ClassWithInitializers *other = nil;
Devin Coughlinde217672016-01-28 22:23:34 +0000348 // False negative. Once we have more subtle suppression of defensive checks in
349 // initializers we should warn here.
350 return other;
Devin Coughlin4a330202016-01-22 01:01:11 +0000351}
352@end
353
354@interface SubClassWithInitializers : ClassWithInitializers
355@end
356
357@implementation SubClassWithInitializers
358// Note: Because this is overridding
359// -[ClassWithInitializers initWithNonnullReturnAndSelfCheckingIdiom],
360// the return type of this method becomes implicitly id _Nonnull.
361- (id)initWithNonnullReturnAndSelfCheckingIdiom {
362 if (self = [super initWithNonnullReturnAndSelfCheckingIdiom]) {
363 }
364
365 return self; // no-warning
366}
Devin Coughlinde217672016-01-28 22:23:34 +0000367
368- (id _Nonnull)initWithNonnullReturnAndSelfCheckingIdiomV2; {
369 // Another common return-checking idiom
370 self = [super initWithNonnullReturnAndSelfCheckingIdiom];
371 if (!self) {
372 return nil; // no-warning
373 }
374
375 return self;
376}
377@end
378
379@interface ClassWithCopyWithZone : NSObject<NSCopying,NSMutableCopying> {
380 id i;
381}
382
383@end
384
385@implementation ClassWithCopyWithZone
386-(id)copyWithZone:(NSZone *)zone {
387 ClassWithCopyWithZone *newInstance = [[ClassWithCopyWithZone alloc] init];
388 if (!newInstance)
389 return nil;
390
391 newInstance->i = i;
392 return newInstance;
393}
394
395-(id)mutableCopyWithZone:(NSZone *)zone {
396 ClassWithCopyWithZone *newInstance = [[ClassWithCopyWithZone alloc] init];
397 if (newInstance) {
398 newInstance->i = i;
399 }
400
401 return newInstance;
402}
Devin Coughlin4a330202016-01-22 01:01:11 +0000403@end