Skip to content

Commit 9e2d8a2

Browse files
FMorschelCommit Queue
authored andcommitted
[DAS] Fixes completion for dot-shorthand in FutureOr<T> and for switches
Bug: #61872 Change-Id: Ie3cfab513b409f7c12d5d920839a4d9076172580 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/458740 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Brian Wilkerson <[email protected]> Auto-Submit: Felipe Morschel <[email protected]> Reviewed-by: Kallen Tu <[email protected]>
1 parent 475efb1 commit 9e2d8a2

File tree

4 files changed

+294
-3
lines changed

4 files changed

+294
-3
lines changed

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,11 @@ class _ContextTypeVisitor extends SimpleAstVisitor<DartType> {
648648
}
649649
}
650650

651+
@override
652+
DartType? visitConstantPattern(ConstantPattern node) {
653+
return _visitParent(node);
654+
}
655+
651656
@override
652657
DartType? visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
653658
if (node.equals.end <= offset) {
@@ -823,6 +828,21 @@ class _ContextTypeVisitor extends SimpleAstVisitor<DartType> {
823828
return null;
824829
}
825830

831+
@override
832+
DartType? visitGuardedPattern(GuardedPattern node) {
833+
if (node.parent
834+
case SwitchExpressionCase(parent: SwitchExpression(:var expression)) ||
835+
SwitchPatternCase(parent: SwitchStatement(:var expression))) {
836+
var when = node.whenClause;
837+
if (when != null && range.startEnd(when, node).contains(offset)) {
838+
return typeProvider.boolType;
839+
} else {
840+
return expression.staticType;
841+
}
842+
}
843+
return null;
844+
}
845+
826846
@override
827847
DartType? visitIfElement(IfElement node) {
828848
if (range
@@ -1391,6 +1411,10 @@ extension on ArgumentList {
13911411
case ConstructorElement constructorElement) {
13921412
return constructorElement.type;
13931413
}
1414+
} else if (parent is SuperConstructorInvocation) {
1415+
if (parent.element case ConstructorElement constructorElement) {
1416+
return constructorElement.type;
1417+
}
13941418
}
13951419
return null;
13961420
}

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -951,6 +951,7 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
951951
var period = node.period;
952952
if (offset >= period.end && offset <= node.constructorName.end) {
953953
var contextType = _computeContextType(node);
954+
contextType = _resolveFutureOrType(contextType);
954955
if (contextType is! InterfaceType) return;
955956
declarationHelper(
956957
mustBeConstant: node.isConst,
@@ -965,6 +966,7 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
965966
var period = node.period;
966967
if (offset >= period.end && offset <= node.memberName.end) {
967968
var contextType = _computeContextType(node);
969+
contextType = _resolveFutureOrType(contextType);
968970
if (contextType == null) return;
969971

970972
var element = contextType.element;
@@ -981,6 +983,7 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
981983
@override
982984
void visitDotShorthandPropertyAccess(DotShorthandPropertyAccess node) {
983985
var contextType = _computeContextType(node);
986+
contextType = _resolveFutureOrType(contextType);
984987
if (contextType == null) return;
985988

986989
var element = contextType.element;
@@ -4086,6 +4089,13 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
40864089
return 'ArgumentList_${context}_$argumentKind';
40874090
}
40884091

4092+
DartType? _resolveFutureOrType(DartType? contextType) {
4093+
if (contextType is InterfaceType && contextType.isDartAsyncFutureOr) {
4094+
return contextType.typeArguments.firstOrNull;
4095+
}
4096+
return contextType;
4097+
}
4098+
40894099
/// Suggests overrides in the context of the given [element].
40904100
///
40914101
/// If the budget has been exceeded, then the results are marked as incomplete
@@ -4114,9 +4124,7 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
41144124
required RecordLiteral? recordLiteral,
41154125
required bool isNewField,
41164126
}) {
4117-
if (contextType != null && (contextType.isDartAsyncFutureOr)) {
4118-
contextType = (contextType as InterfaceType).typeArguments.firstOrNull;
4119-
}
4127+
contextType = _resolveFutureOrType(contextType);
41204128
RecordType recordType;
41214129
if (contextType is RecordType) {
41224130
recordType = contextType;

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

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,42 @@ suggestions
125125
''');
126126
}
127127

128+
Future<void> test_class_functionExpression_futureOr() async {
129+
allowedIdentifiers = {'getter'};
130+
await computeSuggestions('''
131+
class C {
132+
static C get getter => C();
133+
}
134+
135+
Future<C> foo() async => .^;
136+
''');
137+
assertResponse(r'''
138+
suggestions
139+
getter
140+
kind: getter
141+
''');
142+
}
143+
144+
Future<void> test_class_switch_expression() async {
145+
allowedIdentifiers = {'getter'};
146+
await computeSuggestions('''
147+
class C {
148+
static C get getter => C();
149+
}
150+
151+
void foo(C c) {
152+
int _ = switch (c) {
153+
.^
154+
};
155+
}
156+
''');
157+
assertResponse(r'''
158+
suggestions
159+
getter
160+
kind: getter
161+
''');
162+
}
163+
128164
Future<void> test_class_withPrefix() async {
129165
allowedIdentifiers = {'getter', 'anotherGetter', 'notStatic'};
130166
await computeSuggestions('''
@@ -165,6 +201,66 @@ suggestions
165201
''');
166202
}
167203

204+
Future<void> test_enum_functionExpression_futureOr() async {
205+
allowedIdentifiers = {'red', 'blue', 'yellow'};
206+
await computeSuggestions('''
207+
enum E { red, blue, yellow }
208+
209+
Future<E> foo() async => .^;
210+
''');
211+
assertResponse(r'''
212+
suggestions
213+
blue
214+
kind: enumConstant
215+
red
216+
kind: enumConstant
217+
yellow
218+
kind: enumConstant
219+
''');
220+
}
221+
222+
Future<void> test_enum_parameter_futureOr() async {
223+
allowedIdentifiers = {'red', 'blue', 'yellow'};
224+
await computeSuggestions('''
225+
import 'dart:async';
226+
227+
enum E { red, blue, yellow }
228+
229+
void foo(FutureOr<E> e) {
230+
foo(.^);
231+
}
232+
''');
233+
assertResponse(r'''
234+
suggestions
235+
blue
236+
kind: enumConstant
237+
red
238+
kind: enumConstant
239+
yellow
240+
kind: enumConstant
241+
''');
242+
}
243+
244+
Future<void> test_enum_return_futureOr() async {
245+
allowedIdentifiers = {'red', 'blue', 'yellow'};
246+
await computeSuggestions('''
247+
enum E { red, blue, yellow }
248+
249+
Future<E> foo() async {
250+
return .^;
251+
}
252+
''');
253+
assertResponse(r'''
254+
suggestions
255+
blue
256+
kind: enumConstant
257+
red
258+
kind: enumConstant
259+
yellow
260+
kind: enumConstant
261+
''');
262+
}
263+
168264
Future<void> test_enum_static() async {
169265
allowedIdentifiers = {'red', 'other'};
170266
await computeSuggestions('''
@@ -186,6 +282,78 @@ suggestions
186282
''');
187283
}
188284

285+
Future<void> test_enum_superCall() async {
286+
allowedIdentifiers = {'red', 'blue', 'yellow'};
287+
await computeSuggestions('''
288+
enum E { red, blue, yellow }
289+
290+
class A {
291+
A(this.e);
292+
final E e;
293+
}
294+
295+
class B extends A {
296+
B() : super(.^);
297+
}
298+
''');
299+
assertResponse(r'''
300+
suggestions
301+
blue
302+
kind: enumConstant
303+
red
304+
kind: enumConstant
305+
yellow
306+
kind: enumConstant
307+
''');
308+
}
309+
310+
Future<void> test_enum_switch_expression() async {
311+
allowedIdentifiers = {'red', 'blue', 'yellow'};
312+
await computeSuggestions('''
313+
enum E { red, blue, yellow }
314+
315+
void foo(E e) {
316+
int _ = switch (e) {
317+
.red => 1,
318+
.^
319+
};
320+
}
321+
''');
322+
assertResponse(r'''
323+
suggestions
324+
blue
325+
kind: enumConstant
326+
red
327+
kind: enumConstant
328+
yellow
329+
kind: enumConstant
330+
''');
331+
}
332+
333+
Future<void> test_enum_switch_statement() async {
334+
allowedIdentifiers = {'red', 'blue', 'yellow'};
335+
await computeSuggestions('''
336+
enum E { red, blue, yellow }
337+
338+
void foo(E e) {
339+
switch (e) {
340+
case .red:
341+
return;
342+
case .^
343+
};
344+
}
345+
''');
346+
assertResponse(r'''
347+
suggestions
348+
blue
349+
kind: enumConstant
350+
red
351+
kind: enumConstant
352+
yellow
353+
kind: enumConstant
354+
''');
355+
}
356+
189357
Future<void> test_enum_withPrefix() async {
190358
allowedIdentifiers = {'red', 'blue', 'yellow', 'black'};
191359
await computeSuggestions('''
@@ -223,6 +391,42 @@ suggestions
223391
''');
224392
}
225393

394+
Future<void> test_extensionType_functionExpression_futureOr() async {
395+
allowedIdentifiers = {'field'};
396+
await computeSuggestions('''
397+
extension type Ext(int i) {
398+
static Ext field = Ext(1);
399+
}
400+
401+
Future<Ext> foo() async => .^;
402+
''');
403+
assertResponse(r'''
404+
suggestions
405+
field
406+
kind: field
407+
''');
408+
}
409+
410+
Future<void> test_extensionType_switch_statement() async {
411+
allowedIdentifiers = {'field'};
412+
await computeSuggestions('''
413+
extension type Ext(int i) {
414+
static Ext field = Ext(1);
415+
}
416+
417+
void foo(Ext e) {
418+
switch (e) {
419+
case .^
420+
};
421+
}
422+
''');
423+
assertResponse(r'''
424+
suggestions
425+
field
426+
kind: field
427+
''');
428+
}
429+
226430
Future<void> test_extensionType_withPrefix() async {
227431
allowedIdentifiers = {'getter', 'anotherGetter', 'notStatic'};
228432
await computeSuggestions('''

0 commit comments

Comments
 (0)