Add support for sort imports to BulkFixProcessor, add prefer_generic_function_type_aliases to list of lints for lightweight mode.

Change-Id: Ic8a1afde5f35a65065dd8439a11c4d99846c2905
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/319240
Commit-Queue: Keerti Parthasarathy <keertip@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Keerti Parthasarathy 2023-08-08 21:10:54 +00:00 committed by Commit Queue
parent 1948b0a9fe
commit 155bfc973b
6 changed files with 94 additions and 6 deletions

View file

@ -2,6 +2,7 @@
// 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 'package:_fe_analyzer_shared/src/scanner/errors.dart';
import 'package:analysis_server/plugin/edit/fix/fix_dart.dart';
import 'package:analysis_server/protocol/protocol_generated.dart'
hide AnalysisOptions;
@ -24,8 +25,10 @@ import 'package:analyzer/exception/exception.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/instrumentation/service.dart';
import 'package:analyzer/source/error_processor.dart';
import 'package:analyzer/source/source_range.dart';
import 'package:analyzer/src/clients/build_resolvers/build_resolvers.dart';
import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/error/syntactic_errors.g.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/lint/linter.dart';
import 'package:analyzer/src/lint/linter_visitor.dart';
@ -42,6 +45,8 @@ import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dar
import 'package:analyzer_plugin/utilities/change_builder/conflicting_edit_exception.dart';
import 'package:collection/collection.dart';
import 'organize_imports.dart';
/// A fix producer that produces changes that will fix multiple diagnostics in
/// one or more files.
///
@ -55,10 +60,12 @@ class BulkFixProcessor {
/// A list of lint codes that can be run on parsed code. These lints will all
/// be run when the `--syntactic-fixes` flag is specified.
static const List<String> syntacticLintCodes = [
LintNames.prefer_generic_function_type_aliases,
LintNames.slash_for_doc_comments,
LintNames.unnecessary_const,
LintNames.unnecessary_new,
LintNames.unnecessary_string_escapes,
LintNames.use_function_type_syntax_for_parameters,
];
/// A map from an error code to a list of generators used to create multiple
@ -270,6 +277,10 @@ class BulkFixProcessor {
return changeMap.hasFixes;
}
Future<BulkFixRequestResult> organizeDirectives(
List<AnalysisContext> contexts) =>
_organizeDirectives(contexts);
Future<void> _applyProducer(
CorrectionProducerContext context, CorrectionProducer producer) async {
producer.configure(context);
@ -696,6 +707,41 @@ class BulkFixProcessor {
return FixProcessor.canBulkFix(errorCode);
}
Future<BulkFixRequestResult> _organizeDirectives(
List<AnalysisContext> contexts) async {
for (var context in contexts) {
for (var path in context.contextRoot.analyzedFiles()) {
var pathContext = context.contextRoot.resourceProvider.pathContext;
if (!file_paths.isDart(pathContext, path) ||
file_paths.isGenerated(path)) {
continue;
}
var result =
context.currentSession.getParsedUnit(path) as ParsedUnitResult;
var code = result.content;
var errors = result.errors;
// check if there are scan/parse errors in the file
var hasParseErrors = errors.any((error) =>
error.errorCode is ScannerErrorCode ||
error.errorCode is ParserErrorCode);
if (hasParseErrors) {
// cannot process files with parse errors
continue;
}
// do organize
var sorter = ImportOrganizer(code, result.unit, errors);
var edits = sorter.organize();
await builder.addGenericFileEdit(path, (builder) {
for (var edit in edits) {
builder.addSimpleReplacement(
SourceRange(edit.offset, edit.length), edit.replacement);
}
});
}
}
return BulkFixRequestResult(builder);
}
/// Return the override set corresponding to the given [result], or `null` if
/// there is no corresponding configuration file or the file content isn't a
/// valid override set.

View file

@ -1733,6 +1733,9 @@ class FixProcessor extends BaseProcessor {
/// A map from error codes to a list of fix generators that work with only
/// parsed results.
static final Map<String, List<ProducerGenerator>> parseLintProducerMap = {
LintNames.prefer_generic_function_type_aliases: [
ConvertToGenericFunctionSyntax.new,
],
LintNames.slash_for_doc_comments: [
ConvertDocumentationIntoLine.new,
],
@ -1745,6 +1748,9 @@ class FixProcessor extends BaseProcessor {
LintNames.unnecessary_string_escapes: [
RemoveUnnecessaryStringEscape.new,
],
LintNames.use_function_type_syntax_for_parameters: [
ConvertToGenericFunctionSyntax.new,
],
};
final DartFixContext fixContext;

View file

@ -22,6 +22,7 @@ class AbstractSingleUnitTest extends AbstractContextTest {
bool useLineEndingsForPlatform = false;
late String testCode;
late ParsedUnitResult testParsedResult;
late ResolvedUnitResult testAnalysisResult;
late CompilationUnit testUnit;
late CompilationUnitElement testUnitElement;
@ -48,6 +49,7 @@ class AbstractSingleUnitTest extends AbstractContextTest {
@override
Future<ParsedUnitResult> getParsedUnit(File file) async {
var result = await super.getParsedUnit(file);
testParsedResult = result;
testCode = result.content;
testUnit = result.unit;
findNode = FindNode(testCode, testUnit);

View file

@ -24,14 +24,14 @@ class PreferGenericFunctionTypeAliasesBulkTest extends BulkFixProcessorTest {
String get lintCode => LintNames.prefer_generic_function_type_aliases;
Future<void> test_singleFile() async {
await resolveTestCode('''
await parseTestCode('''
typedef String F(int x);
typedef F2<P, R>(P x);
''');
await assertHasFix('''
typedef F = String Function(int x);
typedef F2<P, R> = Function(P x);
''');
''', isParse: true);
}
}
@ -93,23 +93,23 @@ class UseFunctionTypeSyntaxForParametersBulkTest extends BulkFixProcessorTest {
String get lintCode => LintNames.use_function_type_syntax_for_parameters;
Future<void> test_singleFile() async {
await resolveTestCode('''
await parseTestCode('''
g(String f(int x), int h()) {}
''');
await assertHasFix('''
g(String Function(int x) f, int Function() h) {}
''');
''', isParse: true);
}
@failingTest
Future<void> test_singleFile_nested() async {
// Only the outer function gets converted.
await resolveTestCode('''
await parseTestCode('''
g(String f(int h())) {}
''');
await assertHasFix('''
g(String Function(int Function() h) f) {}
''');
''', isParse: true);
}
}

View file

@ -118,6 +118,20 @@ abstract class BulkFixProcessorTest extends AbstractSingleUnitTest {
expect(fileEdits, isEmpty);
}
Future<void> assertOrganize(String expectedCode) async {
var tracker = DeclarationsTracker(MemoryByteStore(), resourceProvider);
var analysisContext = contextFor(testFile);
tracker.addContext(analysisContext);
processor = BulkFixProcessor(TestInstrumentationService(), await workspace,
useConfigFiles: useConfigFiles);
await processor.organizeDirectives([analysisContext]);
var change = processor.builder.sourceChange;
var fileEdits = change.edits;
expect(fileEdits, hasLength(1));
resultCode = SourceEdit.applySequence(testCode, change.edits[0].edits);
expect(resultCode, expectedCode);
}
/// Computes fixes for the specified [testUnit].
Future<BulkFixProcessor> computeFixes({bool isParse = false}) async {
var tracker = DeclarationsTracker(MemoryByteStore(), resourceProvider);

View file

@ -11,10 +11,30 @@ import 'fix_processor.dart';
void main() {
defineReflectiveSuite(() {
defineReflectiveTests(OrganizeImportsBulkTest);
defineReflectiveTests(OrganizeImportsTest);
});
}
@reflectiveTest
class OrganizeImportsBulkTest extends BulkFixProcessorTest {
Future<void> test_single_file() async {
await parseTestCode('''
import 'dart:io';
import 'dart:async';
Future a;
''');
await assertOrganize('''
import 'dart:async';
import 'dart:io';
Future a;
''');
}
}
@reflectiveTest
class OrganizeImportsTest extends FixProcessorLintTest {
@override