mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 10:49:00 +00:00
[analysis_server] FlutterRemoveWidget
to handle Builder
Fixes #49949 Change-Id: I6b6b0454661523f622256199f1ebd4051e37ec0e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/259590 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
parent
7d46dac715
commit
de68893488
4 changed files with 142 additions and 14 deletions
|
@ -6,10 +6,14 @@ 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/dart/ast/visitor.dart';
|
||||
import 'package:analyzer/dart/element/element.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';
|
||||
import 'package:analyzer_plugin/utilities/range_factory.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
class FlutterRemoveWidget extends CorrectionProducer {
|
||||
@override
|
||||
|
@ -47,25 +51,42 @@ class FlutterRemoveWidget extends CorrectionProducer {
|
|||
} else {
|
||||
var childArgument = flutter.findChildArgument(widgetCreation);
|
||||
if (childArgument != null) {
|
||||
await _removeChild(builder, widgetCreation, childArgument);
|
||||
await _removeSingle(builder, widgetCreation, childArgument.expression);
|
||||
} else {
|
||||
var builderArgument = flutter.findBuilderArgument(widgetCreation);
|
||||
if (builderArgument != null) {
|
||||
await _removeBuilder(builder, widgetCreation, builderArgument);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _removeChild(
|
||||
Future<void> _removeBuilder(
|
||||
ChangeBuilder builder,
|
||||
InstanceCreationExpression widgetCreation,
|
||||
NamedExpression childArgument) async {
|
||||
// child: ThisWidget(child: ourChild)
|
||||
// children: [foo, ThisWidget(child: ourChild), bar]
|
||||
await builder.addDartFileEdit(file, (builder) {
|
||||
var childExpression = childArgument.expression;
|
||||
var childText = utils.getNodeText(childExpression);
|
||||
var indentOld = utils.getLinePrefix(childExpression.offset);
|
||||
var indentNew = utils.getLinePrefix(widgetCreation.offset);
|
||||
childText = replaceSourceIndent(childText, indentOld, indentNew);
|
||||
builder.addSimpleReplacement(range.node(widgetCreation), childText);
|
||||
});
|
||||
NamedExpression builderArgument) async {
|
||||
var builderExpression = builderArgument.expression;
|
||||
if (builderExpression is! FunctionExpression) return;
|
||||
var parameterElement =
|
||||
builderExpression.parameters?.parameters.firstOrNull?.declaredElement;
|
||||
if (parameterElement == null) return;
|
||||
|
||||
var visitor = _UsageFinder(parameterElement);
|
||||
var body = builderExpression.body;
|
||||
body.visitChildren(visitor);
|
||||
if (visitor.used) return;
|
||||
|
||||
if (body is BlockFunctionBody) {
|
||||
var statements = body.block.statements;
|
||||
if (statements.length != 1) return;
|
||||
var statement = statements.first;
|
||||
if (statement is! ReturnStatement) return;
|
||||
var expression = statement.expression;
|
||||
if (expression == null) return;
|
||||
await _removeSingle(builder, widgetCreation, expression);
|
||||
} else if (body is ExpressionFunctionBody) {
|
||||
await _removeSingle(builder, widgetCreation, body.expression);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _removeChildren(
|
||||
|
@ -88,4 +109,32 @@ class FlutterRemoveWidget extends CorrectionProducer {
|
|||
builder.addSimpleReplacement(range.node(widgetCreation), childText);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _removeSingle(
|
||||
ChangeBuilder builder,
|
||||
InstanceCreationExpression widgetCreation,
|
||||
Expression expression,
|
||||
) async {
|
||||
await builder.addDartFileEdit(file, (builder) {
|
||||
var childText = utils.getNodeText(expression);
|
||||
var indentOld = utils.getLinePrefix(expression.offset);
|
||||
var indentNew = utils.getLinePrefix(widgetCreation.offset);
|
||||
childText = replaceSourceIndent(childText, indentOld, indentNew);
|
||||
builder.addSimpleReplacement(range.node(widgetCreation), childText);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class _UsageFinder extends RecursiveAstVisitor<void> {
|
||||
final Element element;
|
||||
bool used = false;
|
||||
|
||||
_UsageFinder(this.element);
|
||||
|
||||
@override
|
||||
void visitSimpleIdentifier(SimpleIdentifier node) {
|
||||
if (node.writeOrReadElement == element) {
|
||||
used = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,6 +113,17 @@ class Flutter {
|
|||
}
|
||||
}
|
||||
|
||||
/// Return the named expression representing the `builder` argument of the
|
||||
/// given [newExpr], or `null` if none.
|
||||
NamedExpression? findBuilderArgument(InstanceCreationExpression newExpr) {
|
||||
for (var argument in newExpr.argumentList.arguments) {
|
||||
if (isBuilderArgument(argument)) {
|
||||
return argument as NamedExpression;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Return the named expression representing the `child` argument of the given
|
||||
/// [newExpr], or `null` if none.
|
||||
NamedExpression? findChildArgument(InstanceCreationExpression newExpr) {
|
||||
|
@ -278,6 +289,10 @@ class Flutter {
|
|||
return null;
|
||||
}
|
||||
|
||||
/// Return `true` is the given [argument] is the `builder` argument.
|
||||
bool isBuilderArgument(Expression argument) =>
|
||||
argument is NamedExpression && argument.name.label.name == 'builder';
|
||||
|
||||
/// Return `true` is the given [argument] is the `child` argument.
|
||||
bool isChildArgument(Expression argument) =>
|
||||
argument is NamedExpression && argument.name.label.name == 'child';
|
||||
|
|
|
@ -162,7 +162,8 @@ class Transform extends SingleChildRenderObjectWidget {
|
|||
|
||||
typedef WidgetBuilder = Widget Function(BuildContext context);
|
||||
|
||||
class Builder {
|
||||
class Builder extends StatelessWidget {
|
||||
final WidgetBuilder builder;
|
||||
|
||||
const Builder({Key? key, @required this.builder});
|
||||
}
|
||||
|
|
|
@ -33,6 +33,69 @@ class FlutterRemoveWidgetTest extends AssistProcessorTest {
|
|||
);
|
||||
}
|
||||
|
||||
Future<void> test_builder_blockFunctionBody() async {
|
||||
await resolveTestCode('''
|
||||
import 'package:flutter/material.dart';
|
||||
void f() {
|
||||
/*caret*/Builder(
|
||||
builder: (context) {
|
||||
return Text('');
|
||||
}
|
||||
);
|
||||
}
|
||||
''');
|
||||
await assertHasAssist('''
|
||||
import 'package:flutter/material.dart';
|
||||
void f() {
|
||||
Text('');
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_builder_blockFunctionBody_many_statements() async {
|
||||
await resolveTestCode('''
|
||||
import 'package:flutter/material.dart';
|
||||
void f() {
|
||||
/*caret*/Builder(
|
||||
builder: (context) {
|
||||
var i = 1;
|
||||
return Text('');
|
||||
}
|
||||
);
|
||||
}
|
||||
''');
|
||||
await assertNoAssist();
|
||||
}
|
||||
|
||||
Future<void> test_builder_expressionFunctionBody() async {
|
||||
await resolveTestCode('''
|
||||
import 'package:flutter/material.dart';
|
||||
void f() {
|
||||
/*caret*/Builder(
|
||||
builder: (context) => Text('')
|
||||
);
|
||||
}
|
||||
''');
|
||||
await assertHasAssist('''
|
||||
import 'package:flutter/material.dart';
|
||||
void f() {
|
||||
Text('');
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_builder_parameter_used() async {
|
||||
await resolveTestCode('''
|
||||
import 'package:flutter/material.dart';
|
||||
void f() {
|
||||
/*caret*/Builder(
|
||||
builder: (context) => context.widget
|
||||
);
|
||||
}
|
||||
''');
|
||||
await assertNoAssist();
|
||||
}
|
||||
|
||||
Future<void> test_childIntoChild_multiLine() async {
|
||||
await resolveTestCode('''
|
||||
import 'package:flutter/material.dart';
|
||||
|
|
Loading…
Reference in a new issue