blob: 4b68e3da9955471331ba873b8c3b2a73890d68c3 [file] [log] [blame]
Gabor Horvath28690922015-08-26 23:17:43 +00001// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.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 testBasicRules() {
54 Dummy *p = returnsNullable();
55 int *ptr = returnsNullableInt();
56 // Make every dereference a different path to avoid sinks after errors.
57 switch (getRandom()) {
58 case 0: {
59 Dummy &r = *p; // expected-warning {{}}
60 } break;
61 case 1: {
62 int b = p->val; // expected-warning {{}}
63 } break;
64 case 2: {
65 int stuff = *ptr; // expected-warning {{}}
66 } break;
67 case 3:
68 takesNonnull(p); // expected-warning {{}}
69 break;
70 case 4: {
71 Dummy d;
72 takesNullable(&d);
73 Dummy dd(d);
74 break;
75 }
76 // Here the copy constructor is called, so a reference is initialized with the
77 // value of p. No ImplicitNullDereference event will be dispatched for this
78 // case. A followup patch is expected to fix this in NonNullParamChecker.
79 default: { Dummy d = *p; } break; // No warning.
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}