[Code completion] Move logic from SuggestionBuilder to NamedArgumentSuggestion.
Change-Id: I1e6d1a75ecb37c8dd7ee65414d880431347053a2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/384302
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 83cc29a..a2108a2 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,7 @@
required this.referencingInterface});
@override
- String get completion => element.name;
+ String get completion => element.displayName;
}
/// The information about a candidate suggestion based on a formal parameter.
@@ -661,16 +661,73 @@
/// doesn't need to be overridden.
final int? replacementLength;
- NamedArgumentSuggestion(
- {required this.parameter,
- required this.appendColon,
- required this.appendComma,
- this.replacementLength,
- required super.matcherScore});
+ final bool isWidget;
+
+ String preferredQuoteForStrings;
+
+ late String _completion;
+
+ // Indicates whether _completion and _selectionOffset have been initialized.
+ bool _initialized = false;
+
+ late int _selectionOffset;
+
+ NamedArgumentSuggestion({
+ required this.parameter,
+ required this.appendColon,
+ required this.appendComma,
+ this.replacementLength,
+ required super.matcherScore,
+ required this.preferredQuoteForStrings,
+ this.isWidget = false,
+ });
@override
- String get completion =>
- '${parameter.name}${appendColon ? ': ' : ''}${appendComma ? ',' : ''}';
+ 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 completion = parameter.name;
+ if (appendColon) {
+ completion += ': ';
+ }
+ var selectionOffset = completion.length;
+
+ // Optionally add Flutter child widget details.
+ // TODO(pq): revisit this special casing; likely it can be generalized away.
+ if (isWidget && appendColon) {
+ var defaultValue =
+ getDefaultStringParameterValue(parameter, preferredQuoteForStrings);
+ // TODO(devoncarew): Should we remove the check here? We would then
+ // suggest values for param types like closures.
+ if (defaultValue != null && defaultValue.text == '[]') {
+ var completionLength = completion.length;
+ completion += defaultValue.text;
+ var cursorPosition = defaultValue.cursorPosition;
+ if (cursorPosition != null) {
+ selectionOffset = completionLength + cursorPosition;
+ }
+ }
+ }
+ if (appendComma) {
+ completion += ',';
+ }
+ _completion = completion;
+ _selectionOffset = selectionOffset;
+ _initialized = true;
+ }
}
/// The information about a candidate suggestion based on a getter or setter.
@@ -1163,6 +1220,8 @@
appendColon: suggestion.appendColon,
appendComma: suggestion.appendComma,
replacementLength: suggestion.replacementLength,
+ completion: suggestion.completion,
+ selectionOffset: suggestion.selectionOffset,
relevance: relevance);
case NameSuggestion():
suggestName(suggestion.name);
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/completion_state.dart b/pkg/analysis_server/lib/src/services/completion/dart/completion_state.dart
index 11e8d7d..c39a66a 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/completion_state.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/completion_state.dart
@@ -5,6 +5,7 @@
import 'package:analysis_server/src/services/completion/dart/completion_manager.dart';
import 'package:analysis_server/src/services/completion/dart/utilities.dart';
import 'package:analysis_server_plugin/src/utilities/selection.dart';
+import 'package:analyzer/dart/analysis/code_style_options.dart';
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
@@ -59,6 +60,10 @@
/// The element of the library containing the completion location.
LibraryElement get libraryElement => request.libraryElement;
+ /// The type of quotes preferred for [String]s as specified in [CodeStyleOptions].
+ String get preferredQuoteForStrings => request
+ .fileState.analysisOptions.codeStyleOptions.preferredQuoteForStrings;
+
/// The type of `this` at the completion location, or `null` if the completion
/// location doesn't allow `this` to be used.
DartType? get thisType {
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/in_scope_completion_pass.dart b/pkg/analysis_server/lib/src/services/completion/dart/in_scope_completion_pass.dart
index 214da2c..fbd72ff 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/in_scope_completion_pass.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/in_scope_completion_pass.dart
@@ -12,6 +12,7 @@
import 'package:analysis_server/src/services/completion/dart/override_helper.dart';
import 'package:analysis_server/src/services/completion/dart/suggestion_collector.dart';
import 'package:analysis_server/src/services/completion/dart/uri_helper.dart';
+import 'package:analysis_server/src/services/completion/dart/utilities.dart';
import 'package:analysis_server/src/services/completion/dart/visibility_tracker.dart';
import 'package:analysis_server/src/utilities/extensions/ast.dart';
import 'package:analysis_server/src/utilities/extensions/completion_request.dart';
@@ -368,12 +369,15 @@
for (var parameter in availableNamedParameters) {
var matcherScore = state.matcher.score(parameter.displayName);
if (matcherScore != -1) {
+ var isWidget = isFlutterWidgetParameter(parameter);
collector.addSuggestion(NamedArgumentSuggestion(
parameter: parameter,
appendColon: true,
appendComma: appendComma,
replacementLength: replacementLength,
matcherScore: matcherScore,
+ preferredQuoteForStrings: state.preferredQuoteForStrings,
+ isWidget: isWidget,
));
}
}
@@ -1972,11 +1976,15 @@
if (!usedNames.contains(parameter.name)) {
var matcherScore = state.matcher.score(parameter.displayName);
if (matcherScore != -1) {
+ var isWidget = isFlutterWidgetParameter(parameter);
collector.addSuggestion(NamedArgumentSuggestion(
parameter: parameter,
matcherScore: matcherScore,
appendColon: appendColon,
- appendComma: false));
+ appendComma: false,
+ isWidget: isWidget,
+ preferredQuoteForStrings:
+ state.preferredQuoteForStrings));
}
}
}
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 9923365..f923c6f 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
@@ -14,7 +14,6 @@
import 'package:analysis_server/src/services/completion/dart/utilities.dart';
import 'package:analysis_server/src/utilities/extensions/ast.dart';
import 'package:analysis_server/src/utilities/extensions/element.dart';
-import 'package:analysis_server/src/utilities/extensions/flutter.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/nullability_suffix.dart';
@@ -581,52 +580,13 @@
void suggestNamedArgument(ParameterElement parameter,
{required bool appendColon,
required bool appendComma,
+ required int selectionOffset,
+ required String completion,
int? replacementLength,
- int? relevance}) {
+ required int relevance}) {
var name = parameter.name;
var type = parameter.type.getDisplayString();
- var completion = name;
- if (appendColon) {
- completion += ': ';
- }
- var selectionOffset = completion.length;
-
- // Optionally add Flutter child widget details.
- // TODO(pq): revisit this special casing; likely it can be generalized away.
- var element = parameter.enclosingElement3;
- // If `appendColon` is false, default values should never be appended.
- if (element is ConstructorElement && appendColon) {
- if (element.enclosingElement3.augmented.declaration.isWidget) {
- var analysisOptions = request.analysisSession.analysisContext
- .getAnalysisOptionsForFile(
- request.resourceProvider.getFile(request.path));
- var codeStyleOptions = analysisOptions.codeStyleOptions;
- // Don't bother with nullability. It won't affect default list values.
- var defaultValue =
- getDefaultStringParameterValue(parameter, codeStyleOptions);
- // TODO(devoncarew): Should we remove the check here? We would then
- // suggest values for param types like closures.
- if (defaultValue != null && defaultValue.text == '[]') {
- var completionLength = completion.length;
- completion += defaultValue.text;
- var cursorPosition = defaultValue.cursorPosition;
- if (cursorPosition != null) {
- selectionOffset = completionLength + cursorPosition;
- }
- }
- }
- }
-
- if (appendComma) {
- completion += ',';
- }
-
- relevance ??= Relevance.namedArgument;
- if (parameter.isRequiredNamed || parameter.hasRequired) {
- relevance = Relevance.requiredNamedArgument;
- }
-
var suggestion = DartCompletionSuggestion(
CompletionSuggestionKind.NAMED_ARGUMENT,
relevance,
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart b/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart
index 6deb00c..a97c531 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart
@@ -9,7 +9,7 @@
import 'package:analysis_server/src/services/completion/dart/completion_manager.dart';
import 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart';
import 'package:analysis_server/src/utilities/extensions/ast.dart';
-import 'package:analyzer/dart/analysis/code_style_options.dart';
+import 'package:analysis_server/src/utilities/extensions/flutter.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/nullability_suffix.dart';
@@ -150,7 +150,7 @@
/// Return a default argument value for the given [parameter].
DefaultArgument? getDefaultStringParameterValue(
- ParameterElement parameter, CodeStyleOptions codeStyleOptions) {
+ ParameterElement parameter, String quote) {
var type = parameter.type;
if (type is InterfaceType) {
if (type.isDartCoreList) {
@@ -158,7 +158,6 @@
} else if (type.isDartCoreMap) {
return DefaultArgument('{}', cursorPosition: 1);
} else if (type.isDartCoreString) {
- var quote = codeStyleOptions.preferredQuoteForStrings;
return DefaultArgument('$quote$quote', cursorPosition: 1);
}
} else if (type is FunctionType) {
@@ -210,6 +209,17 @@
);
}
+/// Returns true if the [parameter] is part of a constructor for a Flutter
+/// [Widget].
+bool isFlutterWidgetParameter(ParameterElement parameter) {
+ var element = parameter.enclosingElement3;
+ if (element is ConstructorElement &&
+ element.enclosingElement3.augmented.declaration.isWidget) {
+ return true;
+ }
+ return false;
+}
+
/// Return name of the type of the given [identifier], or, if it unresolved, the
/// name of its declared [declaredType].
String? nameForType(SimpleIdentifier identifier, TypeAnnotation? declaredType) {
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_missing_required_argument.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_missing_required_argument.dart
index d229d50..d6e3c80 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_missing_required_argument.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_missing_required_argument.dart
@@ -94,8 +94,8 @@
}
var codeStyleOptions = getCodeStyleOptions(unitResult.file);
- var defaultValue =
- getDefaultStringParameterValue(missingParameter, codeStyleOptions);
+ var defaultValue = getDefaultStringParameterValue(
+ missingParameter, codeStyleOptions.preferredQuoteForStrings);
await builder.addDartFileEdit(file, (builder) {
builder.addInsertion(offset, (builder) {