blob: 2b3e173c61379370e8f63edcdb8185c1bbbedc34 [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: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/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.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 ConvertToFieldParameter extends CorrectionProducer {
@override
AssistKind get assistKind => DartAssistKind.CONVERT_TO_FIELD_PARAMETER;
@override
Future<void> compute(ChangeBuilder builder) async {
// prepare parameter
var context = _findParameter(node);
if (context == null) {
return;
}
// analyze parameter
var parameterName = context.identifier.name;
var parameterElement = context.parameter.declaredElement!;
var initializers = context.constructor.initializers;
// check number of references
var visitor = _ReferenceCounter(parameterElement);
for (var initializer in initializers) {
initializer.accept(visitor);
}
if (visitor.count != 1) {
return;
}
// find the field initializer
ConstructorFieldInitializer? parameterInitializer;
for (var initializer in initializers) {
if (initializer is ConstructorFieldInitializer) {
var expression = initializer.expression;
if (expression is SimpleIdentifier &&
expression.name == parameterName) {
parameterInitializer = initializer;
}
}
}
if (parameterInitializer == null) {
return;
}
var fieldName = parameterInitializer.fieldName.name;
final context_final = context;
final parameterInitializer_final = parameterInitializer;
await builder.addDartFileEdit(file, (builder) {
// replace parameter
builder.addSimpleReplacement(
range.node(context_final.parameter),
'this.$fieldName',
);
// remove initializer
var initializerIndex = initializers.indexOf(parameterInitializer_final);
if (initializers.length == 1) {
builder.addDeletion(
range.endEnd(
context_final.constructor.parameters,
parameterInitializer_final,
),
);
} else {
if (initializerIndex == 0) {
var next = initializers[initializerIndex + 1];
builder.addDeletion(
range.startStart(parameterInitializer_final, next),
);
} else {
var prev = initializers[initializerIndex - 1];
builder.addDeletion(
range.endEnd(prev, parameterInitializer_final),
);
}
}
});
}
static _Context? _findParameter(AstNode node) {
var parent = node.parent;
if (parent is SimpleFormalParameter) {
var identifier = parent.identifier;
if (identifier == null) return null;
var formalParameterList = parent.parent;
if (formalParameterList is! FormalParameterList) return null;
var constructor = formalParameterList.parent;
if (constructor is! ConstructorDeclaration) return null;
return _Context(
parameter: parent,
identifier: identifier,
constructor: constructor,
);
}
if (node is SimpleIdentifier && parent is ConstructorFieldInitializer) {
var constructor = parent.parent;
if (constructor is! ConstructorDeclaration) return null;
if (parent.expression == node) {
for (var formalParameter in constructor.parameters.parameters) {
if (formalParameter is SimpleFormalParameter) {
var identifier = formalParameter.identifier;
if (identifier != null && identifier.name == node.name) {
return _Context(
parameter: formalParameter,
identifier: identifier,
constructor: constructor,
);
}
}
}
}
}
return null;
}
}
class _Context {
final SimpleFormalParameter parameter;
final SimpleIdentifier identifier;
final ConstructorDeclaration constructor;
_Context({
required this.parameter,
required this.identifier,
required this.constructor,
});
}
class _ReferenceCounter extends RecursiveAstVisitor<void> {
final ParameterElement parameterElement;
int count = 0;
_ReferenceCounter(this.parameterElement);
@override
void visitSimpleIdentifier(SimpleIdentifier node) {
if (node.staticElement == parameterElement) {
count++;
}
}
}