Migrate several lib/src/services/correction/dart/

R=brianwilkerson@google.com

Change-Id: I7957e3fa724e618e6cf8c6a94344b0b4057aa080
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/195041
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Konstantin Shcheglov
2021-04-12 18:56:16 +00:00
committed by commit-bot@chromium.org
parent c1339411bb
commit 81be9be4a6
38 changed files with 537 additions and 459 deletions
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
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/correction/util.dart';
@@ -16,7 +14,7 @@ import 'package:analyzer_plugin/utilities/range_factory.dart';
class RenameToCamelCase extends CorrectionProducer {
/// The camel-case version of the name.
String _newName;
String _newName = '';
@override
List<Object> get fixArguments => [_newName];
@@ -29,10 +27,10 @@ class RenameToCamelCase extends CorrectionProducer {
@override
Future<void> compute(ChangeBuilder builder) async {
if (node is! SimpleIdentifier) {
var identifier = node;
if (identifier is! SimpleIdentifier) {
return;
}
SimpleIdentifier identifier = node;
// Prepare the new name.
var words = identifier.name.split('_');
@@ -42,17 +40,21 @@ class RenameToCamelCase extends CorrectionProducer {
_newName = words.first + words.skip(1).map((w) => capitalize(w)).join();
// Find references to the identifier.
List<SimpleIdentifier> references;
List<SimpleIdentifier>? references;
var element = identifier.staticElement;
if (element is LocalVariableElement) {
AstNode root = node.thisOrAncestorOfType<Block>();
references = findLocalElementReferences(root, element);
var root = node.thisOrAncestorOfType<Block>();
if (root != null) {
references = findLocalElementReferences(root, element);
}
} else if (element is ParameterElement) {
if (!element.isNamed) {
var root = node.thisOrAncestorMatching((node) =>
node.parent is ClassOrMixinDeclaration ||
node.parent is CompilationUnit);
references = findLocalElementReferences(root, element);
if (root != null) {
references = findLocalElementReferences(root, element);
}
}
}
if (references == null) {
@@ -60,8 +62,9 @@ class RenameToCamelCase extends CorrectionProducer {
}
// Compute the change.
var references_final = references;
await builder.addDartFileEdit(file, (builder) {
for (var reference in references) {
for (var reference in references_final) {
builder.addSimpleReplacement(range.node(reference), _newName);
}
});
@@ -2,10 +2,9 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analyzer/error/error.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';
@@ -19,8 +18,13 @@ class ReplaceBooleanWithBool extends CorrectionProducer {
@override
Future<void> compute(ChangeBuilder builder) async {
final analysisError = diagnostic;
if (analysisError is! AnalysisError) {
return;
}
await builder.addDartFileEdit(file, (builder) {
builder.addSimpleReplacement(range.error(diagnostic), 'bool');
builder.addSimpleReplacement(range.error(analysisError), 'bool');
});
}
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
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';
@@ -31,29 +29,35 @@ class ReplaceCascadeWithDot extends CorrectionProducer {
@override
Future<void> compute(ChangeBuilder builder) async {
var node = this.node;
if (node is CascadeExpression) {
var sections = node.cascadeSections;
if (sections.length == 1) {
await _replaceFor(builder, sections[0]);
}
final cascadeExpression = node;
if (cascadeExpression is! CascadeExpression) {
return;
}
var sections = cascadeExpression.cascadeSections;
if (sections.length == 1) {
await _replaceFor(builder, sections[0]);
}
}
Future<void> _replaceFor(ChangeBuilder builder, Expression section) async {
Future<void> _replaceFor(ChangeBuilder builder, Expression? section) async {
if (section is AssignmentExpression) {
return _replaceFor(builder, section.leftHandSide);
}
if (section is IndexExpression) {
if (section.period != null) {
return _replaceToken(builder, section.period, _indexReplacement);
var period = section.period;
if (period != null) {
return _replaceToken(builder, period, _indexReplacement);
}
return _replaceFor(builder, section.target);
}
if (section is MethodInvocation) {
return _replaceToken(builder, section.operator, _propertyReplacement);
var operator = section.operator;
if (operator != null) {
return _replaceToken(builder, operator, _propertyReplacement);
}
}
if (section is PropertyAccess) {
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
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';
@@ -20,12 +18,19 @@ class ReplaceColonWithEquals extends CorrectionProducer {
@override
Future<void> compute(ChangeBuilder builder) async {
if (node is DefaultFormalParameter) {
await builder.addDartFileEdit(file, (builder) {
builder.addSimpleReplacement(
range.token((node as DefaultFormalParameter).separator), ' =');
});
final node = this.node;
if (node is! DefaultFormalParameter) {
return;
}
var separator = node.separator;
if (separator == null) {
return;
}
await builder.addDartFileEdit(file, (builder) {
builder.addSimpleReplacement(range.token(separator), ' =');
});
}
/// Return an instance of this class. Used as a tear-off in `FixProcessor`.
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
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';
@@ -18,58 +16,98 @@ class ReplaceConditionalWithIfElse extends CorrectionProducer {
@override
Future<void> compute(ChangeBuilder builder) async {
ConditionalExpression conditional;
// may be on Statement with Conditional
var statement = node.thisOrAncestorOfType<Statement>();
if (statement == null) {
return;
}
// variable declaration
var inVariable = false;
if (statement is VariableDeclarationStatement) {
var variableStatement = statement;
for (var variable in variableStatement.variables.variables) {
if (variable.initializer is ConditionalExpression) {
conditional = variable.initializer as ConditionalExpression;
inVariable = true;
break;
}
}
}
// assignment
var inAssignment = false;
if (statement is ExpressionStatement) {
var exprStmt = statement;
if (exprStmt.expression is AssignmentExpression) {
var assignment = exprStmt.expression as AssignmentExpression;
if (assignment.operator.type == TokenType.EQ &&
assignment.rightHandSide is ConditionalExpression) {
conditional = assignment.rightHandSide as ConditionalExpression;
inAssignment = true;
}
}
}
// return
var inReturn = false;
if (statement is ReturnStatement) {
var returnStatement = statement;
if (returnStatement.expression is ConditionalExpression) {
conditional = returnStatement.expression as ConditionalExpression;
inReturn = true;
}
}
// prepare environment
var indent = utils.getIndent(1);
var prefix = utils.getNodePrefix(statement);
if (inVariable || inAssignment || inReturn) {
// Type v = conditional;
if (statement is VariableDeclarationStatement) {
return _variableDeclarationStatement(builder, statement);
}
// v = conditional;
if (statement is ExpressionStatement) {
var expression = statement.expression;
if (expression is AssignmentExpression) {
return _assignmentExpression(builder, statement, expression);
}
}
// return conditional;
if (statement is ReturnStatement) {
return _returnStatement(builder, statement);
}
}
Future<void> _assignmentExpression(
ChangeBuilder builder,
ExpressionStatement statement,
AssignmentExpression assignment,
) async {
var conditional = assignment.rightHandSide;
if (assignment.operator.type == TokenType.EQ &&
conditional is ConditionalExpression) {
var indent = utils.getIndent(1);
var prefix = utils.getNodePrefix(statement);
await builder.addDartFileEdit(file, (builder) {
// Type v = Conditional;
if (inVariable) {
var leftSide = assignment.leftHandSide;
var conditionSrc = utils.getNodeText(conditional.condition);
var thenSrc = utils.getNodeText(conditional.thenExpression);
var elseSrc = utils.getNodeText(conditional.elseExpression);
var name = utils.getNodeText(leftSide);
var src = '';
src += 'if ($conditionSrc) {' + eol;
src += prefix + indent + '$name = $thenSrc;' + eol;
src += prefix + '} else {' + eol;
src += prefix + indent + '$name = $elseSrc;' + eol;
src += prefix + '}';
builder.addSimpleReplacement(range.node(statement), src);
});
}
}
Future<void> _returnStatement(
ChangeBuilder builder,
ReturnStatement statement,
) async {
var conditional = statement.expression;
if (conditional is ConditionalExpression) {
var indent = utils.getIndent(1);
var prefix = utils.getNodePrefix(statement);
await builder.addDartFileEdit(file, (builder) {
var conditionSrc = utils.getNodeText(conditional.condition);
var thenSrc = utils.getNodeText(conditional.thenExpression);
var elseSrc = utils.getNodeText(conditional.elseExpression);
var src = '';
src += 'if ($conditionSrc) {' + eol;
src += prefix + indent + 'return $thenSrc;' + eol;
src += prefix + '} else {' + eol;
src += prefix + indent + 'return $elseSrc;' + eol;
src += prefix + '}';
builder.addSimpleReplacement(range.node(statement), src);
});
}
}
Future<void> _variableDeclarationStatement(
ChangeBuilder builder,
VariableDeclarationStatement statement,
) async {
for (var variable in statement.variables.variables) {
var conditional = variable.initializer;
if (conditional is ConditionalExpression) {
var indent = utils.getIndent(1);
var prefix = utils.getNodePrefix(statement);
await builder.addDartFileEdit(file, (builder) {
var variable = conditional.parent as VariableDeclaration;
var variableList = variable.parent as VariableDeclarationList;
if (variableList.type == null) {
var type = variable.declaredElement.type;
var type = variable.declaredElement!.type;
var keyword = variableList.keyword;
if (keyword != null && keyword.keyword == Keyword.VAR) {
builder.addReplacement(range.token(keyword), (builder) {
@@ -94,37 +132,8 @@ class ReplaceConditionalWithIfElse extends CorrectionProducer {
src += prefix + indent + '$name = $elseSrc;' + eol;
src += prefix + '}';
builder.addSimpleReplacement(range.endLength(statement, 0), src);
}
// v = Conditional;
if (inAssignment) {
var assignment = conditional.parent as AssignmentExpression;
var leftSide = assignment.leftHandSide;
var conditionSrc = utils.getNodeText(conditional.condition);
var thenSrc = utils.getNodeText(conditional.thenExpression);
var elseSrc = utils.getNodeText(conditional.elseExpression);
var name = utils.getNodeText(leftSide);
var src = '';
src += 'if ($conditionSrc) {' + eol;
src += prefix + indent + '$name = $thenSrc;' + eol;
src += prefix + '} else {' + eol;
src += prefix + indent + '$name = $elseSrc;' + eol;
src += prefix + '}';
builder.addSimpleReplacement(range.node(statement), src);
}
// return Conditional;
if (inReturn) {
var conditionSrc = utils.getNodeText(conditional.condition);
var thenSrc = utils.getNodeText(conditional.thenExpression);
var elseSrc = utils.getNodeText(conditional.elseExpression);
var src = '';
src += 'if ($conditionSrc) {' + eol;
src += prefix + indent + 'return $thenSrc;' + eol;
src += prefix + '} else {' + eol;
src += prefix + indent + 'return $elseSrc;' + eol;
src += prefix + '}';
builder.addSimpleReplacement(range.node(statement), src);
}
});
});
}
}
}
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
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';
@@ -20,11 +18,14 @@ class ReplaceFinalWithConst extends CorrectionProducer {
@override
Future<void> compute(ChangeBuilder builder) async {
final node = this.node;
if (node is VariableDeclarationList) {
await builder.addDartFileEdit(file, (builder) {
builder.addSimpleReplacement(
range.token((node as VariableDeclarationList).keyword), 'const');
});
var keyword = node.keyword;
if (keyword != null) {
await builder.addDartFileEdit(file, (builder) {
builder.addSimpleReplacement(range.token(keyword), 'const');
});
}
}
}
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
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';
@@ -20,11 +18,12 @@ class ReplaceFinalWithVar extends CorrectionProducer {
@override
Future<void> compute(ChangeBuilder builder) async {
var target = node;
if (target is VariableDeclarationList) {
if (target.type == null) {
final node = this.node;
if (node is VariableDeclarationList) {
var keyword = node.keyword;
if (keyword != null && node.type == null) {
await builder.addDartFileEdit(file, (builder) {
builder.addSimpleReplacement(range.token(target.keyword), 'var');
builder.addSimpleReplacement(range.token(keyword), 'var');
});
}
}
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
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';
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
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';
@@ -20,7 +18,7 @@ class ReplaceNewWithConst extends CorrectionProducer {
@override
Future<void> compute(ChangeBuilder builder) async {
var node = this.node;
AstNode? node = this.node;
if (node is ConstructorName) {
node = node.parent;
}
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
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';
@@ -22,13 +20,14 @@ class ReplaceNullWithClosure extends CorrectionProducer {
@override
Future<void> compute(ChangeBuilder builder) async {
AstNode nodeToFix;
AstNode? nodeToFix;
var parameters = const <ParameterElement>[];
final coveredNode = this.coveredNode;
if (coveredNode is NamedExpression) {
NamedExpression namedExpression = coveredNode;
var expression = namedExpression.expression;
var expression = coveredNode.expression;
if (expression is NullLiteral) {
var element = namedExpression.element;
var element = coveredNode.element;
if (element is ParameterElement) {
var type = element.type;
if (type is FunctionType) {
@@ -41,14 +40,17 @@ class ReplaceNullWithClosure extends CorrectionProducer {
nodeToFix = coveredNode;
}
if (nodeToFix != null) {
await builder.addDartFileEdit(file, (builder) {
builder.addReplacement(range.node(nodeToFix), (builder) {
builder.writeParameters(parameters);
builder.write(' => null');
});
});
if (nodeToFix == null) {
return;
}
final nodeToFix_final = nodeToFix;
await builder.addDartFileEdit(file, (builder) {
builder.addReplacement(range.node(nodeToFix_final), (builder) {
builder.writeParameters(parameters);
builder.write(' => null');
});
});
}
/// Return an instance of this class. Used as a tear-off in `FixProcessor`.
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
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';
@@ -18,7 +16,10 @@ class ReplaceReturnTypeFuture extends CorrectionProducer {
Future<void> compute(ChangeBuilder builder) async {
// prepare the existing type
var typeName = node.thisOrAncestorOfType<TypeAnnotation>();
var typeProvider = this.typeProvider;
if (typeName == null) {
return;
}
await builder.addDartFileEdit(file, (builder) {
builder.replaceTypeWithFuture(typeName, typeProvider);
});
@@ -2,10 +2,9 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analyzer/error/error.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';
@@ -16,9 +15,12 @@ class ReplaceVarWithDynamic extends CorrectionProducer {
@override
Future<void> compute(ChangeBuilder builder) async {
await builder.addDartFileEdit(file, (builder) {
builder.addSimpleReplacement(range.error(diagnostic), 'dynamic');
});
final diagnostic = this.diagnostic;
if (diagnostic is AnalysisError) {
await builder.addDartFileEdit(file, (builder) {
builder.addSimpleReplacement(range.error(diagnostic), 'dynamic');
});
}
}
/// Return an instance of this class. Used as a tear-off in `FixProcessor`.
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
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';
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
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';
@@ -21,20 +19,14 @@ class ReplaceWithConditionalAssignment extends CorrectionProducer {
@override
Future<void> compute(ChangeBuilder builder) async {
IfStatement ifStatement =
var node = this.node;
var ifStatement =
node is IfStatement ? node : node.thisOrAncestorOfType<IfStatement>();
if (ifStatement == null) {
return;
}
var thenStatement = ifStatement.thenStatement;
Statement uniqueStatement(Statement statement) {
if (statement is Block) {
return uniqueStatement(statement.statements.first);
}
return statement;
}
thenStatement = uniqueStatement(thenStatement);
var thenStatement = _uniqueStatement(ifStatement.thenStatement);
if (thenStatement is ExpressionStatement) {
final expression = thenStatement.expression.unParenthesized;
if (expression is AssignmentExpression) {
@@ -53,4 +45,11 @@ class ReplaceWithConditionalAssignment extends CorrectionProducer {
/// Return an instance of this class. Used as a tear-off in `FixProcessor`.
static ReplaceWithConditionalAssignment newInstance() =>
ReplaceWithConditionalAssignment();
static Statement _uniqueStatement(Statement statement) {
if (statement is Block) {
return _uniqueStatement(statement.statements.first);
}
return statement;
}
}
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
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';
@@ -13,7 +11,7 @@ import 'package:analyzer_plugin/utilities/range_factory.dart';
class ReplaceWithEightDigitHex extends CorrectionProducer {
/// The replacement text, used as an argument to the fix message.
String _replacement;
String _replacement = '';
@override
List<Object> get fixArguments => [_replacement];
@@ -33,6 +31,9 @@ class ReplaceWithEightDigitHex extends CorrectionProducer {
return;
}
var value = (node as IntegerLiteral).value;
if (value == null) {
return;
}
_replacement = '0x' + value.toRadixString(16).padLeft(8, '0');
//
// Build the edit.
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
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';
@@ -12,7 +10,7 @@ import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:analyzer_plugin/utilities/range_factory.dart';
class ReplaceWithExtensionName extends CorrectionProducer {
String _extensionName;
String _extensionName = '';
@override
List<Object> get fixArguments => [_extensionName];
@@ -35,7 +33,7 @@ class ReplaceWithExtensionName extends CorrectionProducer {
}
}
AstNode _getTarget(AstNode invocation) {
AstNode? _getTarget(AstNode? invocation) {
if (invocation is MethodInvocation && node == invocation.methodName) {
return invocation.target;
} else if (invocation is PropertyAccess &&
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
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';
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
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';
@@ -2,16 +2,14 @@
// 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.
// @dart = 2.9
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/token.dart';
import 'package:analyzer/src/dart/ast/extensions.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';
import 'package:meta/meta.dart';
class ReplaceWithInterpolation extends CorrectionProducer {
@override
@@ -22,9 +20,9 @@ class ReplaceWithInterpolation extends CorrectionProducer {
//
// Validate the fix.
//
BinaryExpression binary;
var candidate = node;
while (_isStringConcatenation(candidate)) {
BinaryExpression? binary;
AstNode? candidate = node;
while (candidate is BinaryExpression && _isStringConcatenation(candidate)) {
binary = candidate;
candidate = candidate.parent;
}
@@ -43,8 +41,9 @@ class ReplaceWithInterpolation extends CorrectionProducer {
//
// Build the edit.
//
final binary_final = binary;
await builder.addDartFileEdit(file, (builder) {
builder.addSimpleReplacement(range.node(binary), interpolation);
builder.addSimpleReplacement(range.node(binary_final), interpolation);
});
}
@@ -82,9 +81,11 @@ class ReplaceWithInterpolation extends CorrectionProducer {
return leftStyle;
}
return leftStyle == rightStyle ? leftStyle : _StringStyle.invalid;
} else if (expression is MethodInvocation &&
expression.methodName.name == 'toString') {
return _extractComponentsInto(expression.target, components);
} else if (expression is MethodInvocation) {
var target = expression.target;
if (target != null && expression.methodName.name == 'toString') {
return _extractComponentsInto(target, components);
}
} else if (expression is ParenthesizedExpression) {
return _extractComponentsInto(expression.expression, components);
}
@@ -95,8 +96,8 @@ class ReplaceWithInterpolation extends CorrectionProducer {
bool _isStringConcatenation(AstNode node) =>
node is BinaryExpression &&
node.operator.type == TokenType.PLUS &&
node.leftOperand.staticType.isDartCoreString &&
node.rightOperand.staticType.isDartCoreString;
node.leftOperand.typeOrThrow.isDartCoreString &&
node.rightOperand.typeOrThrow.isDartCoreString;
String _mergeComponents(_StringStyle style, List<AstNode> components) {
var quotes = style.quotes;
@@ -161,10 +162,11 @@ class _StringStyle {
final int state;
factory _StringStyle(
{@required bool multiline,
@required bool raw,
@required bool singleQuoted}) {
factory _StringStyle({
required bool multiline,
required bool raw,
required bool singleQuoted,
}) {
return _StringStyle._((multiline ? multilineBit : 0) +
(raw ? rawBit : 0) +
(singleQuoted ? singleQuotedBit : 0));
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
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';
@@ -14,106 +12,28 @@ import 'package:analyzer_plugin/utilities/range_factory.dart';
class ReplaceWithIsEmpty extends CorrectionProducer {
@override
FixKind fixKind;
FixKind fixKind = DartFixKind.REPLACE_WITH_IS_EMPTY;
@override
FixKind multiFixKind;
FixKind multiFixKind = DartFixKind.REPLACE_WITH_IS_EMPTY_MULTI;
@override
Future<void> compute(ChangeBuilder builder) async {
/// Return the value of an integer literal or prefix expression with a
/// minus and then an integer literal. For anything else, returns `null`.
int getIntValue(Expression expressions) {
// Copied from package:linter/src/rules/prefer_is_empty.dart.
if (expressions is IntegerLiteral) {
return expressions.value;
} else if (expressions is PrefixExpression) {
var operand = expressions.operand;
if (expressions.operator.type == TokenType.MINUS &&
operand is IntegerLiteral) {
return -operand.value;
}
}
return null;
}
/// Return the expression producing the object on which `length` is being
/// invoked, or `null` if there is no such expression.
Expression getLengthTarget(Expression expression) {
if (expression is PropertyAccess &&
expression.propertyName.name == 'length') {
return expression.target;
} else if (expression is PrefixedIdentifier &&
expression.identifier.name == 'length') {
return expression.prefix;
}
return null;
}
var binary = node.thisOrAncestorOfType<BinaryExpression>();
var operator = binary.operator.type;
String getter;
Expression lengthTarget;
var rightValue = getIntValue(binary.rightOperand);
if (rightValue != null) {
lengthTarget = getLengthTarget(binary.leftOperand);
if (rightValue == 0) {
if (operator == TokenType.EQ_EQ || operator == TokenType.LT_EQ) {
getter = 'isEmpty';
fixKind = DartFixKind.REPLACE_WITH_IS_EMPTY;
multiFixKind = DartFixKind.REPLACE_WITH_IS_EMPTY_MULTI;
} else if (operator == TokenType.GT || operator == TokenType.BANG_EQ) {
getter = 'isNotEmpty';
fixKind = DartFixKind.REPLACE_WITH_IS_NOT_EMPTY;
multiFixKind = DartFixKind.REPLACE_WITH_IS_NOT_EMPTY_MULTI;
}
} else if (rightValue == 1) {
// 'length >= 1' is same as 'isNotEmpty',
// and 'length < 1' is same as 'isEmpty'
if (operator == TokenType.GT_EQ) {
getter = 'isNotEmpty';
fixKind = DartFixKind.REPLACE_WITH_IS_NOT_EMPTY;
multiFixKind = DartFixKind.REPLACE_WITH_IS_NOT_EMPTY_MULTI;
} else if (operator == TokenType.LT) {
getter = 'isEmpty';
fixKind = DartFixKind.REPLACE_WITH_IS_EMPTY;
multiFixKind = DartFixKind.REPLACE_WITH_IS_EMPTY_MULTI;
}
}
} else {
var leftValue = getIntValue(binary.leftOperand);
if (leftValue != null) {
lengthTarget = getLengthTarget(binary.rightOperand);
if (leftValue == 0) {
if (operator == TokenType.EQ_EQ || operator == TokenType.GT_EQ) {
getter = 'isEmpty';
fixKind = DartFixKind.REPLACE_WITH_IS_EMPTY;
multiFixKind = DartFixKind.REPLACE_WITH_IS_EMPTY_MULTI;
} else if (operator == TokenType.LT ||
operator == TokenType.BANG_EQ) {
getter = 'isNotEmpty';
fixKind = DartFixKind.REPLACE_WITH_IS_NOT_EMPTY;
multiFixKind = DartFixKind.REPLACE_WITH_IS_NOT_EMPTY_MULTI;
}
} else if (leftValue == 1) {
// '1 <= length' is same as 'isNotEmpty',
// and '1 > length' is same as 'isEmpty'
if (operator == TokenType.LT_EQ) {
getter = 'isNotEmpty';
fixKind = DartFixKind.REPLACE_WITH_IS_NOT_EMPTY;
multiFixKind = DartFixKind.REPLACE_WITH_IS_NOT_EMPTY_MULTI;
} else if (operator == TokenType.GT) {
getter = 'isEmpty';
fixKind = DartFixKind.REPLACE_WITH_IS_EMPTY;
multiFixKind = DartFixKind.REPLACE_WITH_IS_EMPTY_MULTI;
}
}
}
}
if (lengthTarget == null || getter == null || fixKind == null) {
if (binary == null) {
return;
}
var target = utils.getNodeText(lengthTarget);
var replacement = _analyzeBinaryExpression(binary);
if (replacement == null) {
return;
}
fixKind = replacement.fixKind;
multiFixKind = replacement.multiFixKind;
var target = utils.getNodeText(replacement.lengthTarget);
var getter = replacement.getter;
await builder.addDartFileEdit(file, (builder) {
builder.addSimpleReplacement(range.node(binary), '$target.$getter');
});
@@ -121,4 +41,117 @@ class ReplaceWithIsEmpty extends CorrectionProducer {
/// Return an instance of this class. Used as a tear-off in `FixProcessor`.
static ReplaceWithIsEmpty newInstance() => ReplaceWithIsEmpty();
static _Replacement? _analyzeBinaryExpression(BinaryExpression binary) {
var operator = binary.operator.type;
var rightValue = _getIntValue(binary.rightOperand);
if (rightValue != null) {
var lengthTarget = _getLengthTarget(binary.leftOperand);
if (lengthTarget == null) {
return null;
}
if (rightValue == 0) {
if (operator == TokenType.EQ_EQ || operator == TokenType.LT_EQ) {
return _Replacement.isEmpty(lengthTarget);
} else if (operator == TokenType.GT || operator == TokenType.BANG_EQ) {
return _Replacement.isNotEmpty(lengthTarget);
}
} else if (rightValue == 1) {
// 'length >= 1' is same as 'isNotEmpty',
// and 'length < 1' is same as 'isEmpty'
if (operator == TokenType.GT_EQ) {
return _Replacement.isNotEmpty(lengthTarget);
} else if (operator == TokenType.LT) {
return _Replacement.isEmpty(lengthTarget);
}
}
} else {
var leftValue = _getIntValue(binary.leftOperand);
if (leftValue != null) {
var lengthTarget = _getLengthTarget(binary.rightOperand);
if (lengthTarget == null) {
return null;
}
if (leftValue == 0) {
if (operator == TokenType.EQ_EQ || operator == TokenType.GT_EQ) {
return _Replacement.isEmpty(lengthTarget);
} else if (operator == TokenType.LT ||
operator == TokenType.BANG_EQ) {
return _Replacement.isNotEmpty(lengthTarget);
}
} else if (leftValue == 1) {
// '1 <= length' is same as 'isNotEmpty',
// and '1 > length' is same as 'isEmpty'
if (operator == TokenType.LT_EQ) {
return _Replacement.isNotEmpty(lengthTarget);
} else if (operator == TokenType.GT) {
return _Replacement.isEmpty(lengthTarget);
}
}
}
}
return null;
}
/// Return the value of an integer literal or prefix expression with a
/// minus and then an integer literal. For anything else, returns `null`.
static int? _getIntValue(Expression expressions) {
// Copied from package:linter/src/rules/prefer_is_empty.dart.
if (expressions is IntegerLiteral) {
return expressions.value;
} else if (expressions is PrefixExpression) {
var operand = expressions.operand;
if (expressions.operator.type == TokenType.MINUS &&
operand is IntegerLiteral) {
var value = operand.value;
if (value != null) {
return -value;
}
}
}
return null;
}
/// Return the expression producing the object on which `length` is being
/// invoked, or `null` if there is no such expression.
static Expression? _getLengthTarget(Expression expression) {
if (expression is PropertyAccess &&
expression.propertyName.name == 'length') {
return expression.target;
} else if (expression is PrefixedIdentifier &&
expression.identifier.name == 'length') {
return expression.prefix;
}
return null;
}
}
class _Replacement {
final FixKind fixKind;
final FixKind multiFixKind;
final String getter;
final Expression lengthTarget;
_Replacement.isEmpty(Expression lengthTarget)
: this._(
fixKind: DartFixKind.REPLACE_WITH_IS_EMPTY,
multiFixKind: DartFixKind.REPLACE_WITH_IS_EMPTY_MULTI,
getter: 'isEmpty',
lengthTarget: lengthTarget,
);
_Replacement.isNotEmpty(Expression lengthTarget)
: this._(
fixKind: DartFixKind.REPLACE_WITH_IS_NOT_EMPTY,
multiFixKind: DartFixKind.REPLACE_WITH_IS_NOT_EMPTY_MULTI,
getter: 'isNotEmpty',
lengthTarget: lengthTarget,
);
_Replacement._({
required this.fixKind,
required this.multiFixKind,
required this.getter,
required this.lengthTarget,
});
}
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
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';
@@ -14,7 +12,7 @@ import 'package:analyzer_plugin/utilities/range_factory.dart';
class ReplaceWithNotNullAware extends CorrectionProducer {
/// The operator that will replace the existing operator.
String _newOperator;
String _newOperator = '';
@override
List<Object> get fixArguments => [_newOperator];
@@ -26,11 +24,13 @@ class ReplaceWithNotNullAware extends CorrectionProducer {
Future<void> compute(ChangeBuilder builder) async {
var node = coveredNode;
if (node is MethodInvocation) {
_newOperator =
node.operator.type == TokenType.QUESTION_PERIOD ? '.' : '..';
await builder.addDartFileEdit(file, (builder) {
builder.addSimpleReplacement(range.token(node.operator), _newOperator);
});
var operator = node.operator;
if (operator != null) {
_newOperator = operator.type == TokenType.QUESTION_PERIOD ? '.' : '..';
await builder.addDartFileEdit(file, (builder) {
builder.addSimpleReplacement(range.token(operator), _newOperator);
});
}
} else if (node is PropertyAccess) {
_newOperator =
node.operator.type == TokenType.QUESTION_PERIOD ? '.' : '..';
@@ -38,15 +38,17 @@ class ReplaceWithNotNullAware extends CorrectionProducer {
builder.addSimpleReplacement(range.token(node.operator), _newOperator);
});
} else if (node is IndexExpression) {
if (node.period != null) {
var period = node.period;
var question = node.question;
if (period != null) {
_newOperator = '..';
await builder.addDartFileEdit(file, (builder) {
builder.addSimpleReplacement(range.token(node.period), '..');
builder.addSimpleReplacement(range.token(period), '..');
});
} else if (node.question != null) {
} else if (question != null) {
_newOperator = '[';
await builder.addDartFileEdit(file, (builder) {
builder.addDeletion(range.token(node.question));
builder.addDeletion(range.token(question));
});
}
} else if (node is SpreadElement) {
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
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';
@@ -19,18 +17,22 @@ class ReplaceWithNullAware extends CorrectionProducer {
Future<void> compute(ChangeBuilder builder) async {
var node = coveredNode;
if (node is Expression) {
final node_final = node;
await builder.addDartFileEdit(file, (builder) {
var parent = node.parent;
var parent = node_final.parent;
while (parent != null) {
if (parent is MethodInvocation && parent.target == node) {
builder.addSimpleReplacement(range.token(parent.operator), '?.');
var operator = parent.operator;
if (operator != null) {
builder.addSimpleReplacement(range.token(operator), '?.');
}
} else if (parent is PropertyAccess && parent.target == node) {
builder.addSimpleReplacement(range.token(parent.operator), '?.');
} else {
break;
}
node = parent;
parent = node.parent;
parent = node?.parent;
}
});
}
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
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';
@@ -24,16 +22,22 @@ class ReplaceWithTearOff extends CorrectionProducer {
if (ancestor == null) {
return;
}
Future<void> addFixOfExpression(InvocationExpression expression) async {
await builder.addDartFileEdit(file, (builder) {
builder.addReplacement(range.node(ancestor), (builder) {
if (expression is MethodInvocation && expression.target != null) {
builder.write(utils.getNodeText(expression.target));
builder.write('.');
}
builder.write(utils.getNodeText(expression.function));
Future<void> addFixOfExpression(Expression? expression) async {
if (expression is InvocationExpression) {
await builder.addDartFileEdit(file, (builder) {
builder.addReplacement(range.node(ancestor), (builder) {
if (expression is MethodInvocation) {
var target = expression.target;
if (target != null) {
builder.write(utils.getNodeText(target));
builder.write('.');
}
}
builder.write(utils.getNodeText(expression.function));
});
});
});
}
}
final body = ancestor.body;
@@ -47,7 +51,7 @@ class ReplaceWithTearOff extends CorrectionProducer {
await addFixOfExpression(expression.unParenthesized);
} else if (statement is ReturnStatement) {
final expression = statement.expression;
await addFixOfExpression(expression.unParenthesized);
await addFixOfExpression(expression?.unParenthesized);
}
}
}
@@ -2,12 +2,11 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/src/services/correction/assist.dart';
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/src/dart/ast/extensions.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/fixes/fixes.dart';
@@ -44,25 +43,28 @@ class ReplaceWithVar extends CorrectionProducer {
return;
}
var initializer = variables[0].initializer;
String typeArgumentsText;
int typeArgumentsOffset;
if (type is NamedType && type.typeArguments != null) {
if (initializer is CascadeExpression) {
initializer = (initializer as CascadeExpression).target;
}
if (initializer is TypedLiteral) {
if (initializer.typeArguments == null) {
typeArgumentsText = utils.getNodeText(type.typeArguments);
if (initializer is ListLiteral) {
typeArgumentsOffset = initializer.leftBracket.offset;
} else if (initializer is SetOrMapLiteral) {
typeArgumentsOffset = initializer.leftBracket.offset;
}
String? typeArgumentsText;
int? typeArgumentsOffset;
if (type is NamedType) {
var typeArguments = type.typeArguments;
if (typeArguments != null) {
if (initializer is CascadeExpression) {
initializer = initializer.target;
}
} else if (initializer is InstanceCreationExpression) {
if (initializer.constructorName.type.typeArguments == null) {
typeArgumentsText = utils.getNodeText(type.typeArguments);
typeArgumentsOffset = initializer.constructorName.type.end;
if (initializer is TypedLiteral) {
if (initializer.typeArguments == null) {
typeArgumentsText = utils.getNodeText(typeArguments);
if (initializer is ListLiteral) {
typeArgumentsOffset = initializer.leftBracket.offset;
} else if (initializer is SetOrMapLiteral) {
typeArgumentsOffset = initializer.leftBracket.offset;
}
}
} else if (initializer is InstanceCreationExpression) {
if (initializer.constructorName.type.typeArguments == null) {
typeArgumentsText = utils.getNodeText(typeArguments);
typeArgumentsOffset = initializer.constructorName.type.end;
}
}
}
}
@@ -80,19 +82,22 @@ class ReplaceWithVar extends CorrectionProducer {
} else {
builder.addSimpleReplacement(range.node(type), 'var');
}
if (typeArgumentsText != null) {
if (typeArgumentsText != null && typeArgumentsOffset != null) {
builder.addSimpleInsertion(typeArgumentsOffset, typeArgumentsText);
}
});
} else if (parent is DeclaredIdentifier &&
grandparent is ForEachPartsWithDeclaration) {
String typeArgumentsText;
int typeArgumentsOffset;
if (type is NamedType && type.typeArguments != null) {
var iterable = grandparent.iterable;
if (iterable is TypedLiteral && iterable.typeArguments == null) {
typeArgumentsText = utils.getNodeText(type.typeArguments);
typeArgumentsOffset = iterable.offset;
String? typeArgumentsText;
int? typeArgumentsOffset;
if (type is NamedType) {
var typeArguments = type.typeArguments;
if (typeArguments != null) {
var iterable = grandparent.iterable;
if (iterable is TypedLiteral && iterable.typeArguments == null) {
typeArgumentsText = utils.getNodeText(typeArguments);
typeArgumentsOffset = iterable.offset;
}
}
}
await builder.addDartFileEdit(file, (builder) {
@@ -101,7 +106,7 @@ class ReplaceWithVar extends CorrectionProducer {
} else {
builder.addSimpleReplacement(range.node(type), 'var');
}
if (typeArgumentsText != null) {
if (typeArgumentsText != null && typeArgumentsOffset != null) {
builder.addSimpleInsertion(typeArgumentsOffset, typeArgumentsText);
}
});
@@ -110,7 +115,7 @@ class ReplaceWithVar extends CorrectionProducer {
/// Return `true` if the type in the [node] can be replaced with `var`.
bool _canConvertVariableDeclarationList(VariableDeclarationList node) {
final staticType = node?.type?.type;
final staticType = node.type?.type;
if (staticType == null || staticType.isDynamic) {
return false;
}
@@ -137,10 +142,10 @@ class ReplaceWithVar extends CorrectionProducer {
if (staticType == null || staticType.isDynamic) {
return false;
}
final iterableType = parent.iterable.staticType;
final iterableType = parent.iterable.typeOrThrow;
var instantiatedType =
iterableType.asInstanceOf(typeProvider.iterableElement);
if (instantiatedType?.typeArguments?.first == staticType) {
if (instantiatedType?.typeArguments.first == staticType) {
return true;
}
return false;
@@ -152,7 +157,7 @@ class ReplaceWithVar extends CorrectionProducer {
/// Using the [node] as a starting point, return the type annotation that is
/// to be replaced, or `null` if there is no type annotation.
TypeAnnotation _findType(AstNode node) {
TypeAnnotation? _findType(AstNode node) {
if (node is VariableDeclarationList) {
return node.type;
}
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
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';
@@ -20,34 +18,45 @@ class ShadowField extends CorrectionProducer {
@override
Future<void> compute(ChangeBuilder builder) async {
final node = this.node;
if (node is! SimpleIdentifier) {
return;
}
var element = (node as SimpleIdentifier).writeOrReadElement;
if (element is! PropertyAccessorElement) {
var accessor = node.writeOrReadElement;
if (accessor is! PropertyAccessorElement) {
return;
}
var accessor = element as PropertyAccessorElement;
if (!accessor.isGetter || accessor.enclosingElement is! ClassElement) {
// TODO(brianwilkerson) Should we also require that the getter be synthetic?
return;
}
var statement = _getStatement();
if (statement == null) {
return;
}
if (statement.parent is! Block) {
var enclosingBlock = statement.parent;
if (enclosingBlock is! Block) {
// TODO(brianwilkerson) Support adding a block between the statement and
// its parent (where the parent will be something like a while or if
// statement). Also support the case where the parent is a case clause.
return;
}
var enclosingBlock = statement.parent as Block;
var finder = _ReferenceFinder(accessor.correspondingSetter);
var correspondingSetter = accessor.correspondingSetter;
if (correspondingSetter == null) {
return;
}
var finder = _ReferenceFinder(correspondingSetter);
enclosingBlock.accept(finder);
if (finder.hasSetterReference) {
return;
}
var fieldName = accessor.name;
var offset = statement.offset;
var prefix = utils.getLinePrefix(offset);
@@ -74,13 +83,13 @@ class ShadowField extends CorrectionProducer {
/// Return the statement immediately enclosing the [node] that would promote
/// the type of the field if it were replaced by a local variable.
Statement _getStatement() {
Statement? _getStatement() {
var parent = node.parent;
Statement enclosingIf(Expression expression) {
Statement? enclosingIf(Expression expression) {
var parent = expression.parent;
while (parent is BinaryExpression) {
var opType = (parent as BinaryExpression).operator.type;
var opType = parent.operator.type;
if (opType != TokenType.AMPERSAND_AMPERSAND) {
break;
}
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/src/services/correction/assist.dart';
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
@@ -32,13 +30,12 @@ class SortChildPropertyLast extends CorrectionProducer {
return;
}
var parent = childProp.parent?.parent;
if (parent is! InstanceCreationExpression ||
!flutter.isWidgetCreation(parent)) {
var creationExpression = childProp.parent?.parent;
if (creationExpression is! InstanceCreationExpression ||
!flutter.isWidgetCreation(creationExpression)) {
return;
}
InstanceCreationExpression creationExpression = parent;
var args = creationExpression.argumentList;
var last = args.arguments.last;
@@ -48,10 +45,10 @@ class SortChildPropertyLast extends CorrectionProducer {
}
await builder.addDartFileEdit(file, (fileEditBuilder) {
var hasTrailingComma = last.endToken.next.type == TokenType.COMMA;
var hasTrailingComma = last.endToken.next!.type == TokenType.COMMA;
var childStart = childProp.beginToken.previous.end;
var childEnd = childProp.endToken.next.end;
var childStart = childProp.beginToken.previous!.end;
var childEnd = childProp.endToken.next!.end;
var childRange = range.startOffsetEndOffset(childStart, childEnd);
var deletionRange = childRange;
@@ -69,7 +66,7 @@ class SortChildPropertyLast extends CorrectionProducer {
var insertionPoint = last.end;
if (hasTrailingComma) {
insertionPoint = last.endToken.next.end;
insertionPoint = last.endToken.next!.end;
} else if (childStart == childProp.offset) {
childText = ', $childText';
} else {
@@ -85,7 +82,7 @@ class SortChildPropertyLast extends CorrectionProducer {
/// Using the [node] as the starting point, find the named expression that is
/// for either the `child` or `children` parameter.
NamedExpression _findNamedExpression(AstNode node) {
NamedExpression? _findNamedExpression(AstNode node) {
if (node is NamedExpression) {
var name = node.name.label.name;
if (name == 'child' || name == 'children') {
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/src/services/correction/assist.dart';
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
import 'package:analysis_server/src/services/correction/util.dart';
@@ -20,10 +18,10 @@ class SplitAndCondition extends CorrectionProducer {
@override
Future<void> compute(ChangeBuilder builder) async {
// check that user invokes quick assist on binary expression
if (node is! BinaryExpression) {
var binaryExpression = node;
if (binaryExpression is! BinaryExpression) {
return;
}
var binaryExpression = node as BinaryExpression;
// prepare operator position
if (!isOperatorSelected(binaryExpression)) {
return;
@@ -33,11 +31,10 @@ class SplitAndCondition extends CorrectionProducer {
return;
}
// prepare "if"
var statement = node.thisOrAncestorOfType<Statement>();
if (statement is! IfStatement) {
var ifStatement = node.thisOrAncestorOfType<Statement>();
if (ifStatement is! IfStatement) {
return;
}
var ifStatement = statement as IfStatement;
// no support "else"
if (ifStatement.elseStatement != null) {
return;
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
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';
@@ -18,16 +16,20 @@ class SplitVariableDeclaration extends CorrectionProducer {
@override
Future<void> compute(ChangeBuilder builder) async {
var variableList = node?.thisOrAncestorOfType<VariableDeclarationList>();
// Must be a local variable declaration.
if (variableList?.parent is! VariableDeclarationStatement) {
var variableList = node.thisOrAncestorOfType<VariableDeclarationList>();
if (variableList == null) {
return;
}
// Must be a local variable declaration.
var statement = variableList.parent;
if (statement is! VariableDeclarationStatement) {
return;
}
VariableDeclarationStatement statement = variableList.parent;
// Cannot be `const` or `final`.
var keywordKind = variableList.keyword?.keyword;
var keyword = variableList.keyword;
var keywordKind = keyword?.keyword;
if (keywordKind == Keyword.CONST || keywordKind == Keyword.FINAL) {
return;
}
@@ -50,9 +52,9 @@ class SplitVariableDeclaration extends CorrectionProducer {
await builder.addDartFileEdit(file, (builder) {
if (variableList.type == null) {
final type = variable.declaredElement.type;
if (!type.isDynamic) {
builder.addReplacement(range.token(variableList.keyword), (builder) {
final type = variable.declaredElement!.type;
if (!type.isDynamic && keyword != null) {
builder.addReplacement(range.token(keyword), (builder) {
builder.writeType(type);
});
}
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analyzer/file_system/file_system.dart';
@@ -25,32 +23,25 @@ class UpdateSdkConstraints extends CorrectionProducer {
@override
Future<void> compute(ChangeBuilder builder) async {
var context = resourceProvider.pathContext;
File pubspecFile;
var folder = resourceProvider.getFolder(context.dirname(file));
while (folder != null) {
pubspecFile = folder.getChildAssumingFile('pubspec.yaml');
if (pubspecFile.exists) {
break;
}
pubspecFile = null;
folder = folder.parent2;
}
var pubspecFile = _findPubspecFile();
if (pubspecFile == null) {
return;
}
var extractor = SdkConstraintExtractor(pubspecFile);
var text = extractor.constraintText();
var offset = extractor.constraintOffset();
if (text == null || offset < 0) {
return;
}
var length = text.length;
String newText;
var spaceOffset = text.indexOf(' ');
if (spaceOffset >= 0) {
length = spaceOffset;
}
String? newText;
if (text == 'any') {
newText = '^$_minimumVersion';
} else if (text.startsWith('^')) {
@@ -63,11 +54,23 @@ class UpdateSdkConstraints extends CorrectionProducer {
if (newText == null) {
return;
}
final newText_final = newText;
await builder.addGenericFileEdit(pubspecFile.path, (builder) {
builder.addSimpleReplacement(SourceRange(offset, length), newText);
builder.addSimpleReplacement(SourceRange(offset, length), newText_final);
});
}
File? _findPubspecFile() {
var file = resourceProvider.getFile(this.file);
for (var folder in file.parent2.withAncestors) {
var pubspecFile = folder.getChildAssumingFile('pubspec.yaml');
if (pubspecFile.exists) {
return pubspecFile;
}
}
}
/// Return an instance of this class that will update the SDK constraints to
/// '2.1.0'. Used as a tear-off in `FixProcessor`.
static UpdateSdkConstraints version_2_1_0() => UpdateSdkConstraints('2.1.0');
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
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';
@@ -20,12 +18,12 @@ class UseConst extends CorrectionProducer {
if (coveredNode is InstanceCreationExpression) {
var instanceCreation = coveredNode as InstanceCreationExpression;
await builder.addDartFileEdit(file, (builder) {
if (instanceCreation.keyword == null) {
var keyword = instanceCreation.keyword;
if (keyword == null) {
builder.addSimpleInsertion(
instanceCreation.constructorName.offset, 'const');
} else {
builder.addSimpleReplacement(
range.token(instanceCreation.keyword), 'const');
builder.addSimpleReplacement(range.token(keyword), 'const');
}
});
}
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/src/services/correction/assist.dart';
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
@@ -37,9 +35,12 @@ class UseCurlyBraces extends CorrectionProducer {
} else if (parent is ForStatement) {
return _forStatement(builder, parent);
} else if (statement is IfStatement) {
if (statement.elseKeyword != null &&
range.token(statement.elseKeyword).contains(selectionOffset)) {
return _ifStatement(builder, statement, statement.elseStatement);
var elseKeyword = statement.elseKeyword;
var elseStatement = statement.elseStatement;
if (elseKeyword != null &&
elseStatement != null &&
range.token(elseKeyword).contains(selectionOffset)) {
return _ifStatement(builder, statement, elseStatement);
} else {
return _ifStatement(builder, statement, null);
}
@@ -88,21 +89,22 @@ class UseCurlyBraces extends CorrectionProducer {
}
Future<void> _ifStatement(
ChangeBuilder builder, IfStatement node, Statement thenOrElse) async {
ChangeBuilder builder, IfStatement node, Statement? thenOrElse) async {
var prefix = utils.getLinePrefix(node.offset);
var indent = prefix + utils.getIndent(1);
await builder.addDartFileEdit(file, (builder) {
var thenStatement = node.thenStatement;
var elseKeyword = node.elseKeyword;
if (thenStatement is! Block &&
(thenOrElse == null || thenOrElse == thenStatement)) {
builder.addSimpleReplacement(
range.endStart(node.rightParenthesis, thenStatement),
' {$eol$indent',
);
if (node.elseKeyword != null) {
if (elseKeyword != null) {
builder.addSimpleReplacement(
range.endStart(thenStatement, node.elseKeyword),
range.endStart(thenStatement, elseKeyword),
'$eol$prefix} ',
);
} else {
@@ -111,11 +113,12 @@ class UseCurlyBraces extends CorrectionProducer {
}
var elseStatement = node.elseStatement;
if (elseStatement != null &&
if (elseKeyword != null &&
elseStatement != null &&
elseStatement is! Block &&
(thenOrElse == null || thenOrElse == elseStatement)) {
builder.addSimpleReplacement(
range.endStart(node.elseKeyword, elseStatement),
range.endStart(elseKeyword, elseStatement),
' {$eol$indent',
);
builder.addSimpleInsertion(elseStatement.end, '$eol$prefix}');
@@ -2,10 +2,9 @@
// 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.
// @dart = 2.9
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/utilities/extensions/ast.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
@@ -17,21 +16,24 @@ class UseEffectiveIntegerDivision extends CorrectionProducer {
@override
Future<void> compute(ChangeBuilder builder) async {
for (var n = node; n != null; n = n.parent) {
if (n is MethodInvocation &&
n.offset == errorOffset &&
n.length == errorLength) {
var target = (n as MethodInvocation).target.unParenthesized;
await builder.addDartFileEdit(file, (builder) {
// replace "/" with "~/"
var binary = target as BinaryExpression;
builder.addSimpleReplacement(range.token(binary.operator), '~/');
// remove everything before and after
builder.addDeletion(range.startStart(n, binary.leftOperand));
builder.addDeletion(range.endEnd(binary.rightOperand, n));
});
// done
break;
for (var n in node.withParents) {
if (n is MethodInvocation) {
if (n.offset == errorOffset && n.length == errorLength) {
var target = n.target;
if (target != null) {
target = target.unParenthesized;
await builder.addDartFileEdit(file, (builder) {
// replace "/" with "~/"
var binary = target as BinaryExpression;
builder.addSimpleReplacement(range.token(binary.operator), '~/');
// remove everything before and after
builder.addDeletion(range.startStart(n, binary.leftOperand));
builder.addDeletion(range.endEnd(binary.rightOperand, n));
});
}
// done
break;
}
}
}
}
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
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';
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
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';
@@ -21,10 +19,10 @@ class UseIsNotEmpty extends CorrectionProducer {
@override
Future<void> compute(ChangeBuilder builder) async {
if (node is! PrefixExpression) {
var prefixExpression = node;
if (prefixExpression is! PrefixExpression) {
return;
}
PrefixExpression prefixExpression = node;
var negation = prefixExpression.operator;
if (negation.type != TokenType.BANG) {
return;
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
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';
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
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';
@@ -20,6 +18,7 @@ class UseRethrow extends CorrectionProducer {
@override
Future<void> compute(ChangeBuilder builder) async {
final coveredNode = this.coveredNode;
if (coveredNode is ThrowExpression) {
await builder.addDartFileEdit(file, (builder) {
builder.addSimpleReplacement(range.node(coveredNode), 'rethrow');
@@ -2,20 +2,16 @@
// 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.
// @dart = 2.9
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/element/element.dart';
import 'package:analyzer/src/dart/ast/extensions.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 WrapInText extends CorrectionProducer {
ParameterElement _parameterElement;
Expression _stringExpression;
@override
FixKind get fixKind => DartFixKind.WRAP_IN_TEXT;
@@ -24,43 +20,55 @@ class WrapInText extends CorrectionProducer {
//
// Extract the information needed to build the edit.
//
_extractContextInformation(node);
if (_parameterElement == null || _stringExpression == null) {
var context = _extractContextInformation(node);
if (context == null) {
return;
}
if (!flutter.isWidgetType(_parameterElement.type)) {
if (!flutter.isWidgetType(context.parameterElement.type)) {
return;
}
//
// Extract the information needed to build the edit.
//
var stringExpressionCode = utils.getNodeText(_stringExpression);
var stringExpressionCode = utils.getNodeText(context.stringExpression);
//
// Build the edit.
//
await builder.addDartFileEdit(file, (builder) {
builder.addSimpleReplacement(
range.node(_stringExpression),
range.node(context.stringExpression),
'Text($stringExpressionCode)',
);
});
}
/// Set the `String` typed named expression to [_stringExpression], and the
/// corresponding parameter to [_parameterElement]. Leave the fields `null`
/// if not a named argument, or not a `String` typed expression.
void _extractContextInformation(AstNode node) {
/// Return an instance of this class. Used as a tear-off in `FixProcessor`.
static WrapInText newInstance() => WrapInText();
static _Context? _extractContextInformation(AstNode node) {
if (node is NamedExpression) {
var expression = node.expression;
if (expression.staticType.isDartCoreString) {
_parameterElement = node.name.label.staticElement;
_stringExpression = expression;
if (expression.typeOrThrow.isDartCoreString) {
var parameterElement = node.name.label.staticElement;
if (parameterElement is ParameterElement) {
return _Context(
stringExpression: expression,
parameterElement: parameterElement,
);
}
}
}
}
/// Return an instance of this class. Used as a tear-off in `FixProcessor`.
static WrapInText newInstance() => WrapInText();
}
class _Context {
final Expression stringExpression;
final ParameterElement parameterElement;
_Context({
required this.stringExpression,
required this.parameterElement,
});
}
@@ -429,7 +429,7 @@ Expression? getQualifiedPropertyTarget(AstNode node) {
/// Returns the given [statement] if not a block, or the first child statement
/// if a block, or `null` if more than one child.
Statement? getSingleStatement(Statement statement) {
Statement? getSingleStatement(Statement? statement) {
if (statement is Block) {
List<Statement> blockStatements = statement.statements;
if (blockStatements.length != 1) {