Skip to content

Commit eb1a814

Browse files
FMorschelCommit Queue
authored andcommitted
[DAS] Fixes create fixes type resolving in for-in loops.
This makes the create fixes correctly suggest `Iterable`, `Future<Iterable>`, or `Future<Stream>` when the awaited expression is used in a for-in loop. It also takes into account the type of the loop variable for the type argument of `Iterable` or `Stream`. Fixes: #62092 Change-Id: I055af13ee12ceb141f5d75c340c607ae803d0b07 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/464782 Reviewed-by: Samuel Rawlins <[email protected]> Auto-Submit: Felipe Morschel <[email protected]> Commit-Queue: Samuel Rawlins <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]>
1 parent 4d455c1 commit eb1a814

File tree

5 files changed

+276
-30
lines changed

5 files changed

+276
-30
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ Future<void> f() async {
406406
print(x);
407407
}
408408
409-
Future<dynamic> myUndefinedFunction() async {
409+
Future<Object?> myUndefinedFunction() async {
410410
}
411411
''');
412412
}

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

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,75 @@ void f(A a) {
261261
''');
262262
}
263263

264+
Future<void> test_futureIterable_int() async {
265+
await resolveTestCode('''
266+
class C {
267+
Future<void> f() async {
268+
for (int v in await test) {
269+
print(v);
270+
}
271+
}
272+
}
273+
''');
274+
await assertHasFix('''
275+
class C {
276+
Future<Iterable<int>> get test => null;
277+
278+
Future<void> f() async {
279+
for (int v in await test) {
280+
print(v);
281+
}
282+
}
283+
}
284+
''');
285+
}
286+
287+
Future<void> test_futureIterable_nullableObject() async {
288+
await resolveTestCode('''
289+
class C {
290+
Future<void> f() async {
291+
for (var v in await test) {
292+
print(v);
293+
}
294+
}
295+
}
296+
''');
297+
await assertHasFix('''
298+
class C {
299+
Future<Iterable<Object?>> get test => null;
300+
301+
Future<void> f() async {
302+
for (var v in await test) {
303+
print(v);
304+
}
305+
}
306+
}
307+
''');
308+
}
309+
310+
Future<void> test_futureStream_NullableObject() async {
311+
await resolveTestCode('''
312+
class C {
313+
Future<void> f() async {
314+
await for (var v in await test) {
315+
print(v);
316+
}
317+
}
318+
}
319+
''');
320+
await assertHasFix('''
321+
class C {
322+
Future<Stream<Object?>> get test => null;
323+
324+
Future<void> f() async {
325+
await for (var v in await test) {
326+
print(v);
327+
}
328+
}
329+
}
330+
''');
331+
}
332+
264333
Future<void> test_guard() async {
265334
await resolveTestCode('''
266335
class A {
@@ -465,6 +534,101 @@ extension E on String {
465534
await assertNoFix();
466535
}
467536

537+
Future<void> test_iterable_identifier() async {
538+
await resolveTestCode('''
539+
class C {
540+
void f() {
541+
int v;
542+
for (v in test) {
543+
print(v);
544+
}
545+
}
546+
}
547+
''');
548+
await assertHasFix('''
549+
class C {
550+
Iterable<int> get test => null;
551+
552+
void f() {
553+
int v;
554+
for (v in test) {
555+
print(v);
556+
}
557+
}
558+
}
559+
''');
560+
}
561+
562+
Future<void> test_iterable_int() async {
563+
await resolveTestCode('''
564+
class C {
565+
void f() {
566+
for (int v in test) {
567+
print(v);
568+
}
569+
}
570+
}
571+
''');
572+
await assertHasFix('''
573+
class C {
574+
Iterable<int> get test => null;
575+
576+
void f() {
577+
for (int v in test) {
578+
print(v);
579+
}
580+
}
581+
}
582+
''');
583+
}
584+
585+
Future<void> test_iterable_nullableObject() async {
586+
await resolveTestCode('''
587+
class C {
588+
void f() {
589+
for (var v in test) {
590+
print(v);
591+
}
592+
}
593+
}
594+
''');
595+
await assertHasFix('''
596+
class C {
597+
Iterable<Object?> get test => null;
598+
599+
void f() {
600+
for (var v in test) {
601+
print(v);
602+
}
603+
}
604+
}
605+
''');
606+
}
607+
608+
@FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/62093')
609+
Future<void> test_iterable_recordDestructuring() async {
610+
await resolveTestCode('''
611+
class C {
612+
void f() {
613+
for (var (int v) in test) {
614+
print(v);
615+
}
616+
}
617+
}
618+
''');
619+
await assertHasFix('''
620+
class C {
621+
Iterable<(int,)> get test => null;
622+
623+
void f() {
624+
for (var (int v) in test) {
625+
print(v);
626+
}
627+
}
628+
}
629+
''');
630+
}
631+
468632
Future<void> test_location_afterLastGetter() async {
469633
await resolveTestCode('''
470634
class A {
@@ -1001,6 +1165,52 @@ void f(String s) {
10011165
await assertNoFix();
10021166
}
10031167

1168+
Future<void> test_stream_int() async {
1169+
await resolveTestCode('''
1170+
class C {
1171+
Future<void> f() async {
1172+
await for (int v in test) {
1173+
print(v);
1174+
}
1175+
}
1176+
}
1177+
''');
1178+
await assertHasFix('''
1179+
class C {
1180+
Stream<int> get test => null;
1181+
1182+
Future<void> f() async {
1183+
await for (int v in test) {
1184+
print(v);
1185+
}
1186+
}
1187+
}
1188+
''');
1189+
}
1190+
1191+
Future<void> test_stream_nullableObject() async {
1192+
await resolveTestCode('''
1193+
class C {
1194+
Future<void> f() async {
1195+
await for (var v in test) {
1196+
print(v);
1197+
}
1198+
}
1199+
}
1200+
''');
1201+
await assertHasFix('''
1202+
class C {
1203+
Stream<Object?> get test => null;
1204+
1205+
Future<void> f() async {
1206+
await for (var v in test) {
1207+
print(v);
1208+
}
1209+
}
1210+
}
1211+
''');
1212+
}
1213+
10041214
Future<void> test_unqualified_instance_asInvocationArgument() async {
10051215
await resolveTestCode('''
10061216
class A {

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,7 +1294,7 @@ class A {
12941294
class A {
12951295
var f = myUndefinedMethod();
12961296
1297-
static myUndefinedMethod() {}
1297+
static Object? myUndefinedMethod() {}
12981298
}
12991299
''');
13001300
}
@@ -1309,7 +1309,7 @@ class A {
13091309
class A {
13101310
late var f = myUndefinedMethod();
13111311
1312-
myUndefinedMethod() {}
1312+
Object? myUndefinedMethod() {}
13131313
}
13141314
''');
13151315
}
@@ -1475,7 +1475,7 @@ class A {
14751475
class A {
14761476
static var f = myUndefinedMethod();
14771477
1478-
static myUndefinedMethod() {}
1478+
static Object? myUndefinedMethod() {}
14791479
}
14801480
''');
14811481
}
@@ -1490,7 +1490,7 @@ class A {
14901490
class A {
14911491
static late var f = myUndefinedMethod();
14921492
1493-
static myUndefinedMethod() {}
1493+
static Object? myUndefinedMethod() {}
14941494
}
14951495
''');
14961496
}

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

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,26 +19,6 @@ class CreateParameterTest extends FixProcessorTest {
1919
@override
2020
FixKind get kind => DartFixKind.createParameter;
2121

22-
Future<void> test_dynamic_type() async {
23-
await resolveTestCode('''
24-
int f(
25-
int b,
26-
) {
27-
var i = b2;
28-
return i;
29-
}
30-
''');
31-
await assertHasFix('''
32-
int f(
33-
int b,
34-
dynamic b2,
35-
) {
36-
var i = b2;
37-
return i;
38-
}
39-
''');
40-
}
41-
4222
Future<void> test_final_comma() async {
4323
await resolveTestCode('''
4424
int f(
@@ -98,6 +78,26 @@ int f(int b, int b2) {
9878
''');
9979
}
10080

81+
Future<void> test_nullableObject_type() async {
82+
await resolveTestCode('''
83+
int f(
84+
int b,
85+
) {
86+
var i = b2;
87+
return i;
88+
}
89+
''');
90+
await assertHasFix('''
91+
int f(
92+
int b,
93+
Object? b2,
94+
) {
95+
var i = b2;
96+
return i;
97+
}
98+
''');
99+
}
100+
101101
Future<void> test_only() async {
102102
await resolveTestCode('''
103103
int f() {

pkg/analysis_server_plugin/lib/edit/dart/correction_producer.dart

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,7 @@ abstract class ResolvedCorrectionProducer
593593
var variableElement = variableDeclaration.declaredFragment?.element;
594594
if (variableElement case VariableElement(:var type)) {
595595
if (type is InvalidType) {
596-
return typeProvider.dynamicType;
596+
return typeProvider.objectQuestionType;
597597
}
598598
return type;
599599
}
@@ -733,13 +733,35 @@ abstract class ResolvedCorrectionProducer
733733
if (grandParent is ExpressionStatement) {
734734
return typeProvider.futureType(typeProvider.voidType);
735735
}
736-
var inferredParentType =
737-
inferUndefinedExpressionType(parent) ?? typeProvider.dynamicType;
738-
if (inferredParentType is InvalidType) {
739-
inferredParentType = typeProvider.dynamicType;
736+
var inferredParentType = inferUndefinedExpressionType(parent);
737+
if (inferredParentType == null || inferredParentType is InvalidType) {
738+
inferredParentType = typeProvider.objectQuestionType;
740739
}
741740
return typeProvider.futureType(inferredParentType);
742741
}
742+
// for (int x in myFunction()) { }
743+
if (parent
744+
case ForEachPartsWithDeclaration(
745+
:var iterable,
746+
:var type,
747+
parent: var statement,
748+
) ||
749+
ForEachPartsWithIdentifier(
750+
:var iterable,
751+
:var type,
752+
parent: var statement,
753+
) ||
754+
ForEachPartsWithPattern(
755+
:var iterable,
756+
:var type,
757+
parent: var statement,
758+
) when iterable == expression) {
759+
var inferredType = type ?? typeProvider.objectQuestionType;
760+
if (statement.awaitKeyword != null) {
761+
return typeProvider.streamType(inferredType);
762+
}
763+
return typeProvider.iterableType(inferredType);
764+
}
743765
// We don't know.
744766
return null;
745767
}
@@ -912,3 +934,17 @@ sealed class _AbstractCorrectionProducer<T extends ParsedUnitResult> {
912934
return _context.dartFixContext!.librariesWithExtensions(memberName);
913935
}
914936
}
937+
938+
extension on ForEachParts {
939+
DartType? get type {
940+
return switch (this) {
941+
ForEachPartsWithDeclaration(
942+
loopVariable: DeclaredIdentifier(type: TypeAnnotation(:var type)),
943+
) ||
944+
ForEachPartsWithIdentifier(
945+
identifier: Identifier(staticType: var type),
946+
) => type,
947+
_ => null,
948+
};
949+
}
950+
}

0 commit comments

Comments
 (0)