Skip to content

Commit 1f99240

Browse files
scheglovcommit-bot@chromium.org
authored andcommitted
Report NOT_INITIALIZED_NON_NULLABLE_STATIC_FIELD.
Change-Id: I0e2b46df212d2534498a181b36066cd05f635700 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/107260 Reviewed-by: Paul Berry <paulberry@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Leaf Petersen <leafp@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
1 parent dd862e7 commit 1f99240

6 files changed

Lines changed: 160 additions & 4 deletions

File tree

pkg/analyzer/lib/error/error.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ const List<ErrorCode> errorCodeValues = const [
237237
CompileTimeErrorCode.NON_SYNC_FACTORY,
238238
CompileTimeErrorCode.NOT_ASSIGNED_POTENTIALLY_NON_NULLABLE_LOCAL_VARIABLE,
239239
CompileTimeErrorCode.NOT_ENOUGH_REQUIRED_ARGUMENTS,
240+
CompileTimeErrorCode.NOT_INITIALIZED_NON_NULLABLE_STATIC_FIELD,
240241
CompileTimeErrorCode.NOT_INITIALIZED_NON_NULLABLE_TOP_LEVEL_VARIABLE,
241242
CompileTimeErrorCode.NOT_ITERABLE_SPREAD,
242243
CompileTimeErrorCode.NOT_MAP_SPREAD,

pkg/analyzer/lib/src/error/codes.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2470,6 +2470,18 @@ class CompileTimeErrorCode extends ErrorCode {
24702470
"{0} required argument(s) expected, but {1} found.",
24712471
correction: "Try adding the missing arguments.");
24722472

2473+
/**
2474+
* It is an error if a static variable with potentially non-nullable type has
2475+
* no initializer expression.
2476+
*
2477+
* Parameters:
2478+
* 0: the name of the field that is invalid
2479+
*/
2480+
static const CompileTimeErrorCode NOT_INITIALIZED_NON_NULLABLE_STATIC_FIELD =
2481+
const CompileTimeErrorCode('NOT_INITIALIZED_NON_NULLABLE_STATIC_FIELD',
2482+
"Non-nullable static field '{0}' must be initialized.",
2483+
correction: "Try adding an initializer expression.");
2484+
24732485
/**
24742486
* It is an error if a top level variable <cut> with potentially non-nullable
24752487
* type has no initializer expression <cut>.

pkg/analyzer/lib/src/generated/error_verifier.dart

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,7 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
718718
}
719719
}
720720
try {
721+
_checkForNotInitializedNonNullableStaticField(node);
721722
super.visitFieldDeclaration(node);
722723
} finally {
723724
_isInStaticVariableDeclaration = false;
@@ -4718,18 +4719,42 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
47184719
}
47194720
}
47204721

4722+
void _checkForNotInitializedNonNullableStaticField(FieldDeclaration node) {
4723+
if (!_isNonNullable) return;
4724+
4725+
if (!node.isStatic) return;
4726+
4727+
var fields = node.fields;
4728+
4729+
// Const and final checked separately.
4730+
if (fields.isConst || fields.isFinal) return;
4731+
4732+
if (fields.type == null) return;
4733+
var type = fields.type.type;
4734+
4735+
if (!_typeSystem.isPotentiallyNonNullable(type)) return;
4736+
4737+
for (var variable in fields.variables) {
4738+
if (variable.initializer == null) {
4739+
_errorReporter.reportErrorForNode(
4740+
CompileTimeErrorCode.NOT_INITIALIZED_NON_NULLABLE_STATIC_FIELD,
4741+
variable.name,
4742+
[variable.name.name],
4743+
);
4744+
}
4745+
}
4746+
}
4747+
47214748
void _checkForNotInitializedNonNullableTopLevelVariable(
47224749
VariableDeclarationList node,
47234750
) {
4751+
if (!_isNonNullable) return;
4752+
47244753
// Const and final checked separately.
47254754
if (node.isConst || node.isFinal) {
47264755
return;
47274756
}
47284757

4729-
if (!_isNonNullable) {
4730-
return;
4731-
}
4732-
47334758
if (node.type == null) {
47344759
return;
47354760
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
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.
4+
5+
import 'package:analyzer/src/dart/analysis/experiments.dart';
6+
import 'package:analyzer/src/error/codes.dart';
7+
import 'package:analyzer/src/generated/engine.dart';
8+
import 'package:test_reflective_loader/test_reflective_loader.dart';
9+
10+
import '../dart/resolution/driver_resolution.dart';
11+
12+
main() {
13+
defineReflectiveSuite(() {
14+
defineReflectiveTests(NotInitializedNonNullableStaticFieldTest);
15+
});
16+
}
17+
18+
@reflectiveTest
19+
class NotInitializedNonNullableStaticFieldTest extends DriverResolutionTest {
20+
@override
21+
AnalysisOptionsImpl get analysisOptions =>
22+
AnalysisOptionsImpl()..enabledExperiments = [EnableString.non_nullable];
23+
24+
test_futureOr_questionArgument_none() async {
25+
assertNoErrorsInCode('''
26+
import 'dart:async';
27+
28+
class A {
29+
static FutureOr<int?> v;
30+
}
31+
''');
32+
}
33+
34+
test_hasInitializer() async {
35+
assertNoErrorsInCode('''
36+
class A {
37+
static int v = 0;
38+
}
39+
''');
40+
}
41+
42+
test_noInitializer() async {
43+
assertErrorsInCode('''
44+
class A {
45+
static int x = 0, y, z = 2;
46+
}
47+
''', [
48+
error(CompileTimeErrorCode.NOT_INITIALIZED_NON_NULLABLE_STATIC_FIELD, 30,
49+
1),
50+
]);
51+
}
52+
53+
test_nullable() async {
54+
assertNoErrorsInCode('''
55+
class A {
56+
static int? v;
57+
}
58+
''');
59+
}
60+
61+
test_type_dynamic() async {
62+
assertNoErrorsInCode('''
63+
class A {
64+
static dynamic v;
65+
}
66+
''');
67+
}
68+
69+
test_type_dynamic_implicit() async {
70+
assertNoErrorsInCode('''
71+
class A {
72+
static var v;
73+
}
74+
''');
75+
}
76+
77+
test_type_never() async {
78+
assertErrorsInCode('''
79+
class A {
80+
static Never v;
81+
}
82+
''', [
83+
error(CompileTimeErrorCode.NOT_INITIALIZED_NON_NULLABLE_STATIC_FIELD, 25,
84+
1),
85+
]);
86+
}
87+
88+
test_type_void() async {
89+
assertNoErrorsInCode('''
90+
class A {
91+
static void v;
92+
}
93+
''');
94+
}
95+
}

pkg/analyzer/test/src/diagnostics/test_all.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ import 'non_constant_spread_expression_from_deferred_library_test.dart'
9898
import 'non_null_opt_out_test.dart' as non_null_opt_out;
9999
import 'not_assigned_potentially_non_nullable_local_variable_test.dart'
100100
as not_assigned_potentially_non_nullable_local_variable;
101+
import 'not_initialized_non_nullable_static_field_test.dart'
102+
as not_initialized_non_nullable_static_field;
101103
import 'not_initialized_non_nullable_top_level_variable_test.dart'
102104
as not_initialized_non_nullable_top_level_variable;
103105
import 'not_iterable_spread_test.dart' as not_iterable_spread;
@@ -240,6 +242,7 @@ main() {
240242
non_constant_spread_expression_from_deferred_library.main();
241243
non_null_opt_out.main();
242244
not_assigned_potentially_non_nullable_local_variable.main();
245+
not_initialized_non_nullable_static_field.main();
243246
not_initialized_non_nullable_top_level_variable.main();
244247
not_iterable_spread.main();
245248
not_map_spread.main();
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
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.
4+
5+
// SharedOptions=--enable-experiment=non-nullable
6+
7+
// Test that it is an error if a static field non-nullable type has no
8+
// initializer expression.
9+
void main() {}
10+
11+
class A {
12+
static int v; //# 01: compile-time error
13+
static int v = 0; //# 02: ok
14+
static int? v; //# 03: ok
15+
static int? v = 0; //# 04: ok
16+
static dynamic v; //# 05: ok
17+
static var v; //# 06: ok
18+
static void v; //# 07: ok
19+
static Never v; //# 08: compile-time error
20+
}

0 commit comments

Comments
 (0)