1// RUN: %clang_cc1 -analyze -analyzer-checker=core,nullability -verify %s
2
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
53void takesAttrNonnull(Dummy *p) __attribute((nonnull(1)));
54
55void 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  }
78  case 5: takesAttrNonnull(p); break; // expected-warning {{Nullable pointer is passed to}}
79  default: { Dummy d = *p; } break; // expected-warning {{Nullable pointer is dereferenced}}
80  }
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}
182
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);  // no-warning
242
243  if (getRandom()) {
244    Dummy *_Nonnull varWithInitializer = p; // no-warning
245
246     Dummy *_Nonnull var1WithInitializer = p,  // no-warning
247           *_Nonnull var2WithInitializer = p;  // no-warning
248  }
249
250  if (getRandom()) {
251    Dummy *_Nonnull varWithoutInitializer;
252    varWithoutInitializer = p; // no-warning
253  }
254
255  return p;
256}
257