| // 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:analysis_server/src/services/correction/fix.dart'; |
| import 'package:analysis_server/src/services/linter/lint_names.dart'; |
| import 'package:analyzer/dart/ast/ast.dart'; |
| import 'package:analyzer/dart/ast/token.dart'; |
| import 'package:analyzer/error/error.dart'; |
| import 'package:analyzer/source/source_range.dart'; |
| import 'package:analyzer/src/dart/error/hint_codes.dart'; |
| import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart'; |
| import 'package:analyzer_plugin/utilities/fixes/fixes.dart'; |
| import 'package:analyzer_plugin/utilities/range_factory.dart'; |
| |
| class RemoveComparison extends CorrectionProducer { |
| @override |
| bool get canBeAppliedInBulk => true; |
| |
| @override |
| bool get canBeAppliedToFile => true; |
| |
| @override |
| FixKind get fixKind => DartFixKind.REMOVE_COMPARISON; |
| |
| @override |
| FixKind get multiFixKind => DartFixKind.REMOVE_COMPARISON_MULTI; |
| |
| /// Return `true` if the null comparison will always return `false`. |
| bool get _conditionIsFalse => |
| (diagnostic as AnalysisError).errorCode == |
| HintCode.UNNECESSARY_NULL_COMPARISON_FALSE; |
| |
| /// Return `true` if the null comparison will always return `true`. |
| bool get _conditionIsTrue { |
| var errorCode = (diagnostic as AnalysisError).errorCode; |
| return errorCode == HintCode.UNNECESSARY_NULL_COMPARISON_TRUE || |
| errorCode.name == LintNames.avoid_null_checks_in_equality_operators; |
| } |
| |
| @override |
| Future<void> compute(ChangeBuilder builder) async { |
| var binaryExpression = node; |
| if (binaryExpression is! BinaryExpression) { |
| return; |
| } |
| var parent = binaryExpression.parent; |
| if (parent is AssertInitializer && _conditionIsTrue) { |
| var constructor = parent.parent as ConstructorDeclaration; |
| var list = constructor.initializers; |
| if (list.length == 1) { |
| await builder.addDartFileEdit(file, (builder) { |
| builder.addDeletion(range.endEnd(constructor.parameters, parent)); |
| }); |
| } else { |
| await builder.addDartFileEdit(file, (builder) { |
| builder.addDeletion(range.nodeInList(list, parent)); |
| }); |
| } |
| } else if (parent is AssertStatement && _conditionIsTrue) { |
| await builder.addDartFileEdit(file, (builder) { |
| builder.addDeletion(utils.getLinesRange(range.node(parent))); |
| }); |
| } else if (parent is BinaryExpression) { |
| if (parent.operator.type == TokenType.AMPERSAND_AMPERSAND && |
| _conditionIsTrue) { |
| await _removeOperatorAndOperand(builder, parent, binaryExpression); |
| } else if (parent.operator.type == TokenType.BAR_BAR && |
| _conditionIsFalse) { |
| await _removeOperatorAndOperand(builder, parent, binaryExpression); |
| } |
| } else if (parent is IfStatement) { |
| if (parent.elseStatement == null && _conditionIsTrue) { |
| await _ifStatement(parent, builder); |
| } |
| } |
| } |
| |
| Future<void> _ifStatement(IfStatement node, ChangeBuilder builder) async { |
| await builder.addDartFileEdit(file, (builder) { |
| var nodeRange = utils.getLinesRangeStatements([node]); |
| |
| String bodyCode; |
| var body = node.thenStatement; |
| if (body is Block) { |
| var statements = body.statements; |
| if (statements.isEmpty) { |
| builder.addDeletion(nodeRange); |
| return; |
| } else { |
| bodyCode = utils.getRangeText( |
| utils.getLinesRangeStatements(statements), |
| ); |
| } |
| } else { |
| bodyCode = utils.getRangeText( |
| utils.getLinesRangeStatements([body]), |
| ); |
| } |
| |
| bodyCode = utils.indentSourceLeftRight(bodyCode); |
| builder.addSimpleReplacement(nodeRange, bodyCode); |
| }); |
| } |
| |
| /// Use the [builder] to add an edit to delete the operator and given |
| /// [operand] from the [binary] expression. |
| Future<void> _removeOperatorAndOperand(ChangeBuilder builder, |
| BinaryExpression binary, Expression operand) async { |
| SourceRange operatorAndOperand; |
| if (binary.leftOperand == node) { |
| operatorAndOperand = range.startStart(node, binary.rightOperand); |
| } else { |
| operatorAndOperand = range.endEnd(binary.leftOperand, node); |
| } |
| await builder.addDartFileEdit(file, (builder) { |
| builder.addDeletion(operatorAndOperand); |
| }); |
| } |
| } |