[Code completion] Add a SetStateMethodSuggestion for completions of the setState method.
Change-Id: I86a0955d45a7d62b3063c9683c883c47fe5a88dd
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/380964
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 73e7285..d2813ed 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
@@ -763,6 +763,75 @@
String get completion => field.name;
}
+/// The information about a candidate suggestion for Flutter's `setState` method.
+final class SetStateMethodSuggestion extends ExecutableSuggestion
+ with MemberSuggestion {
+ @override
+ final MethodElement element;
+
+ late String _completion;
+
+ /// The element defined by the declaration in which the suggestion is to be
+ /// applied, or `null` if the completion is in a static context.
+ @override
+ final InterfaceElement? referencingInterface;
+
+ /// The identation to be used for a multi-line completion.
+ final String indent;
+
+ // Indicates whether _completion, _displayText, and _selectionOffset have been initialized.
+ bool _initialized = false;
+
+ late int _selectionOffset;
+
+ late String _displayText;
+
+ /// Initialize a newly created candidate suggestion to suggest the [element].
+ SetStateMethodSuggestion(
+ {required this.element,
+ required super.importData,
+ required this.referencingInterface,
+ required super.matcherScore,
+ required this.indent,
+ super.kind = CompletionSuggestionKind.INVOCATION});
+
+ @override
+ String get completion {
+ _init();
+ return _completion;
+ }
+
+ /// Text to be displayed in a completion pop-up.
+ String get displayText {
+ _init();
+ return _displayText;
+ }
+
+ /// 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;
+ }
+ // Build the completion and the selection offset.
+ var buffer = StringBuffer();
+ buffer.writeln('setState(() {');
+ buffer.write('$indent ');
+ _selectionOffset = buffer.length;
+ buffer.writeln();
+ buffer.write('$indent});');
+ _completion = buffer.toString();
+ _displayText = 'setState(() {});';
+
+ _initialized = true;
+ }
+}
+
/// The information about a candidate suggestion based on a static field in a
/// location where the name of the field must be qualified by the name of the
/// enclosing element.
@@ -1066,6 +1135,18 @@
appendColon: suggestion.appendColon,
appendComma: suggestion.appendComma,
);
+ case SetStateMethodSuggestion():
+ var inheritanceDistance =
+ suggestion.inheritanceDistance(request.featureComputer);
+ suggestSetStateMethod(
+ suggestion.element,
+ kind: suggestion.kind,
+ completion: suggestion.completion,
+ displayText: suggestion.displayText,
+ selectionOffset: suggestion.selectionOffset,
+ inheritanceDistance: inheritanceDistance,
+ relevance: relevance,
+ );
case StaticFieldSuggestion():
suggestStaticField(suggestion.element,
prefix: suggestion.prefix, relevance: relevance);
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 7394dce..517c209 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
@@ -10,6 +10,7 @@
import 'package:analysis_server/src/services/completion/dart/not_imported_completion_pass.dart';
import 'package:analysis_server/src/services/completion/dart/suggestion_collector.dart';
import 'package:analysis_server/src/services/completion/dart/visibility_tracker.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/type.dart';
@@ -1662,6 +1663,19 @@
}
var matcherScore = state.matcher.score(method.displayName);
if (matcherScore != -1) {
+ var enclosingElement = method.enclosingElement;
+ if (method.name == 'setState' &&
+ enclosingElement is ClassElement &&
+ enclosingElement.isExactState) {
+ var suggestion = SetStateMethodSuggestion(
+ element: method,
+ importData: importData,
+ referencingInterface: referencingInterface,
+ matcherScore: matcherScore,
+ indent: state.indent);
+ collector.addSuggestion(suggestion);
+ return;
+ }
var suggestion = MethodSuggestion(
kind: _executableSuggestionKind,
element: method,
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/relevance_computer.dart b/pkg/analysis_server/lib/src/services/completion/dart/relevance_computer.dart
index 74185b9..0f74ba0 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/relevance_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/relevance_computer.dart
@@ -191,6 +191,12 @@
);
case RecordLiteralNamedFieldSuggestion():
return Relevance.requiredNamedArgument;
+ case SetStateMethodSuggestion():
+ return _computeMethodRelevance(
+ suggestion.element,
+ suggestion.inheritanceDistance(featureComputer),
+ suggestion.isNotImported,
+ );
case StaticFieldSuggestion():
return _computeStaticFieldRelevance(
suggestion.element,
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 0371d94..53b3508 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
@@ -744,41 +744,6 @@
inheritanceDistance: inheritanceDistance,
);
- var enclosingElement = method.enclosingElement;
- if (method.name == 'setState' &&
- enclosingElement is ClassElement &&
- enclosingElement.isExactState) {
- // TODO(brianwilkerson): Make this more efficient by creating the correct
- // suggestion in the first place.
- // Find the line indentation.
- var indent = getRequestLineIndent(request);
-
- // Build the completion and the selection offset.
- var buffer = StringBuffer();
- buffer.writeln('setState(() {');
- buffer.write('$indent ');
- var selectionOffset = buffer.length;
- buffer.writeln();
- buffer.write('$indent});');
-
- _addSuggestion(
- DartCompletionSuggestion(
- kind,
- relevance,
- buffer.toString(),
- selectionOffset,
- 0,
- false,
- false,
- // Let the user know that we are going to insert a complete statement.
- displayText: 'setState(() {});',
- elementLocation: method.location,
- ),
- textToMatchOverride: 'setState',
- );
- return;
- }
-
_addBuilder(
_createCompletionSuggestionBuilder(
method,
@@ -1038,6 +1003,31 @@
);
}
+ /// Add a suggestion for the Flutter's `setState` method.
+ void suggestSetStateMethod(MethodElement method,
+ {required CompletionSuggestionKind kind,
+ required String completion,
+ required String displayText,
+ required int selectionOffset,
+ required double inheritanceDistance,
+ required int relevance}) {
+ _addSuggestion(
+ DartCompletionSuggestion(
+ kind,
+ relevance,
+ completion,
+ selectionOffset,
+ 0,
+ false,
+ false,
+ // Let the user know that we are going to insert a complete statement.
+ displayText: displayText,
+ elementLocation: method.location,
+ ),
+ textToMatchOverride: 'setState',
+ );
+ }
+
/// Add a suggestion for a static field declared within a class or extension.
/// If the field is synthetic, add the corresponding getter instead.
///