From 275581bca14724093b8cdd36b033dd5978a6bf7c Mon Sep 17 00:00:00 2001 From: FMorschel Date: Tue, 16 Dec 2025 09:07:37 -0800 Subject: [PATCH] [DAS] Fixes completion for switch expression pattern after `when` Fixes: https://github.com/dart-lang/sdk/issues/62210 Change-Id: I42a3d6f3f93a8ecc8f4b866d89119a6cc49bd3e8 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/467160 Commit-Queue: Keerti Parthasarathy Reviewed-by: Samuel Rawlins Auto-Submit: Felipe Morschel Reviewed-by: Keerti Parthasarathy --- .../completion/dart/declaration_helper.dart | 2 + .../dart/in_scope_completion_pass.dart | 15 +++- .../dart/location/switch_expression_test.dart | 89 ++++++++++++++++++- 3 files changed, 100 insertions(+), 6 deletions(-) diff --git a/pkg/analysis_server/lib/src/services/completion/dart/declaration_helper.dart b/pkg/analysis_server/lib/src/services/completion/dart/declaration_helper.dart index b4d75a21d58..ee410236644 100644 --- a/pkg/analysis_server/lib/src/services/completion/dart/declaration_helper.dart +++ b/pkg/analysis_server/lib/src/services/completion/dart/declaration_helper.dart @@ -1301,6 +1301,8 @@ class DeclarationHelper { case FunctionExpression(): _visitParameterList(currentNode.parameters); _visitTypeParameterList(currentNode.typeParameters); + case GuardedPattern(): + _visitPattern(currentNode.pattern); case IfElement(): _visitIfElement(currentNode); case IfStatement(): diff --git a/pkg/analysis_server/lib/src/services/completion/dart/in_scope_completion_pass.dart b/pkg/analysis_server/lib/src/services/completion/dart/in_scope_completion_pass.dart index 07e264556f0..bbbe9d26321 100644 --- a/pkg/analysis_server/lib/src/services/completion/dart/in_scope_completion_pass.dart +++ b/pkg/analysis_server/lib/src/services/completion/dart/in_scope_completion_pass.dart @@ -3010,7 +3010,7 @@ class InScopeCompletionPass extends SimpleAstVisitor { @override void visitSwitchExpressionCase(SwitchExpressionCase node) { - if (node.arrow.isSynthetic) { + if (node.arrow.isSynthetic || node.arrow.offset >= offset) { // The user is completing in the pattern. collector.completionLocation = 'SwitchExpression_body'; _forPattern(node); @@ -3021,7 +3021,18 @@ class InScopeCompletionPass extends SimpleAstVisitor { if (endToken == expression.beginToken || endToken.isSynthetic) { // The user is completing in the expression. collector.completionLocation = 'SwitchExpressionCase_expression'; - _forExpression(node.expression); + var type = + _computeContextType(node.expression) ?? DynamicTypeImpl.instance; + _forExpression( + node.expression, + canBeBool: _canBeBool(type), + canBeNull: _canBeNull(type), + // TODO(FMorschel): Determine if the parameter type has a constant + // constructor. + // Function tear-offs and closures cannot have the `const` keyword + // before it + canSuggestConst: !type.isDartCoreFunction && type is! FunctionType, + ); } } diff --git a/pkg/analysis_server/test/services/completion/dart/location/switch_expression_test.dart b/pkg/analysis_server/test/services/completion/dart/location/switch_expression_test.dart index d41c806a415..097908a9d44 100644 --- a/pkg/analysis_server/test/services/completion/dart/location/switch_expression_test.dart +++ b/pkg/analysis_server/test/services/completion/dart/location/switch_expression_test.dart @@ -17,6 +17,45 @@ class SwitchExpressionTest extends AbstractCompletionDriverTest with SwitchExpressionTestCases {} mixin SwitchExpressionTestCases on AbstractCompletionDriverTest { + Future test_beforeArrow() async { + await computeSuggestions(''' +int f(Object p01) { + return switch (p01) { + ^ => 0, + }; +} + +class A1 { + A1.named(); +} + +const c01 = 0; + +final v01 = 0; + +int f01() => 0; +'''); + assertResponse(r''' +suggestions + A1 + kind: class + c01 + kind: topLevelVariable + const + kind: keyword + false + kind: keyword + final + kind: keyword + null + kind: keyword + true + kind: keyword + var + kind: keyword +'''); + } + Future test_body_afterArrow() async { await computeSuggestions(''' int f(Object p01) { @@ -29,12 +68,27 @@ int f(Object p01) { suggestions p01 kind: parameter - false + const kind: keyword - null - kind: keyword - true + switch kind: keyword +'''); + } + + Future test_body_afterArrow_newVar() async { + await computeSuggestions(''' +int f(Object p01) { + return switch (p01) { + var v01 => ^ + }; +} +'''); + assertResponse(r''' +suggestions + v01 + kind: localVariable + p01 + kind: parameter const kind: keyword switch @@ -72,6 +126,33 @@ suggestions '''); } + Future test_body_afterWhen_newVar() async { + await computeSuggestions(''' +int f(Object p01) { + return switch (p01) { + var v01 when ^ + }; +} +'''); + assertResponse(r''' +suggestions + v01 + kind: localVariable + false + kind: keyword + true + kind: keyword + p01 + kind: parameter + null + kind: keyword + const + kind: keyword + switch + kind: keyword +'''); + } + Future test_body_empty() async { await computeSuggestions(''' int f(Object p01) {