blob: dfa930568a56220858c0c4e939561b7bc5621f13 [file] [log] [blame]
// 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:_fe_analyzer_shared/src/scanner/token.dart';
import 'package:analysis_server/src/services/correction/assist.dart';
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer_plugin/utilities/assist/assist.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
import 'package:analyzer_plugin/utilities/range_factory.dart';
class JoinVariableDeclaration extends CorrectionProducer {
@override
AssistKind get assistKind => DartAssistKind.JOIN_VARIABLE_DECLARATION;
@override
Future<void> compute(ChangeBuilder builder) async {
if (node is SimpleIdentifier) {
var parent = node.parent;
if (parent is AssignmentExpression &&
parent.leftHandSide == node &&
parent.parent is ExpressionStatement) {
await _joinOnAssignment(builder, parent);
return;
}
}
var declList = node.thisOrAncestorOfType<VariableDeclarationList>();
if (declList != null && declList.variables.length == 1) {
await _joinOnDeclaration(builder, declList);
}
}
/// Join the declaration when the variable is on the left-hand side of an
/// assignment.
Future<void> _joinOnAssignment(
ChangeBuilder builder, AssignmentExpression assignExpression) async {
// Check that assignment is not a compound assignment.
if (assignExpression.operator.type != TokenType.EQ) {
return;
}
// prepare "declaration" statement
var element = (node as SimpleIdentifier).staticElement;
if (element == null) {
return;
}
var declOffset = element.nameOffset;
var unit = resolvedResult.unit;
var declNode = NodeLocator(declOffset).searchWithin(unit);
if (declNode != null &&
declNode.parent is VariableDeclaration &&
(declNode.parent as VariableDeclaration).name == declNode &&
declNode.parent.parent is VariableDeclarationList &&
declNode.parent.parent.parent is VariableDeclarationStatement) {
} else {
return;
}
var decl = declNode.parent as VariableDeclaration;
var declStatement = decl.parent.parent as VariableDeclarationStatement;
// may be has initializer
if (decl.initializer != null) {
return;
}
// check that "declaration" statement declared only one variable
if (declStatement.variables.variables.length != 1) {
return;
}
// check that the "declaration" and "assignment" statements are
// parts of the same Block
var assignStatement = node.parent.parent as ExpressionStatement;
if (assignStatement.parent is Block &&
assignStatement.parent == declStatement.parent) {
} else {
return;
}
var block = assignStatement.parent as Block;
// check that "declaration" and "assignment" statements are adjacent
List<Statement> statements = block.statements;
if (statements.indexOf(assignStatement) ==
statements.indexOf(declStatement) + 1) {
} else {
return;
}
await builder.addDartFileEdit(file, (builder) {
builder.addSimpleReplacement(
range.endStart(declNode, assignExpression.operator), ' ');
});
}
/// Join the declaration when the variable is on the left-hand side of an
/// assignment.
Future<void> _joinOnDeclaration(
ChangeBuilder builder, VariableDeclarationList declList) async {
// prepare enclosing VariableDeclarationList
var decl = declList.variables[0];
// already initialized
if (decl.initializer != null) {
return;
}
// prepare VariableDeclarationStatement in Block
if (declList.parent is VariableDeclarationStatement &&
declList.parent.parent is Block) {
} else {
return;
}
var declStatement = declList.parent as VariableDeclarationStatement;
var block = declStatement.parent as Block;
List<Statement> statements = block.statements;
// prepare assignment
// declaration should not be last Statement
var declIndex = statements.indexOf(declStatement);
if (declIndex < statements.length - 1) {
} else {
return;
}
// next Statement should be assignment
var assignStatement = statements[declIndex + 1];
if (assignStatement is ExpressionStatement) {
} else {
return;
}
var expressionStatement = assignStatement as ExpressionStatement;
// expression should be assignment
if (expressionStatement.expression is AssignmentExpression) {
} else {
return;
}
var assignExpression =
expressionStatement.expression as AssignmentExpression;
// check that pure assignment
if (assignExpression.operator.type != TokenType.EQ) {
return;
}
await builder.addDartFileEdit(file, (builder) {
builder.addSimpleReplacement(
range.endStart(decl.name, assignExpression.operator), ' ');
});
}
/// Return an instance of this class. Used as a tear-off in `AssistProcessor`.
static JoinVariableDeclaration newInstance() => JoinVariableDeclaration();
}