Skip to content

Commit 222f3dc

Browse files
DanTupcommit-bot@chromium.org
authored andcommitted
[Analyzer] Prevent two sets of parens being inserted for setState() when LSP's completeFunctionCalls is enabled
Fixes Dart-Code/Dart-Code#3006. Change-Id: Idc1ac2b41208a13a887e0c0ece98a255114fc634 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/176242 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Brian Wilkerson <[email protected]>
1 parent e40ae3b commit 222f3dc

File tree

2 files changed

+66
-0
lines changed

2 files changed

+66
-0
lines changed

pkg/analysis_server/lib/src/lsp/mapping.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1297,6 +1297,14 @@ Pair<String, lsp.InsertTextFormat> _buildInsertText({
12971297
var insertText = completion;
12981298
var insertTextFormat = lsp.InsertTextFormat.PlainText;
12991299

1300+
// SuggestionBuilder already does the equiv of completeFunctionCalls for
1301+
// some methods (for example Flutter's setState). If the completion already
1302+
// includes any `(` then disable our own insertion as the special-cased code
1303+
// will likely provide better code.
1304+
if (completion.contains('(')) {
1305+
completeFunctionCalls = false;
1306+
}
1307+
13001308
// If the client supports snippets, we can support completeFunctionCalls or
13011309
// setting a selection.
13021310
if (supportsSnippets) {

pkg/analysis_server/test/lsp/completion_dart_test.dart

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,15 @@ class CompletionTest extends AbstractLspAnalysisServerTest {
3131
);
3232
}
3333

34+
@override
35+
void setUp() {
36+
super.setUp();
37+
writePackageConfig(
38+
projectFolderPath,
39+
flutter: true,
40+
);
41+
}
42+
3443
Future<void> test_commitCharacter_completionItem() async {
3544
await provideConfig(
3645
() => initialize(
@@ -124,6 +133,55 @@ main() {
124133
);
125134
}
126135

136+
Future<void> test_completeFunctionCalls_flutterSetState() async {
137+
// Flutter's setState method has special handling inside SuggestionBuilder
138+
// that already adds in a selection (which overlaps with completeFunctionCalls).
139+
// Ensure we don't end up with two sets of parens/placeholders in this case.
140+
final content = '''
141+
import 'package:flutter/material.dart';
142+
143+
class MyWidget extends StatefulWidget {
144+
@override
145+
_MyWidgetState createState() => _MyWidgetState();
146+
}
147+
148+
class _MyWidgetState extends State<MyWidget> {
149+
@override
150+
Widget build(BuildContext context) {
151+
[[setSt^]]
152+
return Container();
153+
}
154+
}
155+
''';
156+
157+
await provideConfig(
158+
() => initialize(
159+
textDocumentCapabilities: withCompletionItemSnippetSupport(
160+
emptyTextDocumentClientCapabilities),
161+
workspaceCapabilities:
162+
withConfigurationSupport(emptyWorkspaceClientCapabilities),
163+
),
164+
{'completeFunctionCalls': true},
165+
);
166+
await openFile(mainFileUri, withoutMarkers(content));
167+
final res = await getCompletion(mainFileUri, positionFromMarker(content));
168+
final item = res.singleWhere((c) => c.label.startsWith('setState('));
169+
170+
// Usually the label would be "setState(…)" but here it's slightly different
171+
// to indicate a full statement is being inserted.
172+
expect(item.label, equals('setState(() {});'));
173+
174+
// Ensure the snippet comes through in the expected format with the expected
175+
// placeholders.
176+
expect(item.insertTextFormat, equals(InsertTextFormat.Snippet));
177+
expect(item.insertText, equals('setState(() {\n \${0:}\n \\});'));
178+
expect(item.textEdit.newText, equals(item.insertText));
179+
expect(
180+
item.textEdit.range,
181+
equals(rangeFromMarkers(content)),
182+
);
183+
}
184+
127185
Future<void> test_completeFunctionCalls_noRequiredParameters() async {
128186
final content = '''
129187
void myFunction({int a}) {}

0 commit comments

Comments
 (0)