Files
sdk/pkg/analysis_server/test/lsp/code_actions_source_test.dart
T
Brian Wilkerson df48c55595 Fix the remove-unused-parameter fix when applied to a field formal parameter
The assist used to change the semantics by removing the assignment of
the default value to the field. This fixes that by adding an explicit
assignment in the initializer list.

Fixes: https://github.com/dart-lang/sdk/issues/61810
Fixes: https://github.com/dart-lang/sdk/issues/62809
Change-Id: I8fdb9169e8499e5a99c7b954f3dad7ddab289bb6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/485280
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
2026-03-03 16:30:09 -08:00

357 lines
9.1 KiB
Dart

// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import 'package:analysis_server/lsp_protocol/protocol.dart';
import 'package:analysis_server/src/lsp/constants.dart';
import 'package:analysis_server/src/services/correction/fix_internal.dart';
import 'package:linter/src/rules.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../shared/shared_code_actions_source_tests.dart';
import 'code_actions_mixin.dart';
import 'server_abstract.dart';
void main() {
defineReflectiveSuite(() {
defineReflectiveTests(SourceCodeActionsTest);
defineReflectiveTests(SortMembersSourceCodeActionsTest);
defineReflectiveTests(OrganizeImportsSourceCodeActionsTest);
defineReflectiveTests(FixAllSourceCodeActionsTest);
});
}
abstract class AbstractSourceCodeActionsTest
extends AbstractLspAnalysisServerTest
with
LspSharedTestMixin,
SharedSourceCodeActionsTestMixin,
CodeActionsTestMixin {}
@reflectiveTest
class FixAllSourceCodeActionsTest extends AbstractSourceCodeActionsTest {
@override
Future<void> setUp() async {
await super.setUp();
// Fix tests are likely to have diagnostics that need fixing.
failTestOnErrorDiagnostic = false;
registerBuiltInFixGenerators();
}
Future<void> test_appliesCorrectEdits() async {
const analysisOptionsContent = '''
linter:
rules:
- unnecessary_new
- prefer_collection_literals
''';
const content = '''
final a = new Object();
final b = new Set<String>();
''';
const expectedContent = '''
final a = Object();
final b = <String>{};
''';
registerLintRules();
newFile(analysisOptionsPath, analysisOptionsContent);
newFile(mainFilePath, content);
await verifyCodeActionLiteralEdits(
content,
expectedContent,
command: Commands.fixAll,
);
}
Future<void> test_multipleIterations_noOverlay() async {
const analysisOptionsContent = '''
linter:
rules:
- prefer_final_locals
- prefer_const_declarations
''';
const content = '''
void f() {
var a = 'test';
}
''';
const expectedContent = '''
void f() {
const a = 'test';
}
''';
registerLintRules();
newFile(analysisOptionsPath, analysisOptionsContent);
newFile(mainFilePath, content);
await verifyCodeActionLiteralEdits(
content,
expectedContent,
command: Commands.fixAll,
);
}
Future<void> test_multipleIterations_overlay() async {
const analysisOptionsContent = '''
linter:
rules:
- prefer_final_locals
- prefer_const_declarations
''';
const content = '''
void f() {
var a = 'test';
}
''';
const expectedContent = '''
void f() {
const a = 'test';
}
''';
registerLintRules();
newFile(analysisOptionsPath, analysisOptionsContent);
await verifyCodeActionLiteralEdits(
content,
expectedContent,
command: Commands.fixAll,
);
}
Future<void> test_multipleIterations_withClientModification() async {
const analysisOptionsContent = '''
linter:
rules:
- prefer_final_locals
- prefer_const_declarations
''';
const content = '''
void f() {
var a = 'test';
}
''';
registerLintRules();
newFile(analysisOptionsPath, analysisOptionsContent);
var codeAction = await expectCodeActionLiteral(
content,
command: Commands.fixAll,
);
var command = codeAction.command!;
// Files must be open to apply edits.
await openFile(testFileUri, content);
// Execute the command with a modification and capture the edit that is
// sent back to us.
ApplyWorkspaceEditParams? editParams;
await handleExpectedRequest<
Object?,
ApplyWorkspaceEditParams,
ApplyWorkspaceEditResult
>(
Method.workspace_applyEdit,
ApplyWorkspaceEditParams.fromJson,
() async {
// Apply the command and immediately modify a file afterwards without
// awaiting.
var commandFuture = executeCommand(command);
await replaceFile(12345, testFileUri, 'client-modified-content');
return commandFuture;
},
handler: (edit) {
// When the server sends the edit back, just keep a copy and say we
// applied successfully (we'll verify the actual edit below).
editParams = edit;
return ApplyWorkspaceEditResult(applied: true);
},
);
// Extract the text edit from the 'workspace/applyEdit' params the server
// sent us.
var change = editParams?.edit.documentChanges!.single;
var edit = change!.map(
(create) => throw 'Expected edit, got create',
(delete) => throw 'Expected edit, got delete',
(rename) => throw 'Expected edit, got rename',
(edit) => edit,
);
// Ensure the edit says that it was based on version 1 (the original
// version) and not the updated 12345 version we sent.
expect(edit.textDocument.version, 1);
}
Future<void> test_part() async {
var containerFilePath = join(projectFolderPath, 'lib', 'container.dart');
var partFilePath = join(projectFolderPath, 'lib', 'part.dart');
const analysisOptionsContent = '''
linter:
rules:
- unnecessary_new
- prefer_collection_literals
''';
const containerFileContent = '''
part 'part.dart';
''';
const content = '''
part of 'container.dart';
final a = new Object();
final b = new Set<String>();
''';
const expectedContent = '''
part of 'container.dart';
final a = Object();
final b = <String>{};
''';
registerLintRules();
newFile(analysisOptionsPath, analysisOptionsContent);
newFile(containerFilePath, containerFileContent);
newFile(partFilePath, content);
await verifyCodeActionLiteralEdits(
filePath: partFilePath,
content,
expectedContent,
command: Commands.fixAll,
);
}
Future<void> test_privateUnusedParameters_notRemovedIfSave() async {
const content = '''
class _MyClass {
int? _param;
_MyClass({
this._param,
});
}
''';
var codeAction = await expectCodeActionLiteral(
content,
command: Commands.fixAll,
triggerKind: CodeActionTriggerKind.Automatic,
);
var command = codeAction.command!;
// We should not get an applyEdit call during the command execution because
// no edits should be produced.
var applyEditSubscription = requestsFromServer
.where((n) => n.method == Method.workspace_applyEdit)
.listen((_) => throw 'workspace/applyEdit was unexpectedly called');
var commandResponse = await executeCommand(command);
expect(commandResponse, isNull);
await pumpEventQueue();
await applyEditSubscription.cancel();
}
Future<void> test_privateUnusedParameters_removedByDefault() async {
const content = '''
class _MyClass {
int? param;
_MyClass({
this.param,
});
}
''';
const expectedContent = '''
class _MyClass {
int? param;
_MyClass() : param = null;
}
''';
await verifyCodeActionLiteralEdits(
content,
expectedContent,
command: Commands.fixAll,
);
}
Future<void> test_unavailable_outsideAnalysisRoot() async {
var otherFile = convertPath('/other/file.dart');
var content = '';
await expectNoAction(
filePath: otherFile,
content,
command: Commands.organizeImports,
);
}
Future<void> test_unusedUsings_notRemovedIfSave() async {
const content = '''
import 'dart:async';
int? a;
''';
var codeAction = await expectCodeActionLiteral(
content,
command: Commands.fixAll,
triggerKind: CodeActionTriggerKind.Automatic,
);
var command = codeAction.command!;
// We should not get an applyEdit call during the command execution because
// no edits should be produced.
var applyEditSubscription = requestsFromServer
.where((n) => n.method == Method.workspace_applyEdit)
.listen((_) => throw 'workspace/applyEdit was unexpectedly called');
var commandResponse = await executeCommand(command);
expect(commandResponse, isNull);
await pumpEventQueue();
await applyEditSubscription.cancel();
}
Future<void> test_unusedUsings_removedByDefault() async {
const content = '''
import 'dart:async';
int? a;
''';
const expectedContent = '''
int? a;
''';
await verifyCodeActionLiteralEdits(
content,
expectedContent,
command: Commands.fixAll,
);
}
}
@reflectiveTest
class OrganizeImportsSourceCodeActionsTest extends AbstractSourceCodeActionsTest
with
SharedSourceCodeActionsTestMixin,
// Tests are defined in a shared mixin.
SharedOrganizeImportsSourceCodeActionsTests {}
@reflectiveTest
class SortMembersSourceCodeActionsTest extends AbstractSourceCodeActionsTest
with
SharedSourceCodeActionsTestMixin,
// Tests are defined in a shared mixin.
SharedSortMembersSourceCodeActionsTests {}
@reflectiveTest
class SourceCodeActionsTest extends AbstractSourceCodeActionsTest
with
SharedSourceCodeActionsTestMixin,
// Tests are defined in a shared mixin.
SharedSourceCodeActionsTests {}