[DAS] Fixing swap with single Widget on children
R=pquitslund@google.com
Fixes https://github.com/dart-lang/sdk/issues/55940
Change-Id: I5cad91a97dcd9fe7b550b3661e8a46a301cbb558
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/387862
Reviewed-by: Phil Quitslund <pquitslund@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Auto-Submit: Felipe Morschel <fmorschel.dev@gmail.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/flutter_swap_with_child.dart b/pkg/analysis_server/lib/src/services/correction/dart/flutter_swap_with_child.dart
index 8be89ba..dcf824e 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/flutter_swap_with_child.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/flutter_swap_with_child.dart
@@ -21,10 +21,15 @@
Future<void> swapParentAndChild(
ChangeBuilder builder,
InstanceCreationExpression parent,
- InstanceCreationExpression child) async {
- // The child must have its own child.
- var stableChild = child.childArgument;
- if (stableChild == null) {
+ InstanceCreationExpression child,
+ bool parentHadSingleChild) async {
+ // The child must have its own single child.
+ AstNode stableChild;
+ if (_singleChildInChildren(child) case var first?) {
+ stableChild = first;
+ } else if (child.childArgument case var childArgument?) {
+ stableChild = childArgument;
+ } else {
return;
}
@@ -68,9 +73,9 @@
builder.writeln('(');
// Write all arguments of the parent.
- // Don't write its child.
+ // Don't write its child/children.
for (var argument in parentArgs.arguments) {
- if (!argument.isChildArgument) {
+ if (!argument.isChildArgument && !argument.isChildrenArgument) {
var text = utils.getNodeText(argument);
text = utils.replaceSourceIndent(
text,
@@ -84,17 +89,36 @@
}
}
- // Write the child of the "child" now, as the child of the "parent".
+ // Write the child(ren) of the "child" now, as the child(ren) of the "parent".
{
var text = utils.getNodeText(stableChild);
+ if (text.trim().startsWith('child: ')) {
+ text = text.substring('child: '.length);
+ } else if (text.trim().startsWith('children: ')) {
+ text = text.substring('children: '.length);
+ }
builder.write(childIndent);
builder.write(' ');
+ if (parentHadSingleChild) {
+ builder.write('child: ');
+ } else {
+ builder.write('children: [');
+ builder.writeln();
+ builder.write(childIndent);
+ builder.write(' ');
+ }
builder.write(text);
builder.writeln(',');
}
// Close the parent expression.
builder.write(childIndent);
+ if (!parentHadSingleChild) {
+ builder.write(' ');
+ builder.write(']');
+ builder.writeln(',');
+ builder.write(childIndent);
+ }
builder.writeln('),');
// Close the child expression.
@@ -103,6 +127,20 @@
});
});
}
+
+ InstanceCreationExpression? _singleChildInChildren(
+ InstanceCreationExpression parent) {
+ if (parent.childrenArgument case var childrenArgument?) {
+ if (childrenArgument.expression case ListLiteral list) {
+ if (list.elements case NodeList(length: 1, first: var first)) {
+ if (first is InstanceCreationExpression) {
+ return first;
+ }
+ }
+ }
+ }
+ return null;
+ }
}
class FlutterSwapWithChild extends FlutterParentAndChild {
@@ -117,13 +155,18 @@
if (parent == null || !parent.isWidgetCreation) {
return;
}
+ var parentHasSingleChild = true;
- var childArgument = parent.childArgument;
- var child = childArgument?.expression;
+ Expression? child;
+ if (_singleChildInChildren(parent) case var first?) {
+ child = first;
+ parentHasSingleChild = false;
+ }
+ child ??= parent.childArgument?.expression;
if (child is! InstanceCreationExpression || !child.isWidgetCreation) {
return;
}
- await swapParentAndChild(builder, parent, child);
+ await swapParentAndChild(builder, parent, child, parentHasSingleChild);
}
}
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/flutter_swap_with_parent.dart b/pkg/analysis_server/lib/src/services/correction/dart/flutter_swap_with_parent.dart
index a7b09fc..e6d1303 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/flutter_swap_with_parent.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/flutter_swap_with_parent.dart
@@ -21,13 +21,25 @@
if (child == null || !child.isWidgetCreation) {
return;
}
+ var parentHadSingleChild = true;
+ NamedExpression? namedExpression;
+ if (child.parent case ListLiteral listLiteral) {
+ if (listLiteral.elements case NodeList(length: var length)
+ when length != 1) {
+ return;
+ }
+ if (listLiteral.parent case NamedExpression parent) {
+ namedExpression = parent;
+ parentHadSingleChild = false;
+ }
+ }
// NamedExpression (child:), ArgumentList, InstanceCreationExpression
- var expr = child.parent?.parent?.parent;
+ var expr = (namedExpression ?? child.parent)?.parent?.parent;
if (expr is! InstanceCreationExpression) {
return;
}
- await swapParentAndChild(builder, expr, child);
+ await swapParentAndChild(builder, expr, child, parentHadSingleChild);
}
}
diff --git a/pkg/analysis_server/test/src/services/correction/assist/flutter_swap_with_child_test.dart b/pkg/analysis_server/test/src/services/correction/assist/flutter_swap_with_child_test.dart
index f06745d..b999280 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/flutter_swap_with_child_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/flutter_swap_with_child_test.dart
@@ -115,4 +115,63 @@
}
}''');
}
+
+ Future<void> test_single_child_multi() async {
+ await resolveTestCode('''
+import 'package:flutter/material.dart';
+build() {
+ return Scaffold(
+ body: /*caret*/Column(
+ children: [
+ Padding(
+ padding: const EdgeInsets.all(8),
+ child: Text('Hello'),
+ ),
+ ],
+ ),
+ );
+}
+startResize() {}
+''');
+ await assertHasAssist('''
+import 'package:flutter/material.dart';
+build() {
+ return Scaffold(
+ body: Padding(
+ padding: const EdgeInsets.all(8),
+ child: Column(
+ children: [
+ Text('Hello'),
+ ],
+ ),
+ ),
+ );
+}
+startResize() {}
+''');
+ }
+
+ Future<void> test_two_children_multi() async {
+ await resolveTestCode('''
+import 'package:flutter/material.dart';
+build() {
+ return Scaffold(
+ body: /*caret*/Column(
+ children: [
+ Padding(
+ padding: const EdgeInsets.all(8),
+ child: Text('Hello'),
+ ),
+ Padding(
+ padding: const EdgeInsets.all(8),
+ child: Text('Hello'),
+ ),
+ ],
+ ),
+ );
+}
+startResize() {}
+''');
+ await assertNoAssist();
+ }
}
diff --git a/pkg/analysis_server/test/src/services/correction/assist/flutter_swap_with_parent_test.dart b/pkg/analysis_server/test/src/services/correction/assist/flutter_swap_with_parent_test.dart
index 4980dea..b19bef1 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/flutter_swap_with_parent_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/flutter_swap_with_parent_test.dart
@@ -162,4 +162,63 @@
}
''');
}
+
+ Future<void> test_single_child_multi() async {
+ await resolveTestCode('''
+import 'package:flutter/material.dart';
+build() {
+ return Scaffold(
+ body: Column(
+ children: [
+ /*caret*/Padding(
+ padding: const EdgeInsets.all(8),
+ child: Text('Hello'),
+ ),
+ ],
+ ),
+ );
+}
+startResize() {}
+''');
+ await assertHasAssist('''
+import 'package:flutter/material.dart';
+build() {
+ return Scaffold(
+ body: Padding(
+ padding: const EdgeInsets.all(8),
+ child: Column(
+ children: [
+ Text('Hello'),
+ ],
+ ),
+ ),
+ );
+}
+startResize() {}
+''');
+ }
+
+ Future<void> test_two_children_multi() async {
+ await resolveTestCode('''
+import 'package:flutter/material.dart';
+build() {
+ return Scaffold(
+ body: Column(
+ children: [
+ /*caret*/Padding(
+ padding: const EdgeInsets.all(8),
+ child: Text('Hello'),
+ ),
+ Padding(
+ padding: const EdgeInsets.all(8),
+ child: Text('Hello'),
+ ),
+ ],
+ ),
+ );
+}
+startResize() {}
+''');
+ await assertNoAssist();
+ }
}