Completion. Issue 55167. Suggest type names for DeclaredVariablePattern, in SwitchPatternCase.

Bug: https://github.com/dart-lang/sdk/issues/55167
Change-Id: I1f00fd0ea589786767443d97e7c74b7f482ba4be
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/359243
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Konstantin Shcheglov 2024-03-23 17:01:30 +00:00 committed by Commit Queue
parent 5acb2132f8
commit c61aecda75
2 changed files with 195 additions and 0 deletions

View file

@ -2338,6 +2338,8 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
@override
void visitSwitchPatternCase(SwitchPatternCase node) {
var coveringNode = state.selection.coveringNode;
if (offset <= node.keyword.end) {
keywordHelper.addKeyword(Keyword.CASE);
} else if (offset <= node.colon.offset) {
@ -2350,6 +2352,39 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
}
}
// `case ^ y:`
// The user want a type for incomplete DeclaredVariablePattern.
var pattern = node.guardedPattern.pattern;
if (pattern is ConstantPattern) {
if (pattern.expression case SimpleIdentifier identifier) {
if (!identifier.isSynthetic && offset < identifier.offset) {
state.request.opType.includeConstructorSuggestions = false;
state.request.opType.mustBeConst = true;
declarationHelper(
mustBeType: true,
).addLexicalDeclarations(node);
return;
}
}
}
// DeclaredVariablePattern `case Name^ y:`
// ObjectPattern `case Name^(): `
if (coveringNode case NamedType type) {
switch (type.parent) {
case DeclaredVariablePattern():
collector.completionLocation = 'DeclaredVariablePattern_type';
state.request.opType.includeConstructorSuggestions = false;
type.accept(this);
return;
case ObjectPattern():
collector.completionLocation = 'ObjectPattern_type';
state.request.opType.includeConstructorSuggestions = false;
type.accept(this);
return;
}
}
collector.completionLocation = 'SwitchPatternCase_pattern';
var previous = node.colon.previous!;
var previousKeyword = previous.keyword;

View file

@ -52,6 +52,166 @@ suggestions
''');
}
Future<void> test_afterCase_declaredVariablePattern_typeX_name() async {
// It is essential to import this library.
// Currently not-yet imported contributor adds classes.
// But we want to exercise InScopeCompletionPass.
newFile('$testPackageLibPath/a.dart', r'''
class A01 {}
class A02 {}
class B01 {}
''');
await computeSuggestions('''
import 'a.dart';
void f(Object? x) {
switch (x) {
case 0: break;
case A0^ y:
break;
}
}
''');
assertResponse(r'''
replacement
left: 2
suggestions
A01
kind: class
A02
kind: class
''');
}
Future<void> test_afterCase_final_x_name() async {
await computeSuggestions('''
void f(Object? x) {
switch (x) {
case final ^ y:
}
}
class A01 {}
class A02 {}
class B01 {}
''');
assertResponse(r'''
suggestions
A01
kind: class
A02
kind: class
B01
kind: class
''');
}
Future<void> test_afterCase_nameX_includeClass_imported() async {
newFile('$testPackageLibPath/a.dart', r'''
class A01 {}
class A02 {}
class B01 {}
''');
await computeSuggestions('''
import 'a.dart';
void f(Object? x) {
switch (x) {
case A0^
}
}
''');
assertResponse(r'''
replacement
left: 2
suggestions
A01
kind: class
A01
kind: constructorInvocation
A02
kind: class
A02
kind: constructorInvocation
''');
}
Future<void> test_afterCase_nameX_includeClass_local() async {
await computeSuggestions('''
void f(Object? x) {
switch (x) {
case A0^
}
}
class A01 {}
class A02 {}
class B01 {}
''');
assertResponse(r'''
replacement
left: 2
suggestions
A01
kind: class
A01
kind: constructorInvocation
A02
kind: class
A02
kind: constructorInvocation
''');
}
Future<void> test_afterCase_nameX_includeClass_notImported() async {
newFile('$testPackageLibPath/a.dart', r'''
class A01 {}
class A02 {}
class B01 {}
''');
await computeSuggestions('''
void f(Object? x) {
switch (x) {
case A0^
}
}
''');
// TODO(scheglov): this is wrong, include only const constructors.
assertResponse(r'''
replacement
left: 2
suggestions
A01
kind: class
A02
kind: class
''');
}
Future<void> test_afterCase_nothing_x_name() async {
await computeSuggestions('''
void f(Object? x) {
switch (x) {
case ^ y:
}
}
class A01 {}
class A02 {}
class B01 {}
''');
assertResponse(r'''
suggestions
A01
kind: class
A02
kind: class
B01
kind: class
''');
}
Future<void> test_afterCase_partial() async {
await computeSuggestions('''
void f(Object x) {