blob: 63cea997d98fc486e2c56b0cc87fcc8e275c6739 [file] [log] [blame]
// Copyright (c) 2022, 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:analyzer/dart/ast/ast.dart';
import 'package:analyzer/source/source_range.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 ConvertToFunctionDeclaration extends CorrectionProducer {
@override
bool get canBeAppliedInBulk => true;
@override
bool get canBeAppliedToFile => true;
@override
FixKind get fixKind => DartFixKind.CONVERT_TO_FUNCTION_DECLARATION;
@override
FixKind get multiFixKind => DartFixKind.CONVERT_TO_FUNCTION_DECLARATION_MULTI;
@override
Future<void> compute(ChangeBuilder builder) async {
var node = this.node;
if (node is! VariableDeclaration) return;
var equals = node.equals;
if (equals == null) return;
var initializer = node.initializer;
var parent = node.parent;
if (parent is! VariableDeclarationList) return;
var keyword = parent.keyword;
var type = parent.type;
var variables = parent.variables;
var grandParent = parent.parent;
if (grandParent is! VariableDeclarationStatement) return;
var previous = _previous(variables, node);
var next = _next(variables, node);
await builder.addDartFileEdit(file, (builder) {
void replaceWithNewLine(SourceRange range,
{String? before, String? after}) {
builder.addReplacement(range, (builder) {
if (before != null) {
builder.write(before);
}
builder.write(utils.endOfLine);
builder.write(utils.getLinePrefix(range.offset));
if (after != null) {
builder.write(after);
}
});
}
if (previous == null) {
if (keyword != null) {
builder.addDeletion(range.startStart(keyword, keyword.next!));
}
if (type != null) {
builder.addDeletion(range.startStart(type, type.endToken.next!));
}
} else if (previous.initializer is! FunctionExpression) {
var r =
range.endStart(previous.endToken, previous.endToken.next!.next!);
replaceWithNewLine(r, before: ';');
}
builder.addDeletion(range.endStart(equals.previous!, equals.next!));
if (next != null) {
var r = range.endStart(node.endToken, node.endToken.next!.next!);
if (next.initializer is FunctionExpression) {
replaceWithNewLine(r);
} else {
var replacement = '';
if (keyword != null) {
replacement += '$keyword ';
}
if (type != null) {
replacement += utils.getNodeText(type) + ' ';
}
replaceWithNewLine(r, after: replacement);
}
} else if (initializer is FunctionExpression &&
initializer.body is BlockFunctionBody) {
builder.addDeletion(range.token(grandParent.semicolon));
}
});
}
VariableDeclaration? _next(
NodeList<VariableDeclaration> variables, VariableDeclaration variable) {
var i = variables.indexOf(variable);
return i < variables.length - 1 ? variables[i + 1] : null;
}
VariableDeclaration? _previous(
NodeList<VariableDeclaration> variables, VariableDeclaration variable) {
var i = variables.indexOf(variable);
return i > 0 ? variables[i - 1] : null;
}
/// Return an instance of this class. Used as a tear-off in `FixProcessor`.
static ConvertToFunctionDeclaration newInstance() =>
ConvertToFunctionDeclaration();
}