Skip to content

Commit 59716fe

Browse files
committed
New Quick Asists for Flutter: 'Replace with child' and 'Replace with children'.
[email protected], [email protected] Bug: flutter/flutter-intellij#1283 Change-Id: Ic50de9739cdab5cd82649dcbd8370c5e728d2ee3 flutter/flutter-intellij#1756 Reviewed-on: https://dart-review.googlesource.com/40240 Reviewed-by: Brian Wilkerson <[email protected]> Reviewed-by: Devon Carew <[email protected]>
1 parent 87a395b commit 59716fe

File tree

5 files changed

+257
-3
lines changed

5 files changed

+257
-3
lines changed

pkg/analysis_server/lib/src/services/correction/assist.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ class DartAssistKind {
7777
const AssistKind('EXTRACT_CLASS', 30, "Extract class into file '{0}'");
7878
static const FLUTTER_CONVERT_TO_STATEFUL_WIDGET = const AssistKind(
7979
"FLUTTER_CONVERT_TO_STATEFUL_WIDGET", 30, "Convert to StatefulWidget");
80+
static const FLUTTER_REPLACE_WITH_CHILDREN = const AssistKind(
81+
"FLUTTER_REPLACE_WITH_CHILDREN", 30, "Replace with children");
8082
static const IMPORT_ADD_SHOW =
8183
const AssistKind('IMPORT_ADD_SHOW', 30, "Add explicit 'show' combinator");
8284
static const INTRODUCE_LOCAL_CAST_TYPE = const AssistKind(

pkg/analysis_server/lib/src/services/correction/assist_internal.dart

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ class AssistProcessor {
143143
await _addProposal_convertToStatefulWidget();
144144
await _addProposal_encapsulateField();
145145
await _addProposal_exchangeOperands();
146+
await _addProposal_flutterReplaceWithChild();
147+
await _addProposal_flutterReplaceWithChildren();
146148
await _addProposal_importAddShow();
147149
await _addProposal_introduceLocalTestedType();
148150
await _addProposal_invertIf();
@@ -1406,6 +1408,71 @@ class AssistProcessor {
14061408
_addAssistFromBuilder(changeBuilder, DartAssistKind.EXCHANGE_OPERANDS);
14071409
}
14081410

1411+
Future<Null> _addProposal_flutterReplaceWithChild() async {
1412+
var widgetCreation = flutter.identifyNewExpression(node);
1413+
if (widgetCreation == null) {
1414+
return;
1415+
}
1416+
1417+
var childArgument = flutter.findChildArgument(widgetCreation);
1418+
if (childArgument == null) {
1419+
return;
1420+
}
1421+
1422+
// child: new ThisWidget(child: ourChild)
1423+
// children: [foo, new ThisWidget(child: ourChild), bar]
1424+
DartChangeBuilder changeBuilder = new DartChangeBuilder(session);
1425+
await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
1426+
var childExpression = childArgument.expression;
1427+
var childText = utils.getNodeText(childExpression);
1428+
var indentOld = utils.getLinePrefix(childExpression.offset);
1429+
var indentNew = utils.getLinePrefix(widgetCreation.offset);
1430+
childText = _replaceSourceIndent(childText, indentOld, indentNew);
1431+
builder.addSimpleReplacement(range.node(widgetCreation), childText);
1432+
});
1433+
_addAssistFromBuilder(
1434+
changeBuilder, DartAssistKind.FLUTTER_REPLACE_WITH_CHILDREN);
1435+
}
1436+
1437+
Future<Null> _addProposal_flutterReplaceWithChildren() async {
1438+
var widgetCreation = flutter.identifyNewExpression(node);
1439+
if (widgetCreation == null) {
1440+
return;
1441+
}
1442+
1443+
// We can inline the list of our children only into another list.
1444+
var widgetParentNode = widgetCreation.parent;
1445+
if (widgetParentNode is! ListLiteral) {
1446+
return;
1447+
}
1448+
1449+
// Prepare the list of our children.
1450+
List<Expression> childrenExpressions;
1451+
{
1452+
var childrenArgument = flutter.findChildrenArgument(widgetCreation);
1453+
var childrenExpression = childrenArgument?.expression;
1454+
if (childrenExpression is ListLiteral &&
1455+
childrenExpression.elements.isNotEmpty) {
1456+
childrenExpressions = childrenExpression.elements;
1457+
} else {
1458+
return;
1459+
}
1460+
}
1461+
1462+
DartChangeBuilder changeBuilder = new DartChangeBuilder(session);
1463+
await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
1464+
var firstChild = childrenExpressions.first;
1465+
var lastChild = childrenExpressions.last;
1466+
var childText = utils.getRangeText(range.startEnd(firstChild, lastChild));
1467+
var indentOld = utils.getLinePrefix(firstChild.offset);
1468+
var indentNew = utils.getLinePrefix(widgetCreation.offset);
1469+
childText = _replaceSourceIndent(childText, indentOld, indentNew);
1470+
builder.addSimpleReplacement(range.node(widgetCreation), childText);
1471+
});
1472+
_addAssistFromBuilder(
1473+
changeBuilder, DartAssistKind.FLUTTER_REPLACE_WITH_CHILDREN);
1474+
}
1475+
14091476
Future<Null> _addProposal_importAddShow() async {
14101477
// prepare ImportDirective
14111478
ImportDirective importDirective =

pkg/analysis_server/lib/src/utilities/flutter.dart

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,23 @@ void convertChildToChildren2(
101101
}
102102

103103
/**
104-
* Return the named expression representing the 'child' argument of the given
105-
* [newExpr], or null if none.
104+
* Return the named expression representing the `child` argument of the given
105+
* [newExpr], or `null` if none.
106106
*/
107107
NamedExpression findChildArgument(InstanceCreationExpression newExpr) =>
108108
newExpr.argumentList.arguments.firstWhere(
109109
(arg) => arg is NamedExpression && arg.name.label.name == 'child',
110110
orElse: () => null);
111111

112+
/**
113+
* Return the named expression representing the `children` argument of the
114+
* given [newExpr], or `null` if none.
115+
*/
116+
NamedExpression findChildrenArgument(InstanceCreationExpression newExpr) =>
117+
newExpr.argumentList.arguments.firstWhere(
118+
(arg) => arg is NamedExpression && arg.name.label.name == 'children',
119+
orElse: () => null);
120+
112121
/**
113122
* Return the Flutter instance creation expression that is the value of the
114123
* 'child' argument of the given [newExpr], or null if none.

pkg/analysis_server/test/services/correction/assist_test.dart

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2628,6 +2628,182 @@ main() {
26282628
''');
26292629
}
26302630

2631+
test_flutterReplaceWithChild_OK_childIntoChild_multiLine() async {
2632+
addFlutterPackage();
2633+
await resolveTestUnit('''
2634+
import 'package:flutter/material.dart';
2635+
main() {
2636+
new Column(
2637+
children: <Widget>[
2638+
new Center(
2639+
child: new /*caret*/Padding(
2640+
padding: const EdgeInsets.all(8.0),
2641+
child: new Center(
2642+
heightFactor: 0.5,
2643+
child: new Text('foo'),
2644+
),
2645+
),
2646+
),
2647+
],
2648+
);
2649+
}
2650+
''');
2651+
_setCaretLocation();
2652+
await assertHasAssist(DartAssistKind.FLUTTER_REPLACE_WITH_CHILDREN, '''
2653+
import 'package:flutter/material.dart';
2654+
main() {
2655+
new Column(
2656+
children: <Widget>[
2657+
new Center(
2658+
child: new Center(
2659+
heightFactor: 0.5,
2660+
child: new Text('foo'),
2661+
),
2662+
),
2663+
],
2664+
);
2665+
}
2666+
''');
2667+
}
2668+
2669+
test_flutterReplaceWithChild_OK_childIntoChild_singleLine() async {
2670+
addFlutterPackage();
2671+
await resolveTestUnit('''
2672+
import 'package:flutter/material.dart';
2673+
main() {
2674+
new Padding(
2675+
padding: const EdgeInsets.all(8.0),
2676+
child: new /*caret*/Center(
2677+
heightFactor: 0.5,
2678+
child: new Text('foo'),
2679+
),
2680+
);
2681+
}
2682+
''');
2683+
_setCaretLocation();
2684+
await assertHasAssist(DartAssistKind.FLUTTER_REPLACE_WITH_CHILDREN, '''
2685+
import 'package:flutter/material.dart';
2686+
main() {
2687+
new Padding(
2688+
padding: const EdgeInsets.all(8.0),
2689+
child: new Text('foo'),
2690+
);
2691+
}
2692+
''');
2693+
}
2694+
2695+
test_flutterReplaceWithChild_OK_childIntoChildren() async {
2696+
addFlutterPackage();
2697+
await resolveTestUnit('''
2698+
import 'package:flutter/material.dart';
2699+
main() {
2700+
new Column(
2701+
children: <Widget>[
2702+
new Text('foo'),
2703+
new /*caret*/Center(
2704+
heightFactor: 0.5,
2705+
child: new Padding(
2706+
padding: const EdgeInsets.all(8.0),
2707+
child: new Text('bar'),
2708+
),
2709+
),
2710+
new Text('baz'),
2711+
],
2712+
);
2713+
}
2714+
''');
2715+
_setCaretLocation();
2716+
await assertHasAssist(DartAssistKind.FLUTTER_REPLACE_WITH_CHILDREN, '''
2717+
import 'package:flutter/material.dart';
2718+
main() {
2719+
new Column(
2720+
children: <Widget>[
2721+
new Text('foo'),
2722+
new Padding(
2723+
padding: const EdgeInsets.all(8.0),
2724+
child: new Text('bar'),
2725+
),
2726+
new Text('baz'),
2727+
],
2728+
);
2729+
}
2730+
''');
2731+
}
2732+
2733+
test_flutterReplaceWithChildren_BAD_parentChild() async {
2734+
addFlutterPackage();
2735+
await resolveTestUnit('''
2736+
import 'package:flutter/material.dart';
2737+
main() {
2738+
new Center(
2739+
child: new /*caret*/Row(
2740+
children: [
2741+
new Text('aaa'),
2742+
new Text('bbb'),
2743+
],
2744+
),
2745+
);
2746+
}
2747+
''');
2748+
_setCaretLocation();
2749+
await assertNoAssist(DartAssistKind.FLUTTER_REPLACE_WITH_CHILDREN);
2750+
}
2751+
2752+
test_flutterReplaceWithChildren_OK_intoChildren() async {
2753+
addFlutterPackage();
2754+
await resolveTestUnit('''
2755+
import 'package:flutter/material.dart';
2756+
main() {
2757+
new Column(
2758+
children: <Widget>[
2759+
new Text('aaa'),
2760+
new /*caret*/Column(
2761+
children: [
2762+
new Row(
2763+
children: [
2764+
new Text('bbb'),
2765+
new Text('ccc'),
2766+
],
2767+
),
2768+
new Row(
2769+
children: [
2770+
new Text('ddd'),
2771+
new Text('eee'),
2772+
],
2773+
),
2774+
],
2775+
),
2776+
new Text('fff'),
2777+
],
2778+
);
2779+
}
2780+
''');
2781+
_setCaretLocation();
2782+
await assertHasAssist(DartAssistKind.FLUTTER_REPLACE_WITH_CHILDREN, '''
2783+
import 'package:flutter/material.dart';
2784+
main() {
2785+
new Column(
2786+
children: <Widget>[
2787+
new Text('aaa'),
2788+
new Row(
2789+
children: [
2790+
new Text('bbb'),
2791+
new Text('ccc'),
2792+
],
2793+
),
2794+
new Row(
2795+
children: [
2796+
new Text('ddd'),
2797+
new Text('eee'),
2798+
],
2799+
),
2800+
new Text('fff'),
2801+
],
2802+
);
2803+
}
2804+
''');
2805+
}
2806+
26312807
test_importAddShow_BAD_hasShow() async {
26322808
await resolveTestUnit('''
26332809
import 'dart:math' show PI;

pkg/analysis_server/test/src/utilities/flutter_util.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ export 'package:flutter/painting.dart';
138138
export 'package:flutter/rendering.dart';
139139
140140
class Center extends StatelessWidget {
141-
const Center({Widget child, Key key});
141+
const Center({Key key, double heightFactor, Widget child});
142142
}
143143
144144
class Column extends Flex {

0 commit comments

Comments
 (0)