mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 15:42:20 +00:00
Include an empty body when suggesting a name for a top-level declaration that does not have a body
Change-Id: I92875fdb80b0541eaa5505b507e822915181ee52 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/370980 Reviewed-by: Keerti Parthasarathy <keertip@google.com> Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
parent
73cd7c6439
commit
2c97c6949e
|
@ -258,12 +258,25 @@ final class IdentifierSuggestion extends CandidateSuggestion {
|
|||
/// The identifier to be inserted.
|
||||
final String identifier;
|
||||
|
||||
/// Whether an empty body should be included in the completion string.
|
||||
final bool includeBody;
|
||||
|
||||
/// Initialize a newly created candidate suggestion to suggest the
|
||||
/// [identifier].
|
||||
IdentifierSuggestion({required this.identifier, required super.matcherScore});
|
||||
///
|
||||
/// If [includeBody] is `true`, then empty curly braces will be included in
|
||||
/// the suggestion.
|
||||
IdentifierSuggestion(
|
||||
{required this.identifier,
|
||||
required this.includeBody,
|
||||
required super.matcherScore});
|
||||
|
||||
@override
|
||||
String get completion => identifier;
|
||||
String get completion => identifier + (includeBody ? ' {}' : '');
|
||||
|
||||
/// The offset, from the beginning of the inserted text, where the cursor
|
||||
/// should be positioned.
|
||||
int get selectionOffset => identifier.length + (includeBody ? 2 : 0);
|
||||
}
|
||||
|
||||
/// The information about a candidate suggestion based on a declaration that can
|
||||
|
@ -843,7 +856,10 @@ extension SuggestionBuilderExtension on SuggestionBuilder {
|
|||
case FunctionCall():
|
||||
suggestFunctionCall();
|
||||
case IdentifierSuggestion():
|
||||
suggestName(suggestion.identifier);
|
||||
suggestName(
|
||||
suggestion.completion,
|
||||
selectionOffset: suggestion.selectionOffset,
|
||||
);
|
||||
case ImportPrefixSuggestion():
|
||||
suggestPrefix(
|
||||
suggestion.libraryElement,
|
||||
|
|
|
@ -51,7 +51,7 @@ class IdentifierHelper {
|
|||
|
||||
/// Adds any suggestions for the name of a top-level declaration (class, enum,
|
||||
/// mixin, function, etc.).
|
||||
void addTopLevelName() {
|
||||
void addTopLevelName({required bool includeBody}) {
|
||||
var context = state.request.analysisSession.resourceProvider.pathContext;
|
||||
var path = state.request.path;
|
||||
var candidateName = context.basenameWithoutExtension(path).toUpperCamelCase;
|
||||
|
@ -69,7 +69,10 @@ class IdentifierHelper {
|
|||
var matcherScore = state.matcher.score(candidateName);
|
||||
if (matcherScore != -1) {
|
||||
collector.addSuggestion(IdentifierSuggestion(
|
||||
identifier: candidateName, matcherScore: matcherScore));
|
||||
identifier: candidateName,
|
||||
includeBody: includeBody,
|
||||
matcherScore: matcherScore,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,8 +88,11 @@ class IdentifierHelper {
|
|||
if (name.isNotEmpty) {
|
||||
var matcherScore = state.matcher.score(name);
|
||||
if (matcherScore != -1) {
|
||||
collector.addSuggestion(
|
||||
IdentifierSuggestion(identifier: name, matcherScore: matcherScore));
|
||||
collector.addSuggestion(IdentifierSuggestion(
|
||||
identifier: name,
|
||||
includeBody: false,
|
||||
matcherScore: matcherScore,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -618,7 +618,10 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
|
|||
} else if (offset <= node.classKeyword.end) {
|
||||
keywordHelper.addKeyword(Keyword.CLASS);
|
||||
} else if (offset <= node.name.end) {
|
||||
identifierHelper(includePrivateIdentifiers: false).addTopLevelName();
|
||||
var hasSyntheticBody =
|
||||
node.leftBracket.isSynthetic && node.rightBracket.isSynthetic;
|
||||
identifierHelper(includePrivateIdentifiers: false)
|
||||
.addTopLevelName(includeBody: hasSyntheticBody);
|
||||
} else if (offset <= node.leftBracket.offset) {
|
||||
keywordHelper.addClassDeclarationKeywords(node);
|
||||
} else if (offset >= node.leftBracket.end &&
|
||||
|
@ -944,7 +947,10 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
|
|||
return;
|
||||
}
|
||||
if (offset <= node.name.end) {
|
||||
identifierHelper(includePrivateIdentifiers: false).addTopLevelName();
|
||||
var hasSyntheticBody =
|
||||
node.leftBracket.isSynthetic && node.rightBracket.isSynthetic;
|
||||
identifierHelper(includePrivateIdentifiers: false)
|
||||
.addTopLevelName(includeBody: hasSyntheticBody);
|
||||
return;
|
||||
}
|
||||
if (offset <= node.leftBracket.offset) {
|
||||
|
@ -1103,10 +1109,16 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
|
|||
if (featureSet.isEnabled(Feature.inline_class)) {
|
||||
keywordHelper.addText('type');
|
||||
}
|
||||
identifierHelper(includePrivateIdentifiers: false).addTopLevelName();
|
||||
// TODO(brianwilkerson): Consider adding both an `on` keyword and a body
|
||||
// when none of them already exist.
|
||||
identifierHelper(includePrivateIdentifiers: false)
|
||||
.addTopLevelName(includeBody: false);
|
||||
return;
|
||||
} else {
|
||||
identifierHelper(includePrivateIdentifiers: false).addTopLevelName();
|
||||
// TODO(brianwilkerson): Consider adding both an `on` keyword and a body
|
||||
// when none of them already exist.
|
||||
identifierHelper(includePrivateIdentifiers: false)
|
||||
.addTopLevelName(includeBody: false);
|
||||
}
|
||||
if (offset <= node.leftBracket.offset) {
|
||||
collector.completionLocation = 'ExtensionDeclaration_onClause';
|
||||
|
@ -1144,7 +1156,10 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
|
|||
if (offset == node.offset) {
|
||||
_forCompilationUnitMemberBefore(node);
|
||||
} else if (offset <= node.name.end) {
|
||||
identifierHelper(includePrivateIdentifiers: false).addTopLevelName();
|
||||
var hasSyntheticBody =
|
||||
node.leftBracket.isSynthetic && node.rightBracket.isSynthetic;
|
||||
identifierHelper(includePrivateIdentifiers: false)
|
||||
.addTopLevelName(includeBody: hasSyntheticBody);
|
||||
} else if (offset >= node.representation.end &&
|
||||
(offset <= node.leftBracket.offset || node.leftBracket.isSynthetic)) {
|
||||
keywordHelper.addKeyword(Keyword.IMPLEMENTS);
|
||||
|
@ -1838,7 +1853,10 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
|
|||
return;
|
||||
}
|
||||
if (offset <= node.name.end) {
|
||||
identifierHelper(includePrivateIdentifiers: false).addTopLevelName();
|
||||
var hasSyntheticBody =
|
||||
node.leftBracket.isSynthetic && node.rightBracket.isSynthetic;
|
||||
identifierHelper(includePrivateIdentifiers: false)
|
||||
.addTopLevelName(includeBody: hasSyntheticBody);
|
||||
return;
|
||||
}
|
||||
if (offset <= node.leftBracket.offset) {
|
||||
|
|
|
@ -834,11 +834,11 @@ class SuggestionBuilder {
|
|||
}
|
||||
|
||||
/// Add a suggestion to use the [name] at a declaration site.
|
||||
void suggestName(String name) {
|
||||
void suggestName(String name, {int? selectionOffset}) {
|
||||
// TODO(brianwilkerson): Explore whether there are any features of the name
|
||||
// that can be used to provide better relevance scores.
|
||||
_addSuggestion(CompletionSuggestion(CompletionSuggestionKind.IDENTIFIER,
|
||||
500, name, name.length, 0, false, false));
|
||||
500, name, selectionOffset ?? name.length, 0, false, false));
|
||||
}
|
||||
|
||||
/// Add a suggestion to add a named argument corresponding to the [parameter].
|
||||
|
|
|
@ -125,10 +125,11 @@ suggestions
|
|||
''');
|
||||
}
|
||||
|
||||
Future<void> test_name() async {
|
||||
allowedIdentifiers = {'Test'};
|
||||
Future<void> test_name_withBody() async {
|
||||
allowedIdentifiers = {'Test', 'Test {}'};
|
||||
printerConfiguration.withSelection = true;
|
||||
await computeSuggestions('''
|
||||
class ^
|
||||
class ^ {}
|
||||
''');
|
||||
assertResponse(r'''
|
||||
suggestions
|
||||
|
@ -137,6 +138,20 @@ suggestions
|
|||
''');
|
||||
}
|
||||
|
||||
Future<void> test_name_withoutBody() async {
|
||||
allowedIdentifiers = {'Test', 'Test {}'};
|
||||
printerConfiguration.withSelection = true;
|
||||
await computeSuggestions('''
|
||||
class ^
|
||||
''');
|
||||
assertResponse(r'''
|
||||
suggestions
|
||||
Test {}
|
||||
kind: identifier
|
||||
selection: 6
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_noBody() async {
|
||||
await computeSuggestions('''
|
||||
class A ^
|
||||
|
|
|
@ -353,15 +353,30 @@ suggestions
|
|||
''');
|
||||
}
|
||||
|
||||
Future<void> test_name() async {
|
||||
allowedIdentifiers = {'Test'};
|
||||
Future<void> test_name_withBody() async {
|
||||
allowedIdentifiers = {'Test', 'Test {}'};
|
||||
printerConfiguration.withSelection = true;
|
||||
await computeSuggestions('''
|
||||
enum ^
|
||||
enum ^ {}
|
||||
''');
|
||||
assertResponse(r'''
|
||||
suggestions
|
||||
Test
|
||||
kind: identifier
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_name_withoutBody() async {
|
||||
allowedIdentifiers = {'Test', 'Test {}'};
|
||||
printerConfiguration.withSelection = true;
|
||||
await computeSuggestions('''
|
||||
enum ^
|
||||
''');
|
||||
assertResponse(r'''
|
||||
suggestions
|
||||
Test {}
|
||||
kind: identifier
|
||||
selection: 6
|
||||
''');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,24 +54,9 @@ suggestions
|
|||
''');
|
||||
}
|
||||
|
||||
Future<void> test_name() async {
|
||||
allowedIdentifiers = {'Test'};
|
||||
await computeSuggestions('''
|
||||
extension ^
|
||||
''');
|
||||
assertResponse(r'''
|
||||
suggestions
|
||||
Test
|
||||
kind: identifier
|
||||
on
|
||||
kind: keyword
|
||||
type
|
||||
kind: keyword
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_name_partial() async {
|
||||
allowedIdentifiers = {'Test'};
|
||||
allowedIdentifiers = {'Test', 'Test {}'};
|
||||
printerConfiguration.withSelection = true;
|
||||
await computeSuggestions('''
|
||||
extension T^
|
||||
''');
|
||||
|
@ -83,6 +68,40 @@ suggestions
|
|||
kind: identifier
|
||||
type
|
||||
kind: keyword
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_name_withBody() async {
|
||||
allowedIdentifiers = {'Test', 'Test {}'};
|
||||
printerConfiguration.withSelection = true;
|
||||
await computeSuggestions('''
|
||||
extension ^ {}
|
||||
''');
|
||||
assertResponse(r'''
|
||||
suggestions
|
||||
Test
|
||||
kind: identifier
|
||||
on
|
||||
kind: keyword
|
||||
type
|
||||
kind: keyword
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_name_withoutBody() async {
|
||||
allowedIdentifiers = {'Test', 'Test {}'};
|
||||
printerConfiguration.withSelection = true;
|
||||
await computeSuggestions('''
|
||||
extension ^
|
||||
''');
|
||||
assertResponse(r'''
|
||||
suggestions
|
||||
Test
|
||||
kind: identifier
|
||||
on
|
||||
kind: keyword
|
||||
type
|
||||
kind: keyword
|
||||
''');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,10 +122,11 @@ suggestions
|
|||
''');
|
||||
}
|
||||
|
||||
Future<void> test_name() async {
|
||||
allowedIdentifiers = {'Test'};
|
||||
Future<void> test_name_withBody() async {
|
||||
allowedIdentifiers = {'Test', 'Test {}'};
|
||||
printerConfiguration.withSelection = true;
|
||||
await computeSuggestions('''
|
||||
extension type ^
|
||||
extension type ^ {}
|
||||
''');
|
||||
assertResponse(r'''
|
||||
suggestions
|
||||
|
@ -134,6 +135,20 @@ suggestions
|
|||
''');
|
||||
}
|
||||
|
||||
Future<void> test_name_withoutBody() async {
|
||||
allowedIdentifiers = {'Test', 'Test {}'};
|
||||
printerConfiguration.withSelection = true;
|
||||
await computeSuggestions('''
|
||||
extension type ^
|
||||
''');
|
||||
assertResponse(r'''
|
||||
suggestions
|
||||
Test {}
|
||||
kind: identifier
|
||||
selection: 6
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_representationField_annotation() async {
|
||||
await computeSuggestions('''
|
||||
extension type E(@^)
|
||||
|
|
|
@ -43,15 +43,30 @@ suggestions
|
|||
''');
|
||||
}
|
||||
|
||||
Future<void> test_name() async {
|
||||
allowedIdentifiers = {'Test'};
|
||||
Future<void> test_name_withBody() async {
|
||||
allowedIdentifiers = {'Test', 'Test {}'};
|
||||
printerConfiguration.withSelection = true;
|
||||
await computeSuggestions('''
|
||||
mixin ^
|
||||
mixin ^ {}
|
||||
''');
|
||||
assertResponse(r'''
|
||||
suggestions
|
||||
Test
|
||||
kind: identifier
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_name_withoutBody() async {
|
||||
allowedIdentifiers = {'Test', 'Test {}'};
|
||||
printerConfiguration.withSelection = true;
|
||||
await computeSuggestions('''
|
||||
mixin ^
|
||||
''');
|
||||
assertResponse(r'''
|
||||
suggestions
|
||||
Test {}
|
||||
kind: identifier
|
||||
selection: 6
|
||||
''');
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue