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>
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 515584d..e59f4c9 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -237,6 +237,7 @@
CompileTimeErrorCode.NON_SYNC_FACTORY,
CompileTimeErrorCode.NOT_ASSIGNED_POTENTIALLY_NON_NULLABLE_LOCAL_VARIABLE,
CompileTimeErrorCode.NOT_ENOUGH_REQUIRED_ARGUMENTS,
+ CompileTimeErrorCode.NOT_INITIALIZED_NON_NULLABLE_STATIC_FIELD,
CompileTimeErrorCode.NOT_INITIALIZED_NON_NULLABLE_TOP_LEVEL_VARIABLE,
CompileTimeErrorCode.NOT_ITERABLE_SPREAD,
CompileTimeErrorCode.NOT_MAP_SPREAD,
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index d1312e3..12c0a1b 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -2471,6 +2471,18 @@
correction: "Try adding the missing arguments.");
/**
+ * It is an error if a static variable with potentially non-nullable type has
+ * no initializer expression.
+ *
+ * Parameters:
+ * 0: the name of the field that is invalid
+ */
+ static const CompileTimeErrorCode NOT_INITIALIZED_NON_NULLABLE_STATIC_FIELD =
+ const CompileTimeErrorCode('NOT_INITIALIZED_NON_NULLABLE_STATIC_FIELD',
+ "Non-nullable static field '{0}' must be initialized.",
+ correction: "Try adding an initializer expression.");
+
+ /**
* It is an error if a top level variable <cut> with potentially non-nullable
* type has no initializer expression <cut>.
*
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 880545a..f618d02 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -718,6 +718,7 @@
}
}
try {
+ _checkForNotInitializedNonNullableStaticField(node);
super.visitFieldDeclaration(node);
} finally {
_isInStaticVariableDeclaration = false;
@@ -4718,18 +4719,42 @@
}
}
+ void _checkForNotInitializedNonNullableStaticField(FieldDeclaration node) {
+ if (!_isNonNullable) return;
+
+ if (!node.isStatic) return;
+
+ var fields = node.fields;
+
+ // Const and final checked separately.
+ if (fields.isConst || fields.isFinal) return;
+
+ if (fields.type == null) return;
+ var type = fields.type.type;
+
+ if (!_typeSystem.isPotentiallyNonNullable(type)) return;
+
+ for (var variable in fields.variables) {
+ if (variable.initializer == null) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.NOT_INITIALIZED_NON_NULLABLE_STATIC_FIELD,
+ variable.name,
+ [variable.name.name],
+ );
+ }
+ }
+ }
+
void _checkForNotInitializedNonNullableTopLevelVariable(
VariableDeclarationList node,
) {
+ if (!_isNonNullable) return;
+
// Const and final checked separately.
if (node.isConst || node.isFinal) {
return;
}
- if (!_isNonNullable) {
- return;
- }
-
if (node.type == null) {
return;
}
diff --git a/pkg/analyzer/test/src/diagnostics/not_initialized_non_nullable_static_field_test.dart b/pkg/analyzer/test/src/diagnostics/not_initialized_non_nullable_static_field_test.dart
new file mode 100644
index 0000000..233eb2b
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/not_initialized_non_nullable_static_field_test.dart
@@ -0,0 +1,95 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/dart/analysis/experiments.dart';
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(NotInitializedNonNullableStaticFieldTest);
+ });
+}
+
+@reflectiveTest
+class NotInitializedNonNullableStaticFieldTest extends DriverResolutionTest {
+ @override
+ AnalysisOptionsImpl get analysisOptions =>
+ AnalysisOptionsImpl()..enabledExperiments = [EnableString.non_nullable];
+
+ test_futureOr_questionArgument_none() async {
+ assertNoErrorsInCode('''
+import 'dart:async';
+
+class A {
+ static FutureOr<int?> v;
+}
+''');
+ }
+
+ test_hasInitializer() async {
+ assertNoErrorsInCode('''
+class A {
+ static int v = 0;
+}
+''');
+ }
+
+ test_noInitializer() async {
+ assertErrorsInCode('''
+class A {
+ static int x = 0, y, z = 2;
+}
+''', [
+ error(CompileTimeErrorCode.NOT_INITIALIZED_NON_NULLABLE_STATIC_FIELD, 30,
+ 1),
+ ]);
+ }
+
+ test_nullable() async {
+ assertNoErrorsInCode('''
+class A {
+ static int? v;
+}
+''');
+ }
+
+ test_type_dynamic() async {
+ assertNoErrorsInCode('''
+class A {
+ static dynamic v;
+}
+''');
+ }
+
+ test_type_dynamic_implicit() async {
+ assertNoErrorsInCode('''
+class A {
+ static var v;
+}
+''');
+ }
+
+ test_type_never() async {
+ assertErrorsInCode('''
+class A {
+ static Never v;
+}
+''', [
+ error(CompileTimeErrorCode.NOT_INITIALIZED_NON_NULLABLE_STATIC_FIELD, 25,
+ 1),
+ ]);
+ }
+
+ test_type_void() async {
+ assertNoErrorsInCode('''
+class A {
+ static void v;
+}
+''');
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index bfd21cf..810392d 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -98,6 +98,8 @@
import 'non_null_opt_out_test.dart' as non_null_opt_out;
import 'not_assigned_potentially_non_nullable_local_variable_test.dart'
as not_assigned_potentially_non_nullable_local_variable;
+import 'not_initialized_non_nullable_static_field_test.dart'
+ as not_initialized_non_nullable_static_field;
import 'not_initialized_non_nullable_top_level_variable_test.dart'
as not_initialized_non_nullable_top_level_variable;
import 'not_iterable_spread_test.dart' as not_iterable_spread;
@@ -240,6 +242,7 @@
non_constant_spread_expression_from_deferred_library.main();
non_null_opt_out.main();
not_assigned_potentially_non_nullable_local_variable.main();
+ not_initialized_non_nullable_static_field.main();
not_initialized_non_nullable_top_level_variable.main();
not_iterable_spread.main();
not_map_spread.main();
diff --git a/tests/language_2/nnbd/static_errors/not_initialized_non_nullable_static_field_test.dart b/tests/language_2/nnbd/static_errors/not_initialized_non_nullable_static_field_test.dart
new file mode 100644
index 0000000..a70142e
--- /dev/null
+++ b/tests/language_2/nnbd/static_errors/not_initialized_non_nullable_static_field_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// SharedOptions=--enable-experiment=non-nullable
+
+// Test that it is an error if a static field non-nullable type has no
+// initializer expression.
+void main() {}
+
+class A {
+ static int v; //# 01: compile-time error
+ static int v = 0; //# 02: ok
+ static int? v; //# 03: ok
+ static int? v = 0; //# 04: ok
+ static dynamic v; //# 05: ok
+ static var v; //# 06: ok
+ static void v; //# 07: ok
+ static Never v; //# 08: compile-time error
+}