55import 'package:analysis_server/src/services/correction/assist.dart' ;
66import 'package:analysis_server_plugin/edit/dart/correction_producer.dart' ;
77import 'package:analyzer/src/dart/ast/extensions.dart' ;
8+ import 'package:analyzer/src/dart/element/type.dart' ;
89import 'package:analyzer/src/utilities/extensions/flutter.dart' ;
910import 'package:analyzer_plugin/utilities/assist/assist.dart' ;
1011import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart' ;
1112import 'package:analyzer_plugin/utilities/range_factory.dart' ;
1213
13- // TODO(bkonyi): share common implementation between the various builder wrappers
14- // See https://github.com/dart-lang/sdk/issues/60075
15- class FlutterWrapBuilder extends ResolvedCorrectionProducer {
16- FlutterWrapBuilder ({required super .context});
14+ class FlutterWrapBuilders extends MultiCorrectionProducer {
15+ FlutterWrapBuilders ({required super .context});
1716
1817 @override
19- CorrectionApplicability get applicability =>
20- // TODO(applicability): comment on why.
21- CorrectionApplicability
22- .singleLocation;
18+ Future <List <ResolvedCorrectionProducer >> get producers async {
19+ var producers = < ResolvedCorrectionProducer > [];
20+ var widgetExpr = node.findWidgetExpression;
21+ if (widgetExpr != null ) {
22+ producers.add (_FlutterWrapBuilder (context: context));
23+ producers.add (_FlutterWrapValueListenableBuilder (context: context));
24+ producers.add (_FlutterWrapStreamBuilder (context: context));
25+ producers.add (_FlutterWrapFutureBuilder (context: context));
26+ }
27+ return producers;
28+ }
29+ }
30+
31+ abstract class _FlutterBaseWrapBuilder extends ResolvedCorrectionProducer {
32+ final List <String > extraBuilderParams;
33+ final List <String > extraNamedParams;
34+ final String builderName;
35+
36+ _FlutterBaseWrapBuilder ({
37+ required super .context,
38+ required this .builderName,
39+ required this .extraNamedParams,
40+ required this .extraBuilderParams,
41+ });
2342
2443 @override
25- AssistKind get assistKind => DartAssistKind .FLUTTER_WRAP_BUILDER ;
44+ CorrectionApplicability get applicability =>
45+ // TODO(applicability): comment on why.
46+ CorrectionApplicability .singleLocation;
47+
48+ bool canWrapOn (TypeImpl typeOrThrow) {
49+ return ! typeOrThrow.isExactWidgetTypeBuilder;
50+ }
2651
2752 @override
2853 Future <void > compute (ChangeBuilder builder) async {
2954 var widgetExpr = node.findWidgetExpression;
3055 if (widgetExpr == null ) {
3156 return ;
3257 }
33- if (widgetExpr.typeOrThrow.isExactWidgetTypeBuilder ) {
58+ if (! canWrapOn ( widgetExpr.typeOrThrow) ) {
3459 return ;
3560 }
3661 var widgetSrc = utils.getNodeText (widgetExpr);
3762
38- var builderElement = await sessionHelper.getFlutterClass ('Builder' );
63+ var builderElement = await sessionHelper.getFlutterClass (builderName );
3964 if (builderElement == null ) {
4065 return ;
4166 }
4267
68+ var params = ['context' , ...extraBuilderParams];
69+
4370 await builder.addDartFileEdit (file, (builder) {
4471 builder.addReplacement (range.node (widgetExpr), (builder) {
4572 builder.writeReference (builderElement);
@@ -50,8 +77,17 @@ class FlutterWrapBuilder extends ResolvedCorrectionProducer {
5077 var indentNew1 = indentOld + utils.oneIndent;
5178 var indentNew2 = indentOld + utils.twoIndents;
5279
80+ var namedParams = extraNamedParams.join (', ' );
81+
82+ if (namedParams.isNotEmpty) {
83+ builder.write (indentNew1);
84+ builder.write ('$namedParams : ' );
85+ builder.addSimpleLinkedEdit ('variable' , namedParams);
86+ builder.writeln (',' );
87+ }
88+
5389 builder.write (indentNew1);
54- builder.writeln ('builder: (context ) {' );
90+ builder.writeln ('builder: (${ params . join ( ', ' )} ) {' );
5591
5692 widgetSrc = utils.replaceSourceIndent (widgetSrc, indentOld, indentNew2);
5793 builder.write (indentNew2);
@@ -69,3 +105,52 @@ class FlutterWrapBuilder extends ResolvedCorrectionProducer {
69105 });
70106 }
71107}
108+
109+ class _FlutterWrapBuilder extends _FlutterBaseWrapBuilder {
110+ _FlutterWrapBuilder ({required super .context})
111+ : super (
112+ builderName: 'Builder' ,
113+ extraNamedParams: const [],
114+ extraBuilderParams: const [],
115+ );
116+
117+ @override
118+ AssistKind get assistKind => DartAssistKind .FLUTTER_WRAP_BUILDER ;
119+ }
120+
121+ class _FlutterWrapFutureBuilder extends _FlutterBaseWrapBuilder {
122+ _FlutterWrapFutureBuilder ({required super .context})
123+ : super (
124+ builderName: 'FutureBuilder' ,
125+ extraNamedParams: const ['future' ],
126+ extraBuilderParams: const ['asyncSnapshot' ],
127+ );
128+
129+ @override
130+ AssistKind get assistKind => DartAssistKind .FLUTTER_WRAP_FUTURE_BUILDER ;
131+ }
132+
133+ class _FlutterWrapStreamBuilder extends _FlutterBaseWrapBuilder {
134+ _FlutterWrapStreamBuilder ({required super .context})
135+ : super (
136+ builderName: 'StreamBuilder' ,
137+ extraNamedParams: const ['stream' ],
138+ extraBuilderParams: const ['asyncSnapshot' ],
139+ );
140+
141+ @override
142+ AssistKind get assistKind => DartAssistKind .FLUTTER_WRAP_STREAM_BUILDER ;
143+ }
144+
145+ class _FlutterWrapValueListenableBuilder extends _FlutterBaseWrapBuilder {
146+ _FlutterWrapValueListenableBuilder ({required super .context})
147+ : super (
148+ builderName: 'ValueListenableBuilder' ,
149+ extraNamedParams: const ['valueListenable' ],
150+ extraBuilderParams: const ['value' , 'child' ],
151+ );
152+
153+ @override
154+ AssistKind get assistKind =>
155+ DartAssistKind .FLUTTER_WRAP_VALUE_LISTENABLE_BUILDER ;
156+ }
0 commit comments