Skip to content

Commit 8e45add

Browse files
FMorschelCommit Queue
authored andcommitted
[DAS] Fixes types for convert to function declaration
Fixes: #60633 Change-Id: I97d7aa1018343d3435d019cb5c3a2605b840d8f2 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/425020 Auto-Submit: Felipe Morschel <[email protected]> Reviewed-by: Samuel Rawlins <[email protected]> Reviewed-by: Ivan Inozemtsev <[email protected]> Commit-Queue: Ivan Inozemtsev <[email protected]>
1 parent aea68e4 commit 8e45add

File tree

2 files changed

+232
-13
lines changed

2 files changed

+232
-13
lines changed

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

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44

55
import 'package:analysis_server/src/services/correction/fix.dart';
66
import 'package:analysis_server_plugin/edit/dart/correction_producer.dart';
7-
import 'package:analyzer/dart/ast/ast.dart';
7+
import 'package:analyzer/dart/ast/visitor.dart';
8+
import 'package:analyzer/dart/element/element.dart';
9+
import 'package:analyzer/dart/element/type.dart';
810
import 'package:analyzer/source/source_range.dart';
11+
import 'package:analyzer/src/dart/ast/ast.dart';
912
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
1013
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
1114
import 'package:analyzer_plugin/utilities/range_factory.dart';
@@ -54,7 +57,7 @@ class ConvertToFunctionDeclaration extends ResolvedCorrectionProducer {
5457
if (before != null) {
5558
builder.write(before);
5659
}
57-
builder.write(utils.endOfLine);
60+
builder.write(eol);
5861
builder.write(utils.getLinePrefix(range.offset));
5962
if (after != null) {
6063
builder.write(after);
@@ -77,8 +80,63 @@ class ConvertToFunctionDeclaration extends ResolvedCorrectionProducer {
7780
replaceWithNewLine(r, before: ';');
7881
}
7982

83+
DartType? returnType;
84+
List<FormalParameterElement?>? parameterList;
85+
if (type case NamedType(
86+
element2: TypeAliasElement(:GenericFunctionTypeElement aliasedElement2),
87+
)) {
88+
returnType = aliasedElement2.returnType;
89+
parameterList = aliasedElement2.formalParameters;
90+
} else if (type is GenericFunctionType) {
91+
returnType = type.returnType?.type;
92+
parameterList =
93+
type.parameters.parameters
94+
.map((node) => node.declaredFragment!.element)
95+
.toList();
96+
} else if (initializer case FunctionExpression(
97+
declaredFragment: ExecutableFragment(:var element),
98+
:var body,
99+
)) {
100+
returnType = element.returnType;
101+
var visitor = _ReturnVisitor();
102+
body.accept(visitor);
103+
if (visitor.noReturnFounds) {
104+
if (typeProvider.nullType == element.returnType) {
105+
returnType = typeProvider.voidType;
106+
} else if (typeProvider.futureNullType == element.returnType) {
107+
returnType = typeProvider.futureType(typeProvider.voidType);
108+
}
109+
}
110+
}
111+
112+
if (builder.canWriteType(returnType)) {
113+
builder.addInsertion(node.offset, (builder) {
114+
builder.writeType(returnType);
115+
builder.write(' ');
116+
});
117+
}
118+
80119
builder.addDeletion(range.endStart(equals.previous!, equals.next!));
81120

121+
if (parameterList != null) {
122+
var staticParameters = parameterList;
123+
if (initializer case FunctionExpression(:var parameters?)) {
124+
for (var (index, parameter) in parameters.parameters.indexed) {
125+
if (parameter.isExplicitlyTyped) {
126+
continue;
127+
}
128+
var staticParameterType = staticParameters[index]?.type;
129+
if (!builder.canWriteType(staticParameterType)) {
130+
continue;
131+
}
132+
builder.addInsertion(parameter.offset, (builder) {
133+
builder.writeType(staticParameterType);
134+
builder.write(' ');
135+
});
136+
}
137+
}
138+
}
139+
82140
if (next != null) {
83141
var r = range.endStart(node.endToken, node.endToken.next!.next!);
84142
if (next.initializer is FunctionExpression) {
@@ -116,3 +174,25 @@ class ConvertToFunctionDeclaration extends ResolvedCorrectionProducer {
116174
return i > 0 ? variables[i - 1] : null;
117175
}
118176
}
177+
178+
class _ReturnVisitor extends RecursiveAstVisitor<void> {
179+
int _count = 0;
180+
bool get noReturnFounds => _count == 0;
181+
182+
@override
183+
void visitExpressionFunctionBody(ExpressionFunctionBody node) {
184+
_count++;
185+
super.visitExpressionFunctionBody(node);
186+
}
187+
188+
@override
189+
void visitFunctionExpression(FunctionExpression node) {
190+
// Inner function expressions are not counted.
191+
}
192+
193+
@override
194+
void visitReturnStatement(ReturnStatement node) {
195+
_count++;
196+
super.visitReturnStatement(node);
197+
}
198+
}

pkg/analysis_server/test/src/services/correction/fix/convert_to_function_declaration_test.dart

Lines changed: 150 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ void f() {
3434
''');
3535
await assertHasFix('''
3636
void f() {
37-
v1() {}
38-
v2() {}
37+
void v1() {}
38+
void v2() {}
3939
v1();
4040
v2();
4141
}
@@ -52,8 +52,8 @@ void f() {
5252
''');
5353
await assertHasFix('''
5454
void f() {
55-
v1() {}
56-
v2() {}
55+
void v1() {}
56+
void v2() {}
5757
v1();
5858
v2();
5959
}
@@ -80,8 +80,8 @@ void f() {
8080
expect(fixes, hasLength(1));
8181
assertProduces(fixes.first, '''
8282
void f() {
83-
v() {
84-
v() {}
83+
void v() {
84+
void v() {}
8585
v();
8686
}
8787
v();
@@ -107,7 +107,7 @@ void f() {
107107
''');
108108
await assertHasFix('''
109109
void f() {
110-
v() {}
110+
void v() {}
111111
v();
112112
}
113113
''');
@@ -123,7 +123,7 @@ void f() {
123123
await assertHasFix('''
124124
void f() {
125125
final v1 = 1;
126-
v2(x, y) {}
126+
void v2(x, y) {}
127127
final v3 = '';
128128
v2(v1, v3);
129129
}
@@ -139,12 +139,92 @@ void f() {
139139
''');
140140
await assertHasFix('''
141141
void f() {
142-
v() => 3;
142+
int v() => 3;
143143
v();
144144
}
145145
''');
146146
}
147147

148+
Future<void> test_functionTypedParameter() async {
149+
await resolveTestCode('''
150+
void f() {
151+
int Function(int Function(String)?) v1 = (p) {
152+
return p?.call('') ?? 0;
153+
};
154+
v1((s) => 0);
155+
}
156+
''');
157+
await assertHasFix('''
158+
void f() {
159+
int v1(int Function(String p1)? p) {
160+
return p?.call('') ?? 0;
161+
}
162+
v1((s) => 0);
163+
}
164+
''');
165+
}
166+
167+
Future<void> test_futureIntBody() async {
168+
await resolveTestCode('''
169+
void f() {
170+
final v1 = () async {
171+
return 0;
172+
};
173+
v1();
174+
}
175+
''');
176+
await assertHasFix('''
177+
void f() {
178+
Future<int> v1() async {
179+
return 0;
180+
}
181+
v1();
182+
}
183+
''');
184+
}
185+
186+
Future<void> test_futureVoid() async {
187+
await resolveTestCode('''
188+
void f() {
189+
final v1 = () async {
190+
};
191+
v1();
192+
}
193+
''');
194+
await assertHasFix('''
195+
void f() {
196+
Future<void> v1() async {
197+
}
198+
v1();
199+
}
200+
''');
201+
}
202+
203+
Future<void> test_innerFunctions() async {
204+
await resolveTestCode('''
205+
void f() {
206+
final v1 = () {
207+
() {
208+
return 0;
209+
};
210+
() => 0;
211+
};
212+
v1();
213+
}
214+
''');
215+
await assertHasFix('''
216+
void f() {
217+
void v1() {
218+
() {
219+
return 0;
220+
};
221+
() => 0;
222+
}
223+
v1();
224+
}
225+
''');
226+
}
227+
148228
Future<void> test_no_initializer() async {
149229
await resolveTestCode('''
150230
typedef F = void Function();
@@ -160,7 +240,7 @@ void f() {
160240
typedef F = void Function();
161241
162242
void f() {
163-
g() {}
243+
void g() {}
164244
final F h;
165245
g();
166246
h = () {};
@@ -178,9 +258,68 @@ void f() {
178258
''');
179259
await assertHasFix('''
180260
void f() {
181-
v() => throw '';
261+
String v() => throw '';
182262
v();
183263
}
264+
''');
265+
}
266+
267+
Future<void> test_typedefTyped() async {
268+
await resolveTestCode('''
269+
typedef T = int Function(int);
270+
271+
void f() {
272+
T v1 = (p) {
273+
return p;
274+
};
275+
v1(0);
276+
}
277+
''');
278+
await assertHasFix('''
279+
typedef T = int Function(int);
280+
281+
void f() {
282+
int v1(int p) {
283+
return p;
284+
}
285+
v1(0);
286+
}
287+
''');
288+
}
289+
290+
Future<void> test_typeParameter() async {
291+
await resolveTestCode('''
292+
void f() {
293+
final v1 = <T>(T p) {
294+
};
295+
v1(0);
296+
}
297+
''');
298+
await assertHasFix('''
299+
void f() {
300+
void v1<T>(T p) {
301+
}
302+
v1(0);
303+
}
304+
''');
305+
}
306+
307+
Future<void> test_variableTyped() async {
308+
await resolveTestCode('''
309+
void f() {
310+
int Function(int) v1 = (p) {
311+
return p;
312+
};
313+
v1(0);
314+
}
315+
''');
316+
await assertHasFix('''
317+
void f() {
318+
int v1(int p) {
319+
return p;
320+
}
321+
v1(0);
322+
}
184323
''');
185324
}
186325
}

0 commit comments

Comments
 (0)