Fix override suggestions with protocol2, a few tests.

Change-Id: I0f49c01d68abdf695cc08a466495f7754c6eb91f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/244363
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Konstantin Shcheglov 2022-05-11 16:02:34 +00:00 committed by Commit Bot
parent cae2f4e874
commit 85615ce2e8
6 changed files with 147 additions and 7 deletions

View file

@ -17,7 +17,7 @@ List<CompletionSuggestionBuilder> fuzzyFilterSort({
var matcher = FuzzyMatcher(pattern, matchStyle: MatchStyle.SYMBOL);
double score(CompletionSuggestionBuilder suggestion) {
var textToMatch = suggestion.completion;
var textToMatch = suggestion.textToMatch;
if (suggestion.kind == CompletionSuggestionKind.KEYWORD ||
suggestion.kind == CompletionSuggestionKind.NAMED_ARGUMENT) {

View file

@ -41,6 +41,9 @@ abstract class CompletionSuggestionBuilder {
/// See [CompletionSuggestion.relevance].
int get relevance;
/// Return the text that should be matched against the filter.
String get textToMatch;
CompletionSuggestion build();
}
@ -81,6 +84,9 @@ class CompletionSuggestionBuilderImpl implements CompletionSuggestionBuilder {
return key;
}
@override
String get textToMatch => completion;
@override
CompletionSuggestion build() {
return CompletionSuggestion(
@ -966,7 +972,10 @@ class SuggestionBuilder {
displayText: displayText);
suggestion.element = protocol.convertElement(element,
withNullability: _isNonNullableByDefault);
_addSuggestion(suggestion);
_addSuggestion(
suggestion,
textToMatchOverride: element.displayName,
);
}
/// Add a suggestion for a [parameter].
@ -1177,9 +1186,15 @@ class SuggestionBuilder {
/// Add the given [suggestion] if it isn't shadowed by a previously added
/// suggestion.
void _addSuggestion(protocol.CompletionSuggestion suggestion) {
void _addSuggestion(
protocol.CompletionSuggestion suggestion, {
String? textToMatchOverride,
}) {
_addBuilder(
ValueCompletionSuggestionBuilder(suggestion),
ValueCompletionSuggestionBuilder(
suggestion,
textToMatchOverride: textToMatchOverride,
),
);
}
@ -1523,8 +1538,12 @@ abstract class SuggestionListener {
/// [CompletionSuggestionBuilder] that is based on a [CompletionSuggestion].
class ValueCompletionSuggestionBuilder implements CompletionSuggestionBuilder {
final CompletionSuggestion _suggestion;
final String? _textToMatchOverride;
ValueCompletionSuggestionBuilder(this._suggestion);
ValueCompletionSuggestionBuilder(
this._suggestion, {
String? textToMatchOverride,
}) : _textToMatchOverride = textToMatchOverride;
@override
String get completion => _suggestion.completion;
@ -1538,6 +1557,9 @@ class ValueCompletionSuggestionBuilder implements CompletionSuggestionBuilder {
@override
int get relevance => _suggestion.relevance;
@override
String get textToMatch => _textToMatchOverride ?? completion;
@override
CompletionSuggestion build() {
return _suggestion;

View file

@ -153,6 +153,14 @@ extension CompletionSuggestionExtension
);
}
@useResult
CheckTarget<String?> get displayText {
return nest(
value.suggestion.displayText,
(selected) => 'has displayText ${valueStr(selected)}',
);
}
@useResult
CheckTarget<String?> get docComplete {
return nest(
@ -401,6 +409,18 @@ extension CompletionSuggestionsExtension
);
}
@useResult
CheckTarget<Iterable<CompletionSuggestionForTesting>> get overrides {
var result = value
.where((suggestion) =>
suggestion.suggestion.kind == CompletionSuggestionKind.OVERRIDE)
.toList();
return nest(
result,
(selected) => 'overrides ${valueStr(selected)}',
);
}
@useResult
CheckTarget<Iterable<CompletionSuggestionForTesting>> get withElementClass {
return nest(

View file

@ -18,14 +18,14 @@ void main() {
@reflectiveTest
class ClassBodyTest1 extends AbstractCompletionDriverTest
with ClassBodyTestCases {
with ClassBodyTestCases, OverrideTestCases {
@override
TestingCompletionProtocol get protocol => TestingCompletionProtocol.version1;
}
@reflectiveTest
class ClassBodyTest2 extends AbstractCompletionDriverTest
with ClassBodyTestCases {
with ClassBodyTestCases, OverrideTestCases {
@override
TestingCompletionProtocol get protocol => TestingCompletionProtocol.version2;
}
@ -311,6 +311,79 @@ mixin M {
}
}
mixin OverrideTestCases on AbstractCompletionDriverTest {
Future<void> test_class_method_fromExtends() async {
final response = await getTestCodeSuggestions('''
class A {
void foo01() {}
}
class B extends A {
foo^
}
''');
check(response).suggestions.overrides.includesAll([
(suggestion) => suggestion
..displayText.isEqualTo('foo01() { … }')
..hasSelection(offset: 60, length: 14)
..completion.isEqualTo(r'''
@override
void foo01() {
// TODO: implement foo01
super.foo01();
}'''),
]);
}
Future<void> test_class_method_fromImplements() async {
final response = await getTestCodeSuggestions('''
class A {
void foo01() {}
}
class B implements A {
foo^
}
''');
check(response).suggestions.overrides.includesAll([
(suggestion) => suggestion
..displayText.isEqualTo('foo01() { … }')
..hasSelection(offset: 55)
..completion.isEqualTo(r'''
@override
void foo01() {
// TODO: implement foo01
}'''),
]);
}
Future<void> test_class_method_fromWith() async {
final response = await getTestCodeSuggestions('''
mixin M {
void foo01() {}
}
class A with M {
foo^
}
''');
check(response).suggestions.overrides.includesAll([
(suggestion) => suggestion
..displayText.isEqualTo('foo01() { … }')
..hasSelection(offset: 60, length: 14)
..completion.isEqualTo(r'''
@override
void foo01() {
// TODO: implement foo01
super.foo01();
}'''),
]);
}
}
class _Context {
final bool isClass;
final bool isMixin;

View file

@ -977,6 +977,15 @@ class LibraryAnalyzer {
// We have a contributor that looks at the type, but it is syntactic.
if (parent is VariableDeclaration && parent.name == node) {
final parent2 = parent.parent;
final parent3 = parent2?.parent;
// `class A { foo^ }` looks like `class A { <noType> foo; }`.
if (parent2 is VariableDeclarationList &&
parent2.type == null &&
parent3 is FieldDeclaration &&
parent3.semicolon.isSynthetic) {
return false;
}
return true;
}
}

View file

@ -130,6 +130,22 @@ class A with foo^ {}
result.assertResolvedNodes([]);
}
test_classDeclaration_body_identifier() async {
var result = await _resolveTestCode(r'''
class A {}
class B {
void foo() {}
bar^
}
''');
result.assertResolvedNodes([
'bar;',
]);
}
test_constructorDeclaration_body() async {
var result = await _resolveTestCode(r'''
class A {}