add quick fix for cast_nullable_to_non_nullable

See: https://github.com/dart-lang/lints/issues/28

Change-Id: Ic0dac81467a3a3fbe7f7bf805ee59e3844edb6a1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/303681
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Phil Quitslund <pquitslund@google.com>
This commit is contained in:
pq 2023-05-17 16:18:54 +00:00 committed by Commit Queue
parent 1b9198c679
commit 1178e96bc1
5 changed files with 58 additions and 3 deletions

View file

@ -16,12 +16,25 @@ import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:analyzer_plugin/utilities/range_factory.dart';
class AddNullCheck extends CorrectionProducer {
final bool skipAssignabilityCheck;
@override
final bool canBeAppliedInBulk;
@override
FixKind fixKind = DartFixKind.ADD_NULL_CHECK;
@override
List<Object>? fixArguments;
AddNullCheck()
: skipAssignabilityCheck = false,
canBeAppliedInBulk = false;
AddNullCheck.withoutAssignabilityCheck()
: skipAssignabilityCheck = true,
canBeAppliedInBulk = true;
@override
Future<void> compute(ChangeBuilder builder) async {
if (!unit.featureSet.isEnabled(Feature.non_nullable)) {
@ -80,6 +93,8 @@ class AddNullCheck extends CorrectionProducer {
target = coveredNode.rightOperand;
}
}
} else if (coveredNode is AsExpression) {
target = coveredNode.expression;
}
if (target == null) {
@ -103,6 +118,8 @@ class AddNullCheck extends CorrectionProducer {
var parent = target.parent;
if (parent is AssignmentExpression && target == parent.rightHandSide) {
toType = parent.writeType;
} else if (parent is AsExpression) {
toType = parent.staticType;
} else if (parent is VariableDeclaration && target == parent.initializer) {
toType = parent.declaredElement?.type;
} else if (parent is ArgumentList) {
@ -156,6 +173,7 @@ class AddNullCheck extends CorrectionProducer {
return;
}
if (toType != null &&
!skipAssignabilityCheck &&
!typeSystem.isAssignableTo(
typeSystem.promoteToNonNull(fromType), toType)) {
// The reason that `fromType` can't be assigned to `toType` is more than

View file

@ -1989,9 +1989,7 @@ LintCode.cancel_subscriptions:
LintCode.cascade_invocations:
status: hasFix
LintCode.cast_nullable_to_non_nullable:
status: needsFix
notes: |-
The fix is to add an explicit null check (`!`).
status: hasFix
LintCode.close_sinks:
status: noFix
LintCode.collection_methods_unrelated_type:

View file

@ -486,6 +486,9 @@ class FixProcessor extends BaseProcessor {
LintNames.cascade_invocations: [
ConvertToCascade.new,
],
LintNames.cast_nullable_to_non_nullable: [
AddNullCheck.withoutAssignabilityCheck,
],
LintNames.combinators_ordering: [
SortCombinators.new,
],

View file

@ -52,6 +52,8 @@ class LintNames {
static const String avoid_void_async = 'avoid_void_async';
static const String await_only_futures = 'await_only_futures';
static const String cascade_invocations = 'cascade_invocations';
static const String cast_nullable_to_non_nullable =
'cast_nullable_to_non_nullable';
static const String combinators_ordering = 'combinators_ordering';
static const String curly_braces_in_flow_control_structures =
'curly_braces_in_flow_control_structures';

View file

@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
@ -14,6 +15,7 @@ void main() {
defineReflectiveSuite(() {
defineReflectiveTests(AddNullCheckTest);
defineReflectiveTests(AddNullCheckReplaceWithNullAwareTest);
defineReflectiveTests(CastNullableToNonNullableTest);
});
}
@ -646,3 +648,35 @@ Iterable<String> f(List<String>? args) sync* {
error.errorCode != CompileTimeErrorCode.YIELD_EACH_OF_INVALID_TYPE);
}
}
@reflectiveTest
class CastNullableToNonNullableTest extends FixProcessorLintTest {
@override
FixKind get kind => DartFixKind.ADD_NULL_CHECK;
@override
String get lintCode => LintNames.cast_nullable_to_non_nullable;
Future<void> test_castNullable() async {
await resolveTestCode(r'''
num? n;
var i = n as int;
''');
await assertHasFix(r'''
num? n;
var i = n! as int;
''');
}
Future<void> test_castNullable_unnecessaryCast() async {
// todo(pq): consider removing unnecessary 'as String' cast
await resolveTestCode(r'''
String? s;
var a = s as String;
''');
await assertHasFix(r'''
String? s;
var a = s! as String;
''');
}
}