Skip to content

Commit 91a3c73

Browse files
FMorschelCommit Queue
authored andcommitted
[DAS] Fixes type completion for switch expression, function declaration and async function body
Fixes: #60808 Change-Id: Ia6cc2cbad3206f62c9149a5e326dc8333aca556f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/434124 Reviewed-by: Samuel Rawlins <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Samuel Rawlins <[email protected]> Auto-Submit: Felipe Morschel <[email protected]>
1 parent 2175df0 commit 91a3c73

File tree

5 files changed

+129
-10
lines changed

5 files changed

+129
-10
lines changed

pkg/analysis_server/lib/src/services/completion/dart/feature_computer.dart

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -706,11 +706,12 @@ class _ContextTypeVisitor extends SimpleAstVisitor<DartType> {
706706
} else if (parent is FunctionExpressionImpl) {
707707
// If the surrounding function has a context type, use it.
708708
var functionContextType = parent.body.bodyContext?.contextType;
709-
if (functionContextType != null) {
709+
if (functionContextType != null &&
710+
functionContextType is! InvalidType) {
710711
return functionContextType;
711-
} else if (parent.parent is FunctionDeclaration) {
712+
} else if (parent.parent case FunctionDeclaration(:var returnType)) {
712713
// Don't walk up past the function declaration.
713-
return null;
714+
return returnType?.type;
714715
}
715716
return _visitParent(parent);
716717
}
@@ -1082,7 +1083,14 @@ parent3: ${node.parent?.parent?.parent}
10821083
if (node.returnKeyword.end < offset) {
10831084
var functionBody = node.thisOrAncestorOfType<FunctionBodyImpl>();
10841085
if (functionBody != null) {
1085-
return functionBody.bodyContext?.contextType;
1086+
AstNode? invocationParent;
1087+
if (functionBody.parent?.parent case FunctionExpressionInvocation(
1088+
:var parent,
1089+
)) {
1090+
invocationParent = parent;
1091+
}
1092+
return functionBody.bodyContext?.contextType ??
1093+
invocationParent?.accept(this);
10861094
}
10871095
}
10881096
return null;
@@ -1144,6 +1152,14 @@ parent3: ${node.parent?.parent?.parent}
11441152
return super.visitSwitchCase(node);
11451153
}
11461154

1155+
@override
1156+
DartType? visitSwitchExpressionCase(SwitchExpressionCase node) {
1157+
if (node.parent case SwitchExpression(:var parent?)) {
1158+
return parent.accept(this);
1159+
}
1160+
return super.visitSwitchExpressionCase(node);
1161+
}
1162+
11471163
@override
11481164
DartType? visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
11491165
if (node.variables.contains(offset)) {

pkg/analysis_server/lib/src/services/completion/dart/in_scope_completion_pass.dart

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4040,7 +4040,13 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
40404040
required RecordLiteral? recordLiteral,
40414041
required bool isNewField,
40424042
}) {
4043-
if (contextType is! RecordType) {
4043+
if (contextType != null && (contextType.isDartAsyncFutureOr)) {
4044+
contextType = (contextType as InterfaceType).typeArguments.firstOrNull;
4045+
}
4046+
RecordType recordType;
4047+
if (contextType is RecordType) {
4048+
recordType = contextType;
4049+
} else {
40444050
return;
40454051
}
40464052

@@ -4058,7 +4064,7 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
40584064
.toSet();
40594065
}
40604066

4061-
for (var field in contextType.namedFields) {
4067+
for (var field in recordType.namedFields) {
40624068
if (!includedNames.contains(field.name)) {
40634069
var matcherScore = state.matcher.score(field.name);
40644070
if (matcherScore != -1) {

pkg/analysis_server/test/services/completion/dart/location/record_literal_test.dart

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,38 @@ final foo01 = 0;
433433
suggestions
434434
foo01
435435
kind: topLevelVariable
436+
''');
437+
}
438+
439+
Future<void> test_futureAsync_suggests_fieldNames() async {
440+
await computeSuggestions('''
441+
Future<({int foo01, String foo02})> f() async => (foo0^);
442+
''');
443+
assertResponse(r'''
444+
replacement
445+
left: 4
446+
suggestions
447+
|foo01: |
448+
kind: namedArgument
449+
|foo02: |
450+
kind: namedArgument
451+
''');
452+
}
453+
454+
Future<void> test_futureOr_suggests_fieldNames() async {
455+
await computeSuggestions('''
456+
import 'dart:async';
457+
458+
FutureOr<({int foo01, String foo02})> f() => (foo0^);
459+
''');
460+
assertResponse(r'''
461+
replacement
462+
left: 4
463+
suggestions
464+
|foo01: |
465+
kind: namedArgument
466+
|foo02: |
467+
kind: namedArgument
436468
''');
437469
}
438470
}

pkg/analysis_server/test/services/completion/dart/location/switch_expression_test.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,16 @@ int f(Object p01) {
2929
suggestions
3030
p01
3131
kind: parameter
32-
const
33-
kind: keyword
3432
false
3533
kind: keyword
3634
null
3735
kind: keyword
38-
switch
39-
kind: keyword
4036
true
4137
kind: keyword
38+
const
39+
kind: keyword
40+
switch
41+
kind: keyword
4242
''');
4343
}
4444

pkg/analysis_server/test/src/services/completion/dart/feature_computer_test.dart

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,26 @@ int x = List<double>.foo^;
474474
''', 'int');
475475
}
476476

477+
Future<void> test_closureCallReturn() async {
478+
await assertContextType('''
479+
void f() {
480+
String f = () {
481+
return ^;
482+
}();
483+
}
484+
''', 'String');
485+
}
486+
487+
Future<void> test_closureReturn() async {
488+
await assertContextType('''
489+
void f() {
490+
String Function() f = () {
491+
return ^;
492+
};
493+
}
494+
''', 'String');
495+
}
496+
477497
Future<void> test_fieldDeclaration_int() async {
478498
await assertContextType('''
479499
class Foo {
@@ -578,6 +598,42 @@ void f() {
578598
''', 'bool');
579599
}
580600

601+
Future<void> test_functionExpressionCallReturn() async {
602+
await assertContextType('''
603+
void f() {
604+
String f = (() => ^)();
605+
}
606+
''', 'String');
607+
}
608+
609+
Future<void> test_functionExpressionReturn() async {
610+
await assertContextType('''
611+
void f() {
612+
String Function() f = (() => ^);
613+
}
614+
''', 'String');
615+
}
616+
617+
Future<void> test_futureOrRecord() async {
618+
await assertContextType('''
619+
import 'dart:async';
620+
621+
FutureOr<({int field})> f() => ^;
622+
''', 'FutureOr<({int field})>');
623+
}
624+
625+
Future<void> test_futureType_async() async {
626+
await assertContextType('''
627+
Future<String> f() async => ^;
628+
''', 'FutureOr<String>');
629+
}
630+
631+
Future<void> test_futureType_noAsync() async {
632+
await assertContextType('''
633+
Future<String> f() => ^;
634+
''', 'Future<String>');
635+
}
636+
581637
Future<void> test_ifElement() async {
582638
await assertContextType('''
583639
void f(bool b, int e) {
@@ -1052,6 +1108,15 @@ void f() {
10521108
''');
10531109
}
10541110

1111+
Future<void> test_switchExpression() async {
1112+
await assertContextType('''
1113+
String f(num n) => switch (n) {
1114+
double() => ^,
1115+
int() => '',
1116+
};
1117+
''', 'String');
1118+
}
1119+
10551120
Future<void> test_topLevelVariableDeclaration_int() async {
10561121
await assertContextType('''
10571122
int i=^;

0 commit comments

Comments
 (0)