mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 00:39:49 +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
|
@ -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/dart/abstract_producer.dart';
|
||||||
import 'package:analysis_server/src/services/correction/fix.dart';
|
import 'package:analysis_server/src/services/correction/fix.dart';
|
||||||
import 'package:analyzer/dart/ast/ast.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/assist/assist.dart';
|
||||||
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.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/fixes/fixes.dart';
|
||||||
import 'package:analyzer_plugin/utilities/range_factory.dart';
|
import 'package:analyzer_plugin/utilities/range_factory.dart';
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
|
||||||
class FlutterRemoveWidget extends CorrectionProducer {
|
class FlutterRemoveWidget extends CorrectionProducer {
|
||||||
@override
|
@override
|
||||||
|
@ -47,25 +51,42 @@ class FlutterRemoveWidget extends CorrectionProducer {
|
||||||
} else {
|
} else {
|
||||||
var childArgument = flutter.findChildArgument(widgetCreation);
|
var childArgument = flutter.findChildArgument(widgetCreation);
|
||||||
if (childArgument != null) {
|
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,
|
ChangeBuilder builder,
|
||||||
InstanceCreationExpression widgetCreation,
|
InstanceCreationExpression widgetCreation,
|
||||||
NamedExpression childArgument) async {
|
NamedExpression builderArgument) async {
|
||||||
// child: ThisWidget(child: ourChild)
|
var builderExpression = builderArgument.expression;
|
||||||
// children: [foo, ThisWidget(child: ourChild), bar]
|
if (builderExpression is! FunctionExpression) return;
|
||||||
await builder.addDartFileEdit(file, (builder) {
|
var parameterElement =
|
||||||
var childExpression = childArgument.expression;
|
builderExpression.parameters?.parameters.firstOrNull?.declaredElement;
|
||||||
var childText = utils.getNodeText(childExpression);
|
if (parameterElement == null) return;
|
||||||
var indentOld = utils.getLinePrefix(childExpression.offset);
|
|
||||||
var indentNew = utils.getLinePrefix(widgetCreation.offset);
|
var visitor = _UsageFinder(parameterElement);
|
||||||
childText = replaceSourceIndent(childText, indentOld, indentNew);
|
var body = builderExpression.body;
|
||||||
builder.addSimpleReplacement(range.node(widgetCreation), childText);
|
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(
|
Future<void> _removeChildren(
|
||||||
|
@ -88,4 +109,32 @@ class FlutterRemoveWidget extends CorrectionProducer {
|
||||||
builder.addSimpleReplacement(range.node(widgetCreation), childText);
|
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
|
/// Return the named expression representing the `child` argument of the given
|
||||||
/// [newExpr], or `null` if none.
|
/// [newExpr], or `null` if none.
|
||||||
NamedExpression? findChildArgument(InstanceCreationExpression newExpr) {
|
NamedExpression? findChildArgument(InstanceCreationExpression newExpr) {
|
||||||
|
@ -278,6 +289,10 @@ class Flutter {
|
||||||
return null;
|
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.
|
/// Return `true` is the given [argument] is the `child` argument.
|
||||||
bool isChildArgument(Expression argument) =>
|
bool isChildArgument(Expression argument) =>
|
||||||
argument is NamedExpression && argument.name.label.name == 'child';
|
argument is NamedExpression && argument.name.label.name == 'child';
|
||||||
|
|
|
@ -162,7 +162,8 @@ class Transform extends SingleChildRenderObjectWidget {
|
||||||
|
|
||||||
typedef WidgetBuilder = Widget Function(BuildContext context);
|
typedef WidgetBuilder = Widget Function(BuildContext context);
|
||||||
|
|
||||||
class Builder {
|
class Builder extends StatelessWidget {
|
||||||
final WidgetBuilder builder;
|
final WidgetBuilder builder;
|
||||||
|
|
||||||
const Builder({Key? key, @required this.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 {
|
Future<void> test_childIntoChild_multiLine() async {
|
||||||
await resolveTestCode('''
|
await resolveTestCode('''
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
Loading…
Reference in a new issue