From ea1d1d76218623ac44f150882a1c005ba81c3e00 Mon Sep 17 00:00:00 2001 From: Konstantin Shcheglov Date: Fri, 23 Mar 2018 00:26:45 +0000 Subject: [PATCH] Support for extracting methods with parameters. R=brianwilkerson@google.com Bug: https://github.com/flutter/flutter-intellij/issues/1250 Change-Id: I906e14feba246a7704fbbcdaa358730be5916a47 Reviewed-on: https://dart-review.googlesource.com/47945 Reviewed-by: Brian Wilkerson Commit-Queue: Konstantin Shcheglov --- .../services/refactoring/extract_widget.dart | 36 ++++++++-- .../refactoring/extract_widget_test.dart | 67 +++++++++++++++++++ 2 files changed, 96 insertions(+), 7 deletions(-) diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_widget.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_widget.dart index d1b3215c645..fae6127938d 100644 --- a/pkg/analysis_server/lib/src/services/refactoring/extract_widget.dart +++ b/pkg/analysis_server/lib/src/services/refactoring/extract_widget.dart @@ -205,11 +205,11 @@ class ExtractWidgetRefactoringImpl extends RefactoringImpl // We added fields, now add the method parameters. if (_method != null) { - // TODO(scheglov) test for method parameters for (var parameter in _method.parameters.parameters) { if (parameter is NormalFormalParameter) { _parameters.add(new _Parameter( - parameter.identifier.name, parameter.element.type)); + parameter.identifier.name, parameter.element.type, + isMethodParameter: true)); } } } @@ -231,10 +231,29 @@ class ExtractWidgetRefactoringImpl extends RefactoringImpl var collector = new _MethodInvocationsCollector(_method.element); _enclosingClassNode.accept(collector); for (var invocation in collector.invocations) { - builder.addReplacement(range.node(invocation), (builder) { - // TODO(scheglov) use arguments - _writeWidgetInstantiation(builder); - }); + builder.addReplacement( + range.startEnd(invocation, invocation.argumentList.leftParenthesis), + (builder) { + builder.write('new $name('); + + // Insert field references. + for (var parameter in _parameters) { + if (parameter.isMethodParameter) { + break; + } + if (parameter != _parameters.first) { + builder.write(', '); + } + builder.write(parameter.name); + } + + // Separate references to fields and method arguments. + if (_parameters.isNotEmpty && + invocation.argumentList.arguments.isNotEmpty) { + builder.write(', '); + } + }, + ); } } @@ -336,7 +355,10 @@ class _Parameter { final String name; final DartType type; - _Parameter(this.name, this.type); + /// Whether the parameter is a parameter of the method being extracted. + final bool isMethodParameter; + + _Parameter(this.name, this.type, {this.isMethodParameter = false}); } class _ParametersCollector extends RecursiveAstVisitor { diff --git a/pkg/analysis_server/test/services/refactoring/extract_widget_test.dart b/pkg/analysis_server/test/services/refactoring/extract_widget_test.dart index cd83a247950..98bdf4ee576 100644 --- a/pkg/analysis_server/test/services/refactoring/extract_widget_test.dart +++ b/pkg/analysis_server/test/services/refactoring/extract_widget_test.dart @@ -357,6 +357,73 @@ class Test extends StatelessWidget { '''); } + test_method_parameters() async { + addFlutterPackage(); + await indexTestUnit(r''' +import 'package:flutter/material.dart'; + +class MyWidget extends StatelessWidget { + String foo; + + @override + Widget build(BuildContext context) { + int bar = 1; + return new Row( + children: [ + createColumn('aaa', bar), + createColumn('bbb', 2), + ], + ); + } + + Widget createColumn(String p1, int p2) { + var a = new Text('$foo $p1'); + var b = new Text('$p2'); + return new Column( + children: [a, b], + ); + } +} +'''); + _createRefactoringForStringOffset('createColumn(String'); + + await _assertSuccessfulRefactoring(r''' +import 'package:flutter/material.dart'; + +class MyWidget extends StatelessWidget { + String foo; + + @override + Widget build(BuildContext context) { + int bar = 1; + return new Row( + children: [ + new Test(foo, 'aaa', bar), + new Test(foo, 'bbb', 2), + ], + ); + } +} + +class Test extends StatelessWidget { + final String foo; + final String p1; + final int p2; + + Test(this.foo, this.p1, this.p2); + + @override + Widget build(BuildContext context) { + var a = new Text('$foo $p1'); + var b = new Text('$p2'); + return new Column( + children: [a, b], + ); + } +} +'''); + } + test_parameters_field_read_enclosingClass() async { addFlutterPackage(); await indexTestUnit(r'''