Add a fix to remove dead null-aware operators
Change-Id: I4573eb87b1e454923655b2b7010ab84f4698ce79
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/136922
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/remove_dead_if_null.dart b/pkg/analysis_server/lib/src/services/correction/dart/remove_dead_if_null.dart
new file mode 100644
index 0000000..ceb57b5
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/correction/dart/remove_dead_if_null.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2020, 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:analysis_server/src/services/correction/dart/abstract_producer.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/source/source_range.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
+import 'package:analyzer_plugin/utilities/range_factory.dart';
+
+class RemoveDeadIfNull extends CorrectionProducer {
+ @override
+ Future<void> compute(DartChangeBuilder builder) async {
+ //
+ // Find the dead if-null expression.
+ //
+ BinaryExpression findIfNull() {
+ var child = node;
+ var parent = node.parent;
+ while (parent != null) {
+ if (parent is BinaryExpression &&
+ parent.operator.type == TokenType.QUESTION_QUESTION &&
+ parent.rightOperand == child) {
+ return parent;
+ }
+ child = parent;
+ parent = parent.parent;
+ }
+ return null;
+ }
+
+ var expression = findIfNull();
+ if (expression == null) {
+ return;
+ }
+ //
+ // Extract the information needed to build the edit.
+ //
+ SourceRange sourceRange =
+ range.endEnd(expression.leftOperand, expression.rightOperand);
+ //
+ // Build the edit.
+ //
+ await builder.addFileEdit(file, (DartFileEditBuilder builder) {
+ builder.addDeletion(sourceRange);
+ });
+ }
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 3aaa193..236f62b 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -18,6 +18,7 @@
import 'package:analysis_server/src/services/correction/dart/convert_to_null_aware.dart';
import 'package:analysis_server/src/services/correction/dart/convert_to_set_literal.dart';
import 'package:analysis_server/src/services/correction/dart/convert_to_where_type.dart';
+import 'package:analysis_server/src/services/correction/dart/remove_dead_if_null.dart';
import 'package:analysis_server/src/services/correction/dart/remove_if_null_operator.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analysis_server/src/services/correction/fix/dart/top_level_declarations.dart';
@@ -4697,7 +4698,12 @@
}
var errorCode = error.errorCode;
- if (errorCode is LintCode) {
+ if (errorCode == StaticWarningCode.DEAD_NULL_AWARE_EXPRESSION) {
+ await compute(
+ RemoveDeadIfNull(),
+ DartFixKind.REMOVE_IF_NULL_OPERATOR,
+ );
+ } else if (errorCode is LintCode) {
String name = errorCode.name;
if (name == LintNames.prefer_collection_literals) {
await compute(
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_if_null_operator_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_if_null_operator_test.dart
index 17c760d..20529c8 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_if_null_operator_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_if_null_operator_test.dart
@@ -11,12 +11,43 @@
void main() {
defineReflectiveSuite(() {
- defineReflectiveTests(RemoveIfNullOperatorTest);
+ defineReflectiveTests(DeadNullAwareExpressionTest);
+ defineReflectiveTests(UnnecessaryNullInIfNullOperatorsTest);
});
}
@reflectiveTest
-class RemoveIfNullOperatorTest extends FixProcessorLintTest {
+class DeadNullAwareExpressionTest extends FixProcessorTest {
+ @override
+ FixKind get kind => DartFixKind.REMOVE_IF_NULL_OPERATOR;
+
+ @override
+ void setUp() {
+ super.setUp();
+ createAnalysisOptionsFile(experiments: ['non-nullable']);
+ }
+
+ Future<void> test_immediateChild() async {
+ await resolveTestUnit('''
+int f(int a, int b) => a ?? b;
+''');
+ await assertHasFix('''
+int f(int a, int b) => a;
+''');
+ }
+
+ Future<void> test_nestedChild() async {
+ await resolveTestUnit('''
+int f(int a, int b) => a ?? b * 2 + 1;
+''');
+ await assertHasFix('''
+int f(int a, int b) => a;
+''');
+ }
+}
+
+@reflectiveTest
+class UnnecessaryNullInIfNullOperatorsTest extends FixProcessorLintTest {
@override
FixKind get kind => DartFixKind.REMOVE_IF_NULL_OPERATOR;