[analysis_server] Don't fail on invalid/complex setters in LSP code completion
Fixes https://github.com/dart-lang/sdk/issues/52050. Change-Id: I6cf5420d5e017b501481cb436a7d1b17f46c0e44 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/295542 Commit-Queue: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
committed by
Commit Queue
parent
a565638b91
commit
453647022f
@@ -50,6 +50,10 @@ final diagnosticTagsForErrorCode = <String, List<lsp.DiagnosticTag>>{
|
||||
],
|
||||
};
|
||||
|
||||
/// A regex to extract the type name from the parameter string of a setter
|
||||
/// completion item.
|
||||
final _completionSetterTypePattern = RegExp(r'^\((\S+)\s+\S+\)$');
|
||||
|
||||
/// Pattern for docComplete text on completion items that can be upgraded to
|
||||
/// the "detail" field so that it can be shown more prominently by clients.
|
||||
///
|
||||
@@ -396,15 +400,17 @@ String? getCompletionDetail(
|
||||
// appear in the completion list, so displaying them as setters is misleading.
|
||||
// To avoid this, always show only the return type, whether it's a getter
|
||||
// or a setter.
|
||||
return prefix +
|
||||
(element?.kind == server.ElementKind.GETTER
|
||||
? (returnType ?? '')
|
||||
// Don't assume setters always have parameters
|
||||
// See https://github.com/dart-lang/sdk/issues/27747
|
||||
: parameters != null && parameters.isNotEmpty
|
||||
// Extract the type part from '(MyType value)`
|
||||
? parameters.substring(1, parameters.lastIndexOf(' '))
|
||||
: '');
|
||||
if (element?.kind == server.ElementKind.GETTER) {
|
||||
return prefix + (returnType ?? '');
|
||||
} else if (parameters == null) {
|
||||
return prefix;
|
||||
} else {
|
||||
// TODO(dantup): Consider having the type of a setter available on
|
||||
// CompletionSuggestion (or changing it to a protocol-agnostic class that
|
||||
// includes it).
|
||||
return prefix +
|
||||
(_completionSetterTypePattern.firstMatch(parameters)?.group(1) ?? '');
|
||||
}
|
||||
} else if (hasParameters && hasReturnType) {
|
||||
return '$prefix$parameters → $returnType';
|
||||
} else if (hasReturnType) {
|
||||
|
||||
@@ -1345,9 +1345,9 @@ void f() {
|
||||
final content = '''
|
||||
class MyClass {
|
||||
String get justGetter => '';
|
||||
String set justSetter(String value) {}
|
||||
set justSetter(String value) {}
|
||||
String get getterAndSetter => '';
|
||||
String set getterAndSetter(String value) {}
|
||||
set getterAndSetter(String value) {}
|
||||
}
|
||||
|
||||
void f() {
|
||||
@@ -2210,6 +2210,41 @@ void f() { }
|
||||
expect(res.any((c) => c.label == 'UniqueNamedClassForLspThree'), isTrue);
|
||||
}
|
||||
|
||||
Future<void> test_setters() async {
|
||||
final content = '''
|
||||
class MyClass {
|
||||
set stringSetter(String a) {}
|
||||
set noArgSetter() {}
|
||||
set multiArgSetter(a, b) {}
|
||||
set functionSetter(String Function(int a, int b) foo) {}
|
||||
}
|
||||
|
||||
void f() {
|
||||
MyClass a;
|
||||
a.^
|
||||
}
|
||||
''';
|
||||
|
||||
await initialize();
|
||||
await openFile(mainFileUri, withoutMarkers(content));
|
||||
final res = await getCompletion(mainFileUri, positionFromMarker(content));
|
||||
final setters = res
|
||||
.where((c) => c.label.endsWith('Setter'))
|
||||
.map((c) => '${c.label} (${c.detail})')
|
||||
.toList();
|
||||
expect(
|
||||
setters,
|
||||
[
|
||||
'stringSetter (String)',
|
||||
'noArgSetter ()',
|
||||
'multiArgSetter ()',
|
||||
// Because of how we extract the type name, we don't currently support
|
||||
// this.
|
||||
'functionSetter ()',
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> test_unimportedSymbols() async {
|
||||
newFile(
|
||||
join(projectFolderPath, 'other_file.dart'),
|
||||
|
||||
Reference in New Issue
Block a user