mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 22:59:47 +00:00
Adds assist for basic Flutter Builder
Fixes issues such as * https://github.com/flutter/flutter-intellij/issues/814 * https://github.com/dart-lang/sdk/issues/33957 . Essentially, in Flutter, it's often useful to create a new context in the UI/widget tree as a place to begin a search towards the trunk of the tree for various state structures attached to lower levels of the tree. The basic `Builder` widget is the official means for creating such a context/entry-point. The patches in this PR are essentially a copy-paste-tweak from two types of existing, similar assists. The main origin was taken from `FlutterWrapStreamBuilder` which wraps client code with a constructor for the StreamBuilder sub-class. The new assist, provided here, is a little more basic/general than the StreamBuilder so it was able to also adopt assertion and test code from some of the other assists for basic widgets. Closes https://github.com/dart-lang/sdk/pull/45656 https://github.com/dart-lang/sdk/pull/45656 GitOrigin-RevId: 00a5043e5dbd410f24f30f6503711413341dbe7a Change-Id: I5f93837af571b4974e35da131112f82cd9359697 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/194941 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
parent
f162db3ba7
commit
c1339411bb
|
@ -138,6 +138,8 @@ class DartAssistKind {
|
|||
static const FLUTTER_WRAP_GENERIC =
|
||||
AssistKind('dart.assist.flutter.wrap.generic', 31, 'Wrap with widget...');
|
||||
|
||||
static const FLUTTER_WRAP_BUILDER = AssistKind(
|
||||
'dart.assist.flutter.wrap.builder', 32, 'Wrap with Builder');
|
||||
static const FLUTTER_WRAP_CENTER =
|
||||
AssistKind('dart.assist.flutter.wrap.center', 32, 'Wrap with Center');
|
||||
static const FLUTTER_WRAP_COLUMN =
|
||||
|
|
|
@ -51,6 +51,7 @@ import 'package:analysis_server/src/services/correction/dart/flutter_remove_widg
|
|||
import 'package:analysis_server/src/services/correction/dart/flutter_swap_with_child.dart';
|
||||
import 'package:analysis_server/src/services/correction/dart/flutter_swap_with_parent.dart';
|
||||
import 'package:analysis_server/src/services/correction/dart/flutter_wrap.dart';
|
||||
import 'package:analysis_server/src/services/correction/dart/flutter_wrap_builder.dart';
|
||||
import 'package:analysis_server/src/services/correction/dart/flutter_wrap_generic.dart';
|
||||
import 'package:analysis_server/src/services/correction/dart/flutter_wrap_stream_builder.dart';
|
||||
import 'package:analysis_server/src/services/correction/dart/import_add_show.dart';
|
||||
|
@ -128,6 +129,7 @@ class AssistProcessor extends BaseProcessor {
|
|||
FlutterRemoveWidget.newInstance,
|
||||
FlutterSwapWithChild.newInstance,
|
||||
FlutterSwapWithParent.newInstance,
|
||||
FlutterWrapBuilder.newInstance,
|
||||
FlutterWrapGeneric.newInstance,
|
||||
FlutterWrapStreamBuilder.newInstance,
|
||||
ImportAddShow.newInstance,
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
|
||||
// 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_plugin/utilities/assist/assist.dart';
|
||||
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
|
||||
import 'package:analyzer_plugin/utilities/range_factory.dart';
|
||||
|
||||
class FlutterWrapBuilder extends CorrectionProducer {
|
||||
@override
|
||||
AssistKind get assistKind => DartAssistKind.FLUTTER_WRAP_BUILDER;
|
||||
|
||||
@override
|
||||
Future<void> compute(ChangeBuilder builder) async {
|
||||
var widgetExpr = flutter.identifyWidgetExpression(node);
|
||||
if (widgetExpr == null) {
|
||||
return;
|
||||
}
|
||||
if (flutter.isExactWidgetTypeBuilder(widgetExpr.staticType)) {
|
||||
return;
|
||||
}
|
||||
var widgetSrc = utils.getNodeText(widgetExpr);
|
||||
|
||||
var builderElement = await sessionHelper.getClass(
|
||||
flutter.widgetsUri,
|
||||
'Builder',
|
||||
);
|
||||
if (builderElement == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
await builder.addDartFileEdit(file, (builder) {
|
||||
builder.addReplacement(range.node(widgetExpr), (builder) {
|
||||
builder.writeReference(builderElement);
|
||||
|
||||
builder.writeln('(');
|
||||
|
||||
var indentOld = utils.getLinePrefix(widgetExpr.offset);
|
||||
var indentNew1 = indentOld + utils.getIndent(1);
|
||||
var indentNew2 = indentOld + utils.getIndent(2);
|
||||
|
||||
builder.write(indentNew1);
|
||||
builder.writeln('builder: (context) {');
|
||||
|
||||
widgetSrc = widgetSrc.replaceAll(
|
||||
RegExp('^$indentOld', multiLine: true),
|
||||
indentNew2,
|
||||
);
|
||||
builder.write(indentNew2);
|
||||
builder.write('return $widgetSrc');
|
||||
builder.writeln(';');
|
||||
|
||||
builder.write(indentNew1);
|
||||
builder.writeln('}');
|
||||
|
||||
builder.write(indentOld);
|
||||
builder.write(')');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// Return an instance of this class. Used as a tear-off in `AssistProcessor`.
|
||||
static FlutterWrapBuilder newInstance() => FlutterWrapBuilder();
|
||||
}
|
|
@ -13,6 +13,7 @@ class Flutter {
|
|||
static final Flutter instance = Flutter();
|
||||
|
||||
static const _nameAlign = 'Align';
|
||||
static const _nameBuilder = 'Builder';
|
||||
static const _nameCenter = 'Center';
|
||||
static const _nameContainer = 'Container';
|
||||
static const _namePadding = 'Padding';
|
||||
|
@ -443,6 +444,12 @@ class Flutter {
|
|||
_isExactWidget(type.element, _nameAlign, _uriBasic);
|
||||
}
|
||||
|
||||
/// Return `true` if the given [type] is the Flutter class `StreamBuilder`.
|
||||
bool isExactWidgetTypeBuilder(DartType type) {
|
||||
return type is InterfaceType &&
|
||||
_isExactWidget(type.element, _nameBuilder, _uriBasic);
|
||||
}
|
||||
|
||||
/// Return `true` if the given [type] is the Flutter class `Center`.
|
||||
bool isExactWidgetTypeCenter(DartType type) {
|
||||
return type is InterfaceType &&
|
||||
|
|
|
@ -157,3 +157,11 @@ class Transform extends SingleChildRenderObjectWidget {
|
|||
Widget child,
|
||||
});
|
||||
}
|
||||
|
||||
typedef WidgetBuilder = Widget Function(BuildContext context);
|
||||
|
||||
class Builder {
|
||||
final WidgetBuilder builder;
|
||||
const Builder(
|
||||
{Key key, @required this.builder});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
|
||||
// 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:analyzer_plugin/utilities/assist/assist.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import 'assist_processor.dart';
|
||||
|
||||
void main() {
|
||||
defineReflectiveSuite(() {
|
||||
defineReflectiveTests(FlutterWrapBuilderTest);
|
||||
});
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class FlutterWrapBuilderTest extends AssistProcessorTest {
|
||||
@override
|
||||
AssistKind get kind => DartAssistKind.FLUTTER_WRAP_BUILDER;
|
||||
|
||||
@override
|
||||
void setUp() {
|
||||
super.setUp();
|
||||
writeTestPackageConfig(
|
||||
flutter: true,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> test_aroundBuilder() async {
|
||||
await resolveTestCode('''
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
main() {
|
||||
/*caret*/Builder(
|
||||
builder: (context) => null,
|
||||
);
|
||||
}
|
||||
''');
|
||||
await assertNoAssist();
|
||||
}
|
||||
|
||||
Future<void> test_aroundNamedConstructor() async {
|
||||
await resolveTestCode('''
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
class MyWidget extends StatelessWidget {
|
||||
MyWidget.named();
|
||||
|
||||
Widget build(BuildContext context) => null;
|
||||
}
|
||||
|
||||
main() {
|
||||
return MyWidget./*caret*/named();
|
||||
}
|
||||
''');
|
||||
await assertHasAssist('''
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
class MyWidget extends StatelessWidget {
|
||||
MyWidget.named();
|
||||
|
||||
Widget build(BuildContext context) => null;
|
||||
}
|
||||
|
||||
main() {
|
||||
return Builder(
|
||||
builder: (context) {
|
||||
return MyWidget.named();
|
||||
}
|
||||
);
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_aroundText() async {
|
||||
await resolveTestCode('''
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
main() {
|
||||
/*caret*/Text('a');
|
||||
}
|
||||
''');
|
||||
await assertHasAssist('''
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
main() {
|
||||
Builder(
|
||||
builder: (context) {
|
||||
return Text('a');
|
||||
}
|
||||
);
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_assignment() async {
|
||||
await resolveTestCode('''
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
main() {
|
||||
Widget w;
|
||||
w = /*caret*/Container();
|
||||
}
|
||||
''');
|
||||
await assertHasAssist('''
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
main() {
|
||||
Widget w;
|
||||
w = Builder(
|
||||
builder: (context) {
|
||||
return Container();
|
||||
}
|
||||
);
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_expressionFunctionBody() async {
|
||||
await resolveTestCode('''
|
||||
import 'package:flutter/widgets.dart';
|
||||
class FakeFlutter {
|
||||
main() => /*caret*/Container();
|
||||
}
|
||||
''');
|
||||
await assertHasAssist('''
|
||||
import 'package:flutter/widgets.dart';
|
||||
class FakeFlutter {
|
||||
main() => Builder(
|
||||
builder: (context) {
|
||||
return Container();
|
||||
}
|
||||
);
|
||||
}
|
||||
''');
|
||||
}
|
||||
}
|
|
@ -54,6 +54,7 @@ import 'flutter_remove_widget_test.dart' as flutter_remove_widget;
|
|||
import 'flutter_surround_with_set_state_test.dart' as surround_with_set_state;
|
||||
import 'flutter_swap_with_child_test.dart' as flutter_swap_with_child;
|
||||
import 'flutter_swap_with_parent_test.dart' as flutter_swap_with_parent;
|
||||
import 'flutter_wrap_builder_test.dart' as flutter_wrap_builder;
|
||||
import 'flutter_wrap_center_test.dart' as flutter_wrap_center;
|
||||
import 'flutter_wrap_column_test.dart' as flutter_wrap_column;
|
||||
import 'flutter_wrap_container_test.dart' as flutter_wrap_container;
|
||||
|
@ -139,6 +140,7 @@ void main() {
|
|||
flutter_wrap_padding.main();
|
||||
flutter_wrap_row.main();
|
||||
flutter_wrap_sized_box.main();
|
||||
flutter_wrap_builder.main();
|
||||
flutter_wrap_stream_builder.main();
|
||||
import_add_show.main();
|
||||
inline_invocation.main();
|
||||
|
|
Loading…
Reference in a new issue