Skip to content

Commit bd2a0e6

Browse files
FMorschelCommit Queue
authored andcommitted
[DAS] Fixes keyword/type in auto-completion for pattern matching
Fixes: #59854 Change-Id: Ic7a0dee51eb45792520ae49d935510e8669f94ff Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/417222 Reviewed-by: Samuel Rawlins <[email protected]> Auto-Submit: Felipe Morschel <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Brian Wilkerson <[email protected]>
1 parent 426227b commit bd2a0e6

File tree

12 files changed

+955
-202
lines changed

12 files changed

+955
-202
lines changed

pkg/analysis_server/lib/src/lsp/completion_utils.dart

Lines changed: 84 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import 'package:path/path.dart' as path;
2727

2828
/// Computes completion string, text to display and imports, if any for
2929
/// an [OverrideSuggestion].
30-
Future<OverrideData?> createOverrideSuggestionData(
30+
Future<TypeImportData?> createOverrideSuggestionData(
3131
OverrideSuggestion suggestion,
3232
DartCompletionRequest request,
3333
) async {
@@ -86,7 +86,7 @@ Future<OverrideData?> createOverrideSuggestionData(
8686
if (suggestion.skipAt) {
8787
displayText = 'override $displayText';
8888
}
89-
return OverrideData(
89+
return TypeImportData(
9090
completion,
9191
displayText,
9292
overrideImports,
@@ -95,6 +95,74 @@ Future<OverrideData?> createOverrideSuggestionData(
9595
);
9696
}
9797

98+
/// Computes completion string, text to display and imports, if any for
99+
/// an [TypedSuggestion].
100+
Future<TypeImportData?> createTypedSuggestionData(
101+
TypedSuggestion suggestion,
102+
DartCompletionRequest request,
103+
) async {
104+
// No keyword or type annotation means that we don't need to do anything.
105+
if (!suggestion.addTypeAnnotation && suggestion.keyword == null) {
106+
return null;
107+
}
108+
var typeImports = <Uri>{};
109+
var builder = ChangeBuilder(session: request.analysisSession);
110+
await builder.addDartFileEdit(request.path, createEditsForImports: false, (
111+
builder,
112+
) {
113+
builder.addReplacement(suggestion.replacementRange, (builder) {
114+
if (suggestion.keyword case var keyword?) {
115+
builder.write(keyword.lexeme);
116+
builder.write(' ');
117+
}
118+
if (suggestion.addTypeAnnotation) {
119+
builder.writeType(suggestion.type, shouldWriteDynamic: true);
120+
builder.write(' ');
121+
}
122+
if (suggestion is SetStateMethodSuggestion &&
123+
(suggestion.addTypeAnnotation || suggestion.keyword != null)) {
124+
builder.write('setState');
125+
} else {
126+
builder.write(suggestion.completion);
127+
}
128+
});
129+
typeImports.addAll(builder.requiredImports);
130+
});
131+
132+
var fileEdits = builder.sourceChange.edits;
133+
if (fileEdits.length != 1) {
134+
return null;
135+
}
136+
137+
var sourceEdits = fileEdits.first.edits;
138+
if (sourceEdits.length != 1) {
139+
return null;
140+
}
141+
142+
var replacement = sourceEdits.first.replacement;
143+
var completion = replacement.trim();
144+
if (completion.isEmpty) {
145+
return null;
146+
}
147+
148+
var selectionRange = builder.selectionRange;
149+
150+
int? selectionOffset;
151+
if (selectionRange != null) {
152+
var offsetDelta =
153+
suggestion.replacementRange.offset + replacement.indexOf(completion);
154+
selectionOffset = selectionRange.offset - offsetDelta;
155+
}
156+
157+
return TypeImportData(
158+
completion,
159+
suggestion.completion,
160+
typeImports,
161+
selectionOffset,
162+
selectionRange?.length,
163+
);
164+
}
165+
98166
// TODO(keertip): Move over completions for plugins and snippets to use
99167
// this function.
100168
Future<lsp.CompletionItem?> toLspCompletionItem(
@@ -268,9 +336,11 @@ Future<lsp.CompletionItem?> toLspCompletionItem(
268336

269337
if (suggestion is SuggestionData) {
270338
selectionOffset = (suggestion as SuggestionData).selectionOffset;
271-
} else if (suggestion case OverrideSuggestion(:var data?)) {
272-
selectionOffset = data.selectionOffset;
273-
selectionLength = data.selectionLength;
339+
} else if (suggestion case TypedSuggestion(
340+
data: TypeImportData(:var selectionOffset?, :var selectionLength?),
341+
)) {
342+
selectionOffset = selectionOffset;
343+
selectionLength = selectionLength;
274344
}
275345

276346
var insertTextInfo = buildInsertText(
@@ -652,16 +722,15 @@ String _getDisplayText(
652722
CandidateSuggestion suggestion,
653723
DartCompletionRequest request,
654724
) {
655-
if (suggestion is SuggestionData) {
656-
return (suggestion as SuggestionData).displayText;
657-
}
658-
if (suggestion is FunctionCall) {
659-
return 'call()';
660-
}
661-
if (suggestion is OverrideSuggestion) {
662-
return suggestion.data?.displayText ?? suggestion.completion;
663-
}
664-
return suggestion.completion;
725+
return switch (suggestion) {
726+
SuggestionData(:var displayText) => displayText,
727+
FunctionCall() => 'call()',
728+
OverrideSuggestion(:var data, :var completion) =>
729+
data?.displayText ?? completion,
730+
TypedSuggestion(:var data, :var completion) =>
731+
data?.displayText ?? completion,
732+
_ => suggestion.completion,
733+
};
665734
}
666735

667736
/// If the [element] has a documentation comment, return it.

pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import 'package:analysis_server/src/services/completion/yaml/yaml_completion_gen
2424
import 'package:analysis_server/src/services/snippets/dart_snippet_request.dart';
2525
import 'package:analysis_server/src/services/snippets/snippet_manager.dart';
2626
import 'package:analysis_server/src/utilities/element_location2.dart';
27+
import 'package:analysis_server/src/utilities/extensions/object.dart';
2728
import 'package:analyzer/dart/analysis/results.dart';
2829
import 'package:analyzer/dart/analysis/session.dart';
2930
import 'package:analyzer/dart/ast/ast.dart' as ast;
@@ -443,6 +444,8 @@ class CompletionHandler
443444
item,
444445
completionRequest,
445446
);
447+
} else if (item is TypedSuggestion) {
448+
item.data = await createTypedSuggestionData(item, completionRequest);
446449
}
447450
var itemReplacementOffset = completionRequest.replacementOffset;
448451
var itemReplacementLength = completionRequest.replacementLength;
@@ -500,6 +503,22 @@ class CompletionHandler
500503
ref: ElementLocation.forElement(element)?.encoding,
501504
);
502505
}
506+
} else if (item is TypedSuggestion) {
507+
var typedData = item.data;
508+
if (typedData != null && typedData.imports.isNotEmpty) {
509+
var element = item.ifTypeOrNull<ElementBasedSuggestion>()?.element;
510+
ElementLocation? elementLocation;
511+
if (element != null) {
512+
elementLocation = ElementLocation.forElement(element);
513+
}
514+
515+
var importUris = typedData.imports;
516+
resolutionInfo = DartCompletionResolutionInfo(
517+
file: unit.path,
518+
importUris: importUris.map((uri) => uri.toString()).toList(),
519+
ref: elementLocation?.encoding,
520+
);
521+
}
503522
}
504523

505524
return toLspCompletionItem(

0 commit comments

Comments
 (0)