OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 // These tests are for an experimental feature that treats Dart primitive types | 5 // These tests are for an experimental feature that treats Dart primitive types |
6 // (int, bool, double, etc.) as non-nullable. This file is not evidence for an | 6 // (int, bool, double, etc.) as non-nullable. This file is not evidence for an |
7 // intention to officially support non-nullable primitives in Dart (or general | 7 // intention to officially support non-nullable primitives in Dart (or general |
8 // NNBD, for that matter) so don't get too crazy about it. | 8 // NNBD, for that matter) so don't get too crazy about it. |
9 | 9 |
10 library analyzer.test.src.task.non_null_primitives.checker_test; | 10 library analyzer.test.src.task.non_null_primitives.checker_test; |
11 | 11 |
12 import 'package:test_reflective_loader/test_reflective_loader.dart'; | 12 import 'package:test_reflective_loader/test_reflective_loader.dart'; |
13 | 13 |
14 import '../strong/strong_test_helper.dart'; | 14 import '../strong/strong_test_helper.dart'; |
15 | 15 |
16 void main() { | 16 void main() { |
17 initStrongModeTests(); | 17 defineReflectiveSuite(() { |
18 defineReflectiveTests(NonNullCheckerTest); | 18 defineReflectiveTests(NonNullCheckerTest); |
| 19 }); |
19 } | 20 } |
20 | 21 |
21 String _withError(String file, String error) { | 22 String _withError(String file, String error) { |
22 return ("" + file).replaceFirst("boom", error); | 23 return ("" + file).replaceFirst("boom", error); |
23 } | 24 } |
24 | 25 |
25 @reflectiveTest | 26 @reflectiveTest |
26 class NonNullCheckerTest { | 27 class NonNullCheckerTest { |
27 // Tests simple usage of ints as iterators for a loop. Not directly related to | 28 // Tests simple usage of ints as iterators for a loop. Not directly related to |
28 // non-nullability, but if it is implemented this should be more efficient, | 29 // non-nullability, but if it is implemented this should be more efficient, |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
66 } | 67 } |
67 | 68 |
68 void main() { | 69 void main() { |
69 bool f = false; // Necessary, because dead code is otherwise detected. | 70 bool f = false; // Necessary, because dead code is otherwise detected. |
70 Point p1 = new Point(0, 0); | 71 Point p1 = new Point(0, 0); |
71 Point p2 = new Point(10, /*boom*/f ? 10 : null); // Change here. | 72 Point p2 = new Point(10, /*boom*/f ? 10 : null); // Change here. |
72 print("p1 + p2 = \${p1 + p2}"); | 73 print("p1 + p2 = \${p1 + p2}"); |
73 } | 74 } |
74 '''; | 75 '''; |
75 | 76 |
| 77 void setUp() { |
| 78 doSetUp(); |
| 79 } |
| 80 |
| 81 void tearDown() { |
| 82 doTearDown(); |
| 83 } |
| 84 |
76 void test_assign_null_to_nonnullable() { | 85 void test_assign_null_to_nonnullable() { |
77 addFile(''' | 86 addFile(''' |
78 int x = 0; | 87 int x = 0; |
79 | 88 |
80 main() { | 89 main() { |
81 x = 1; | 90 x = 1; |
82 x = /*error:INVALID_ASSIGNMENT*/null; | 91 x = /*error:INVALID_ASSIGNMENT*/null; |
83 } | 92 } |
84 '''); | 93 '''); |
85 check(nonnullableTypes: <String>['dart:core,int']); | 94 check(nonnullableTypes: <String>['dart:core,int']); |
86 } | 95 } |
87 | 96 |
88 void test_forLoop() { | |
89 checkFile(''' | |
90 class MyList { | |
91 int length; | |
92 MyList() { | |
93 length = 6; | |
94 } | |
95 String operator [](int i) { | |
96 return <String>["Dart", "Java", "JS", "C", "C++", "C#"][i]; | |
97 } | |
98 } | |
99 | |
100 main() { | |
101 var languages = new MyList(); | |
102 for (int i = 0; i < languages.length; ++i) { | |
103 print(languages[i]); | |
104 } | |
105 } | |
106 '''); | |
107 } | |
108 | |
109 void test_compoundAssignment() { | 97 void test_compoundAssignment() { |
110 addFile(''' | 98 addFile(''' |
111 void main() { | 99 void main() { |
112 int i = 1; | 100 int i = 1; |
113 i += 2; | 101 i += 2; |
114 /*error:INVALID_ASSIGNMENT*/i += null; | 102 /*error:INVALID_ASSIGNMENT*/i += null; |
115 print(i); | 103 print(i); |
116 } | 104 } |
117 '''); | 105 '''); |
118 check(nonnullableTypes: <String>['dart:core,int']); | 106 check(nonnullableTypes: <String>['dart:core,int']); |
119 } | 107 } |
120 | 108 |
121 void test_forEach() { | 109 void test_forEach() { |
122 addFile(''' | 110 addFile(''' |
123 void main() { | 111 void main() { |
124 var ints = <num>[1, 2, 3, null]; | 112 var ints = <num>[1, 2, 3, null]; |
125 for (int /*error:INVALID_ASSIGNMENT*/i in ints) { | 113 for (int /*error:INVALID_ASSIGNMENT*/i in ints) { |
126 print(i); | 114 print(i); |
127 } | 115 } |
128 } | 116 } |
129 '''); | 117 '''); |
130 check(nonnullableTypes: <String>['dart:core,int']); | 118 check(nonnullableTypes: <String>['dart:core,int']); |
131 } | 119 } |
132 | 120 |
133 void test_initialize_nonnullable_with_null() { | 121 void test_forLoop() { |
134 addFile('int x = /*error:INVALID_ASSIGNMENT*/null;'); | 122 checkFile(''' |
135 check(nonnullableTypes: <String>['dart:core,int']); | 123 class MyList { |
| 124 int length; |
| 125 MyList() { |
| 126 length = 6; |
136 } | 127 } |
| 128 String operator [](int i) { |
| 129 return <String>["Dart", "Java", "JS", "C", "C++", "C#"][i]; |
| 130 } |
| 131 } |
137 | 132 |
138 void test_initialize_nonnullable_with_valid_value() { | 133 main() { |
139 addFile('int x = 0;'); | 134 var languages = new MyList(); |
140 check(nonnullableTypes: <String>['dart:core,int']); | 135 for (int i = 0; i < languages.length; ++i) { |
| 136 print(languages[i]); |
141 } | 137 } |
142 | |
143 void test_nonnullable_fields() { | |
144 addFile(defaultNnbdExample); | |
145 // `null` can be passed as an argument to `Point` in default mode. | |
146 addFile(_withError(defaultNnbdExampleMod1, "error:INVALID_ASSIGNMENT")); | |
147 // A nullable expression can be passed as an argument to `Point` in default | |
148 // mode. | |
149 addFile(_withError(defaultNnbdExampleMod2, "error:INVALID_ASSIGNMENT")); | |
150 check(nonnullableTypes: <String>['dart:core,int']); | |
151 } | |
152 | |
153 void test_nullable_fields() { | |
154 addFile(defaultNnbdExample); | |
155 // `null` can be passed as an argument to `Point` in default mode. | |
156 addFile(defaultNnbdExampleMod1); | |
157 // A nullable expression can be passed as an argument to `Point` in default | |
158 // mode. | |
159 addFile(defaultNnbdExampleMod2); | |
160 check(); | |
161 } | |
162 | |
163 // Default example from NNBD document. | |
164 void test_nullableTypes() { | |
165 // By default x can be set to null. | |
166 checkFile('int x = null;'); | |
167 } | |
168 | |
169 void test_prefer_final_to_non_nullable_error() { | |
170 addFile('main() { final int /*error:FINAL_NOT_INITIALIZED*/x; }'); | |
171 addFile('final int /*error:FINAL_NOT_INITIALIZED*/x;'); | |
172 addFile(''' | |
173 void foo() {} | |
174 | |
175 class A { | |
176 final int x; | |
177 | |
178 /*warning:FINAL_NOT_INITIALIZED_CONSTRUCTOR_1*/A(); | |
179 } | 138 } |
180 '''); | 139 '''); |
181 check(nonnullableTypes: <String>['dart:core,int']); | |
182 } | |
183 | |
184 void test_uninitialized_nonnullable_field_declaration() { | |
185 addFile(''' | |
186 void foo() {} | |
187 | |
188 class A { | |
189 // Ideally, we should allow x to be init in the constructor, but that requires | |
190 // too much complication in the checker, so for now we throw a static error at | |
191 // the declaration site. | |
192 int /*error:NON_NULLABLE_FIELD_NOT_INITIALIZED*/x; | |
193 | |
194 A(); | |
195 } | |
196 '''); | |
197 check(nonnullableTypes: <String>['dart:core,int']); | |
198 } | |
199 | |
200 void test_uninitialized_nonnullable_local_variable() { | |
201 // Ideally, we will do flow analysis and throw an error only if a variable | |
202 // is used before it has been initialized. | |
203 addFile('main() { int /*error:NON_NULLABLE_FIELD_NOT_INITIALIZED*/x; }'); | |
204 check(nonnullableTypes: <String>['dart:core,int']); | |
205 } | |
206 | |
207 void test_uninitialized_nonnullable_top_level_variable_declaration() { | |
208 // If `int`s are non-nullable, then this code should throw an error. | |
209 addFile('int /*error:NON_NULLABLE_FIELD_NOT_INITIALIZED*/x;'); | |
210 check(nonnullableTypes: <String>['dart:core,int']); | |
211 } | |
212 | |
213 void test_method_call() { | |
214 addFile(''' | |
215 int s(int x) { | |
216 return x + 1; | |
217 } | |
218 | |
219 void main() { | |
220 s(10); | |
221 s(/*error:INVALID_ASSIGNMENT*/null); | |
222 } | |
223 '''); | |
224 check(nonnullableTypes: <String>['dart:core,int']); | |
225 } | 140 } |
226 | 141 |
227 void test_generics() { | 142 void test_generics() { |
228 addFile(''' | 143 addFile(''' |
229 class Foo<T> { | 144 class Foo<T> { |
230 T x; | 145 T x; |
231 | 146 |
232 Foo(this.x); | 147 Foo(this.x); |
233 } | 148 } |
234 | 149 |
(...skipping 17 matching lines...) Expand all Loading... |
252 } | 167 } |
253 | 168 |
254 void main() { | 169 void main() { |
255 var f = new Foo<String>(); | 170 var f = new Foo<String>(); |
256 var g = new Foo<int>(); // Should fail at runtime. | 171 var g = new Foo<int>(); // Should fail at runtime. |
257 } | 172 } |
258 '''); | 173 '''); |
259 check(nonnullableTypes: <String>['dart:core,int']); | 174 check(nonnullableTypes: <String>['dart:core,int']); |
260 } | 175 } |
261 | 176 |
| 177 void test_initialize_nonnullable_with_null() { |
| 178 addFile('int x = /*error:INVALID_ASSIGNMENT*/null;'); |
| 179 check(nonnullableTypes: <String>['dart:core,int']); |
| 180 } |
| 181 |
| 182 void test_initialize_nonnullable_with_valid_value() { |
| 183 addFile('int x = 0;'); |
| 184 check(nonnullableTypes: <String>['dart:core,int']); |
| 185 } |
| 186 |
262 void test_map() { | 187 void test_map() { |
263 addFile(''' | 188 addFile(''' |
264 class Pair<K, V> { | 189 class Pair<K, V> { |
265 K first; | 190 K first; |
266 V second; | 191 V second; |
267 | 192 |
268 Pair(this.first, this.second); | 193 Pair(this.first, this.second); |
269 } | 194 } |
270 | 195 |
271 class SlowMap<K, V> { | 196 class SlowMap<K, V> { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
305 legs.insert("spider", 8); | 230 legs.insert("spider", 8); |
306 legs.insert("goat", 4); | 231 legs.insert("goat", 4); |
307 legs.insert("chicken", 2); | 232 legs.insert("chicken", 2); |
308 | 233 |
309 int x = legs.get("goat"); // This should not produce an error. | 234 int x = legs.get("goat"); // This should not produce an error. |
310 int y = legs.get("sheep"); // TODO(stanm): Runtime error here. | 235 int y = legs.get("sheep"); // TODO(stanm): Runtime error here. |
311 } | 236 } |
312 '''); | 237 '''); |
313 check(nonnullableTypes: <String>['dart:core,int']); | 238 check(nonnullableTypes: <String>['dart:core,int']); |
314 } | 239 } |
| 240 |
| 241 // Default example from NNBD document. |
| 242 void test_method_call() { |
| 243 addFile(''' |
| 244 int s(int x) { |
| 245 return x + 1; |
315 } | 246 } |
| 247 |
| 248 void main() { |
| 249 s(10); |
| 250 s(/*error:INVALID_ASSIGNMENT*/null); |
| 251 } |
| 252 '''); |
| 253 check(nonnullableTypes: <String>['dart:core,int']); |
| 254 } |
| 255 |
| 256 void test_nonnullable_fields() { |
| 257 addFile(defaultNnbdExample); |
| 258 // `null` can be passed as an argument to `Point` in default mode. |
| 259 addFile(_withError(defaultNnbdExampleMod1, "error:INVALID_ASSIGNMENT")); |
| 260 // A nullable expression can be passed as an argument to `Point` in default |
| 261 // mode. |
| 262 addFile(_withError(defaultNnbdExampleMod2, "error:INVALID_ASSIGNMENT")); |
| 263 check(nonnullableTypes: <String>['dart:core,int']); |
| 264 } |
| 265 |
| 266 void test_nullable_fields() { |
| 267 addFile(defaultNnbdExample); |
| 268 // `null` can be passed as an argument to `Point` in default mode. |
| 269 addFile(defaultNnbdExampleMod1); |
| 270 // A nullable expression can be passed as an argument to `Point` in default |
| 271 // mode. |
| 272 addFile(defaultNnbdExampleMod2); |
| 273 check(); |
| 274 } |
| 275 |
| 276 void test_nullableTypes() { |
| 277 // By default x can be set to null. |
| 278 checkFile('int x = null;'); |
| 279 } |
| 280 |
| 281 void test_prefer_final_to_non_nullable_error() { |
| 282 addFile('main() { final int /*error:FINAL_NOT_INITIALIZED*/x; }'); |
| 283 addFile('final int /*error:FINAL_NOT_INITIALIZED*/x;'); |
| 284 addFile(''' |
| 285 void foo() {} |
| 286 |
| 287 class A { |
| 288 final int x; |
| 289 |
| 290 /*warning:FINAL_NOT_INITIALIZED_CONSTRUCTOR_1*/A(); |
| 291 } |
| 292 '''); |
| 293 check(nonnullableTypes: <String>['dart:core,int']); |
| 294 } |
| 295 |
| 296 void test_uninitialized_nonnullable_field_declaration() { |
| 297 addFile(''' |
| 298 void foo() {} |
| 299 |
| 300 class A { |
| 301 // Ideally, we should allow x to be init in the constructor, but that requires |
| 302 // too much complication in the checker, so for now we throw a static error at |
| 303 // the declaration site. |
| 304 int /*error:NON_NULLABLE_FIELD_NOT_INITIALIZED*/x; |
| 305 |
| 306 A(); |
| 307 } |
| 308 '''); |
| 309 check(nonnullableTypes: <String>['dart:core,int']); |
| 310 } |
| 311 |
| 312 void test_uninitialized_nonnullable_local_variable() { |
| 313 // Ideally, we will do flow analysis and throw an error only if a variable |
| 314 // is used before it has been initialized. |
| 315 addFile('main() { int /*error:NON_NULLABLE_FIELD_NOT_INITIALIZED*/x; }'); |
| 316 check(nonnullableTypes: <String>['dart:core,int']); |
| 317 } |
| 318 |
| 319 void test_uninitialized_nonnullable_top_level_variable_declaration() { |
| 320 // If `int`s are non-nullable, then this code should throw an error. |
| 321 addFile('int /*error:NON_NULLABLE_FIELD_NOT_INITIALIZED*/x;'); |
| 322 check(nonnullableTypes: <String>['dart:core,int']); |
| 323 } |
| 324 } |
OLD | NEW |