[Code completion] Some more refactoring in SuggestionBuilder.
Change-Id: I86a1a1211385589ce1e288db5487cc8073b01746
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/384821
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Keerti Parthasarathy <keertip@google.com>
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/candidate_suggestion.dart b/pkg/analysis_server/lib/src/services/completion/dart/candidate_suggestion.dart
index a2108a2..2870cef 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/candidate_suggestion.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/candidate_suggestion.dart
@@ -325,7 +325,14 @@
required this.referencingInterface});
@override
- String get completion => element.displayName;
+ String get completion {
+ if (element.isEnumConstant) {
+ var constantName = element.name;
+ var enumName = element.enclosingElement3.name;
+ return '$enumName.$constantName';
+ }
+ return element.displayName;
+ }
}
/// The information about a candidate suggestion based on a formal parameter.
@@ -856,6 +863,12 @@
final bool appendColon;
final bool appendComma;
+ late String _completion;
+ late int _selectionOffset;
+
+ // Whether _completion, _displayText, and _selectionOffset have been initialized.
+ bool _initialized = false;
+
RecordLiteralNamedFieldSuggestion.newField({
required this.field,
required this.appendComma,
@@ -869,7 +882,36 @@
appendComma = false;
@override
- String get completion => field.name;
+ String get completion {
+ _init();
+ return _completion;
+ }
+
+ /// The offset, from the beginning of the inserted text, where the cursor
+ /// should be positioned.
+ int get selectionOffset {
+ _init();
+ return _selectionOffset;
+ }
+
+ void _init() {
+ if (_initialized) {
+ return;
+ }
+ var name = field.name;
+
+ var completion = name;
+ if (appendColon) {
+ completion += ': ';
+ }
+ _selectionOffset = completion.length;
+
+ if (appendComma) {
+ completion += ',';
+ }
+ _completion = completion;
+ _initialized = true;
+ }
}
/// The information about a candidate suggestion for Flutter's `setState` method.
@@ -1048,7 +1090,7 @@
required super.matcherScore});
@override
- String get completion => '$completionPrefix${element.name}';
+ String get completion => '$completionPrefix${element.displayName}';
}
/// The information about a candidate suggestion based on a type parameter.
@@ -1136,8 +1178,8 @@
prefix: suggestion.prefix, relevance: relevance);
case EnumConstantSuggestion():
if (suggestion.includeEnumName) {
- suggestEnumConstant(suggestion.element,
- prefix: suggestion.prefix, relevance: relevance);
+ suggestEnumConstant(suggestion.element, suggestion.completion,
+ relevance: relevance);
} else {
suggestField(suggestion.element,
inheritanceDistance: 0.0, relevance: relevance);
@@ -1151,7 +1193,8 @@
case FieldSuggestion():
var fieldElement = suggestion.element;
if (fieldElement.isEnumConstant) {
- suggestEnumConstant(fieldElement, relevance: relevance);
+ suggestEnumConstant(fieldElement, suggestion.completion,
+ relevance: relevance);
} else {
var inheritanceDistance =
suggestion.inheritanceDistance(request.featureComputer);
@@ -1266,7 +1309,9 @@
);
case StaticFieldSuggestion():
suggestStaticField(suggestion.element,
- prefix: suggestion.prefix, relevance: relevance);
+ prefix: suggestion.prefix,
+ relevance: relevance,
+ completion: suggestion.completion);
case SuperParameterSuggestion():
suggestSuperFormalParameter(suggestion.element);
case TopLevelFunctionSuggestion():
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/declaration_helper.dart b/pkg/analysis_server/lib/src/services/completion/dart/declaration_helper.dart
index c8ab9c5..2b41367 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/declaration_helper.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/declaration_helper.dart
@@ -882,8 +882,8 @@
matcherScore: matcherScore),
MixinElement() => MixinSuggestion(
importData: null, element: element, matcherScore: matcherScore),
- PropertyAccessorElement() => TopLevelPropertyAccessSuggestion(
- importData: null, element: element, matcherScore: matcherScore),
+ PropertyAccessorElement() =>
+ _createSuggestionFromTopLevelProperty(element, matcherScore),
TopLevelVariableElement() => TopLevelVariableSuggestion(
importData: null, element: element, matcherScore: matcherScore),
TypeAliasElement() => TypeAliasSuggestion(
@@ -1419,6 +1419,26 @@
return true;
}
+ ImportableSuggestion? _createSuggestionFromTopLevelProperty(
+ PropertyAccessorElement element, double matcherScore,
+ {ImportData? importData}) {
+ if (element.isSynthetic) {
+ if (element.isGetter) {
+ var variable = element.variable2;
+ if (variable is TopLevelVariableElement) {
+ return TopLevelVariableSuggestion(
+ importData: importData,
+ element: variable,
+ matcherScore: matcherScore);
+ }
+ }
+ } else {
+ return TopLevelPropertyAccessSuggestion(
+ importData: importData, element: element, matcherScore: matcherScore);
+ }
+ return null;
+ }
+
/// Returns `true` if the [identifier] is a wildcard (a single `_`).
bool _isWildcard(String? identifier) => identifier == '_';
@@ -1938,11 +1958,12 @@
}
var matcherScore = state.matcher.score(element.displayName);
if (matcherScore != -1) {
- var suggestion = TopLevelPropertyAccessSuggestion(
- importData: importData,
- element: element,
- matcherScore: matcherScore);
- collector.addSuggestion(suggestion);
+ var suggestion = _createSuggestionFromTopLevelProperty(
+ element, matcherScore,
+ importData: importData);
+ if (suggestion != null) {
+ collector.addSuggestion(suggestion);
+ }
}
}
}
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
index f923c6f..ff4d934 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
@@ -273,12 +273,8 @@
/// Add a suggestion for an enum [constant]. If the enum can only be
/// referenced using a prefix, then the [prefix] should be provided.
- void suggestEnumConstant(FieldElement constant,
+ void suggestEnumConstant(FieldElement constant, String completion,
{String? prefix, int? relevance}) {
- var constantName = constant.name;
- var enumElement = constant.enclosingElement3;
- var enumName = enumElement.name;
- var completion = '$enumName.$constantName';
relevance ??= relevanceComputer.computeTopLevelRelevance(constant,
elementType: constant.type, isNotImportedLibrary: isNotImportedLibrary);
_addBuilder(
@@ -615,20 +611,20 @@
void suggestNamedRecordField(RecordTypeNamedField field,
{required bool appendColon,
required bool appendComma,
- int? replacementLength}) {
- var name = field.name;
- var type = field.type.getDisplayString();
+ int? replacementLength,
+ String? completion,
+ int? selectionOffset}) {
+ if (completion == null || selectionOffset == null) {
+ completion = field.name;
+ if (appendColon) {
+ completion += ': ';
+ }
+ selectionOffset = completion.length;
- var completion = name;
- if (appendColon) {
- completion += ': ';
+ if (appendComma) {
+ completion += ',';
+ }
}
- var selectionOffset = completion.length;
-
- if (appendComma) {
- completion += ',';
- }
-
_addSuggestion(
CompletionSuggestion(
CompletionSuggestionKind.NAMED_ARGUMENT,
@@ -638,8 +634,8 @@
0,
false,
false,
- parameterName: name,
- parameterType: type,
+ parameterName: field.name,
+ parameterType: field.type.getDisplayString(),
replacementLength: replacementLength,
),
);
@@ -806,14 +802,14 @@
/// If the enclosing element can only be referenced using a prefix, then
/// the [prefix] should be provided.
void suggestStaticField(FieldElement element,
- {String? prefix, int? relevance}) {
+ {String? prefix, int? relevance, String? completion}) {
assert(element.isStatic);
var enclosingPrefix = '';
var enclosingName = _enclosingClassOrExtensionName(element);
if (enclosingName != null) {
enclosingPrefix = '$enclosingName.';
}
- var completion = enclosingPrefix + element.name;
+ completion ??= enclosingPrefix + element.name;
if (_couldMatch(completion, prefix)) {
relevance ??= relevanceComputer.computeTopLevelRelevance(element,
elementType: element.type,
@@ -876,52 +872,39 @@
accessor.enclosingElement3 is CompilationUnitElement,
'Enclosing element of ${accessor.runtimeType} is '
'${accessor.enclosingElement3.runtimeType}.');
- if (accessor.isSynthetic) {
- // Avoid visiting a field twice. All fields induce a getter, but only
- // non-final fields induce a setter, so we don't add a suggestion for a
- // synthetic setter.
- if (accessor.isGetter) {
- var variable = accessor.variable2;
- if (variable is TopLevelVariableElement) {
- suggestTopLevelVariable(variable);
- }
- }
- } else {
- var completion = _getCompletionString(accessor);
- if (completion == null) return;
- if (_couldMatch(completion, prefix)) {
- var type = _getPropertyAccessorType(accessor);
- var featureComputer = request.featureComputer;
- var contextType =
- featureComputer.contextTypeFeature(request.contextType, type);
- var elementKind = _computeElementKind(accessor);
- var hasDeprecated = featureComputer.hasDeprecatedFeature(accessor);
- var isConstant = _preferConstants
- ? featureComputer.isConstantFeature(accessor)
- : 0.0;
- var startsWithDollar =
- featureComputer.startsWithDollarFeature(accessor.name);
- var superMatches = 0.0;
- relevance ??= relevanceComputer.computeScore(
- contextType: contextType,
- elementKind: elementKind,
- hasDeprecated: hasDeprecated,
- isConstant: isConstant,
- isNotImported: request.featureComputer
- .isNotImportedFeature(isNotImportedLibrary),
- startsWithDollar: startsWithDollar,
- superMatches: superMatches,
- );
- _addBuilder(
- _createCompletionSuggestionBuilder(
- accessor,
- kind: CompletionSuggestionKind.IDENTIFIER,
- prefix: prefix,
- relevance: relevance,
- isNotImported: isNotImportedLibrary,
- ),
- );
- }
+ var completion = _getCompletionString(accessor);
+ if (completion == null) return;
+ if (_couldMatch(completion, prefix)) {
+ var type = _getPropertyAccessorType(accessor);
+ var featureComputer = request.featureComputer;
+ var contextType =
+ featureComputer.contextTypeFeature(request.contextType, type);
+ var elementKind = _computeElementKind(accessor);
+ var hasDeprecated = featureComputer.hasDeprecatedFeature(accessor);
+ var isConstant =
+ _preferConstants ? featureComputer.isConstantFeature(accessor) : 0.0;
+ var startsWithDollar =
+ featureComputer.startsWithDollarFeature(accessor.name);
+ var superMatches = 0.0;
+ relevance ??= relevanceComputer.computeScore(
+ contextType: contextType,
+ elementKind: elementKind,
+ hasDeprecated: hasDeprecated,
+ isConstant: isConstant,
+ isNotImported:
+ request.featureComputer.isNotImportedFeature(isNotImportedLibrary),
+ startsWithDollar: startsWithDollar,
+ superMatches: superMatches,
+ );
+ _addBuilder(
+ _createCompletionSuggestionBuilder(
+ accessor,
+ kind: CompletionSuggestionKind.IDENTIFIER,
+ prefix: prefix,
+ relevance: relevance,
+ isNotImported: isNotImportedLibrary,
+ ),
+ );
}
}