Report when a potentially nullable type is used in an on clause
Change-Id: I6e9e779d5bb0f37cfd71d4d2dc38c1511c03d59f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/99484
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 3b88ce1..6d2713d 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -235,6 +235,7 @@
CompileTimeErrorCode.NO_ANNOTATION_CONSTRUCTOR_ARGUMENTS,
CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTOR_EXPLICIT,
CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTOR_IMPLICIT,
+ CompileTimeErrorCode.NULLABLE_TYPE_IN_CATCH_CLAUSE,
CompileTimeErrorCode.NULLABLE_TYPE_IN_EXTENDS_CLAUSE,
CompileTimeErrorCode.NULLABLE_TYPE_IN_IMPLEMENTS_CLAUSE,
CompileTimeErrorCode.NULLABLE_TYPE_IN_ON_CLAUSE,
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index f3a75cb..5eda88c4 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -2203,6 +2203,17 @@
"making the called constructor not be a factory constructor.");
/**
+ * It is an error if the type `T` in the on-catch clause `on T catch` is
+ * potentially nullable.
+ */
+ static const CompileTimeErrorCode NULLABLE_TYPE_IN_CATCH_CLAUSE =
+ const CompileTimeErrorCode(
+ 'NULLABLE_TYPE_IN_CATCH_CLAUSE',
+ "A nullable type cannot be used in an 'on' clause because it isn't valid "
+ "to throw 'null'.",
+ correction: "Try removing the question mark.");
+
+ /**
* It is a compile-time error for a class to extend, implement, or mixin a
* type of the form T? for any T.
*/
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 669874e..7f2f741 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -473,6 +473,7 @@
try {
_isInCatchClause = true;
_checkForTypeAnnotationDeferredClass(node.exceptionType);
+ _checkForPotentiallyNullableType(node.exceptionType);
super.visitCatchClause(node);
} finally {
_isInCatchClause = previousIsInCatchClause;
@@ -4718,6 +4719,18 @@
}
/**
+ * Verify that the [type] is not potentially nullable.
+ */
+ void _checkForPotentiallyNullableType(TypeAnnotation type) {
+ if (_options.experimentStatus.non_nullable &&
+ type?.type != null &&
+ _typeSystem.isPotentiallyNullable(type.type)) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.NULLABLE_TYPE_IN_CATCH_CLAUSE, type);
+ }
+ }
+
+ /**
* Check that the given named optional [parameter] does not begin with '_'.
*
* See [CompileTimeErrorCode.PRIVATE_OPTIONAL_PARAMETER].
@@ -5195,7 +5208,7 @@
}
/**
- * Verify that the given type [name] is not a deferred type.
+ * Verify that the [type] is not a deferred type.
*
* See [StaticWarningCode.TYPE_ANNOTATION_DEFERRED_CLASS].
*/
diff --git a/pkg/analyzer/test/src/diagnostics/nullable_type_in_catch_clause_test.dart b/pkg/analyzer/test/src/diagnostics/nullable_type_in_catch_clause_test.dart
new file mode 100644
index 0000000..b500cd6
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/nullable_type_in_catch_clause_test.dart
@@ -0,0 +1,60 @@
+// 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(NullableTypeInCatchClauseTest);
+ });
+}
+
+@reflectiveTest
+class NullableTypeInCatchClauseTest extends DriverResolutionTest {
+ @override
+ AnalysisOptionsImpl get analysisOptions =>
+ AnalysisOptionsImpl()..enabledExperiments = [EnableString.non_nullable];
+
+ test_noOnClause() async {
+ assertNoErrorsInCode('''
+f() {
+ try {
+ } catch (e) {
+ }
+}
+''');
+ }
+
+ test_on_class() async {
+ assertErrorsInCode('''
+class A {}
+f() {
+ try {
+ } on A? {
+ }
+}
+''', [
+ error(CompileTimeErrorCode.NULLABLE_TYPE_IN_CATCH_CLAUSE, 32, 2),
+ ]);
+ }
+
+ test_on_typeParameter() async {
+ assertErrorsInCode('''
+class A<B> {
+ m() {
+ try {
+ } on B {
+ }
+ }
+}
+''', [
+ error(CompileTimeErrorCode.NULLABLE_TYPE_IN_CATCH_CLAUSE, 40, 1),
+ ]);
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index 14f3f20..56a1409 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -86,6 +86,8 @@
import 'null_aware_in_condition_test.dart' as null_aware_in_condition;
import 'null_aware_in_logical_operator_test.dart'
as null_aware_in_logical_operator;
+import 'nullable_type_in_catch_clause_test.dart'
+ as nullable_type_in_catch_clause;
import 'nullable_type_in_extends_clause_test.dart'
as nullable_type_in_extends_clause;
import 'nullable_type_in_implements_clause_test.dart'
@@ -208,6 +210,7 @@
null_aware_before_operator.main();
null_aware_in_condition.main();
null_aware_in_logical_operator.main();
+ nullable_type_in_catch_clause.main();
nullable_type_in_extends_clause.main();
nullable_type_in_implements_clause.main();
nullable_type_in_on_clause.main();