df48c55595
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>
357 lines
9.1 KiB
Dart
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 {}
|