blob: 7ee4818e309a8f2a43d5d5a71b45ad049992fcb6 [file] [log] [blame]
// Copyright (c) 2021, 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/dart/ast/visitor.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:analyzer_plugin/utilities/range_factory.dart';
class ConvertForEachToForLoop extends CorrectionProducer {
@override
bool get canBeAppliedInBulk => true;
@override
bool get canBeAppliedToFile => true;
@override
FixKind get fixKind => DartFixKind.CONVERT_FOR_EACH_TO_FOR_LOOP;
@override
FixKind get multiFixKind => DartFixKind.CONVERT_FOR_EACH_TO_FOR_LOOP_MULTI;
@override
Future<void> compute(ChangeBuilder builder) async {
var invocation = node.parent;
if (invocation is! MethodInvocation) {
return;
}
var statement = invocation.parent;
if (statement is! ExpressionStatement) {
return;
}
var argument = invocation.argumentList.arguments[0];
if (argument is! FunctionExpression) {
return;
}
var parameters = argument.parameters?.parameters;
if (parameters == null || parameters.length != 1) {
return;
}
var parameter = parameters[0];
if (parameter is! NormalFormalParameter) {
return;
}
var loopVariableName = parameter.identifier?.name;
if (loopVariableName == null) {
return;
}
var target = utils.getNodeText(invocation.target!);
var body = argument.body;
if (body is BlockFunctionBody) {
await builder.addDartFileEdit(file, (builder) {
builder.addReplacement(range.startStart(invocation, body), (builder) {
builder.write('for (var ');
builder.write(loopVariableName);
builder.write(' in ');
builder.write(target);
builder.write(') ');
});
builder.addDeletion(range.endEnd(body, statement));
body.visitChildren(_ReturnVisitor(builder));
});
} else if (body is ExpressionFunctionBody) {
await builder.addDartFileEdit(file, (builder) {
var expression = body.expression;
var prefix = utils.getPrefix(statement.offset);
builder.addReplacement(range.startStart(invocation, expression),
(builder) {
builder.write('for (var ');
builder.write(loopVariableName);
builder.write(' in ');
builder.write(target);
builder.writeln(') {');
builder.write(prefix);
builder.write(' ');
});
builder.addReplacement(range.endEnd(expression, statement), (builder) {
builder.writeln(';');
builder.write(prefix);
builder.write('}');
});
body.visitChildren(_ReturnVisitor(builder));
});
}
}
}
class _ReturnVisitor extends RecursiveAstVisitor<void> {
final DartFileEditBuilder builder;
_ReturnVisitor(this.builder);
@override
void visitReturnStatement(ReturnStatement node) {
builder.addSimpleReplacement(range.node(node), 'continue;');
}
}