| // Copyright (c) 2020, 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 'dart:core'; |
| |
| import 'package:analysis_server/plugin/edit/fix/fix_dart.dart'; |
| import 'package:analysis_server/src/services/correction/change_workspace.dart'; |
| import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart'; |
| import 'package:analysis_server/src/services/correction/dart/add_await.dart'; |
| import 'package:analysis_server/src/services/correction/dart/add_override.dart'; |
| import 'package:analysis_server/src/services/correction/dart/convert_add_all_to_spread.dart'; |
| import 'package:analysis_server/src/services/correction/dart/convert_conditional_expression_to_if_element.dart'; |
| import 'package:analysis_server/src/services/correction/dart/convert_documentation_into_line.dart'; |
| import 'package:analysis_server/src/services/correction/dart/convert_quotes.dart'; |
| import 'package:analysis_server/src/services/correction/dart/convert_to_contains.dart'; |
| import 'package:analysis_server/src/services/correction/dart/convert_to_generic_function_syntax.dart'; |
| import 'package:analysis_server/src/services/correction/dart/convert_to_if_null.dart'; |
| import 'package:analysis_server/src/services/correction/dart/convert_to_where_type.dart'; |
| import 'package:analysis_server/src/services/correction/dart/create_method.dart'; |
| import 'package:analysis_server/src/services/correction/dart/make_final.dart'; |
| import 'package:analysis_server/src/services/correction/dart/remove_argument.dart'; |
| import 'package:analysis_server/src/services/correction/dart/remove_await.dart'; |
| import 'package:analysis_server/src/services/correction/dart/remove_const.dart'; |
| import 'package:analysis_server/src/services/correction/dart/remove_duplicate_case.dart'; |
| import 'package:analysis_server/src/services/correction/dart/remove_empty_catch.dart'; |
| import 'package:analysis_server/src/services/correction/dart/remove_empty_constructor_body.dart'; |
| import 'package:analysis_server/src/services/correction/dart/remove_empty_else.dart'; |
| import 'package:analysis_server/src/services/correction/dart/remove_empty_statement.dart'; |
| import 'package:analysis_server/src/services/correction/dart/remove_initializer.dart'; |
| import 'package:analysis_server/src/services/correction/dart/remove_method_declaration.dart'; |
| import 'package:analysis_server/src/services/correction/dart/remove_operator.dart'; |
| import 'package:analysis_server/src/services/correction/dart/remove_this_expression.dart'; |
| import 'package:analysis_server/src/services/correction/dart/remove_type_annotation.dart'; |
| import 'package:analysis_server/src/services/correction/dart/remove_unnecessary_new.dart'; |
| import 'package:analysis_server/src/services/correction/dart/replace_cascade_with_dot.dart'; |
| import 'package:analysis_server/src/services/correction/dart/replace_colon_with_equals.dart'; |
| import 'package:analysis_server/src/services/correction/dart/replace_null_with_closure.dart'; |
| import 'package:analysis_server/src/services/correction/dart/replace_with_conditional_assignment.dart'; |
| import 'package:analysis_server/src/services/correction/dart/replace_with_is_empty.dart'; |
| import 'package:analysis_server/src/services/correction/dart/replace_with_tear_off.dart'; |
| import 'package:analysis_server/src/services/correction/dart/replace_with_var.dart'; |
| import 'package:analysis_server/src/services/correction/dart/use_curly_braces.dart'; |
| import 'package:analysis_server/src/services/correction/dart/use_is_not_empty.dart'; |
| import 'package:analysis_server/src/services/correction/dart/use_rethrow.dart'; |
| import 'package:analysis_server/src/services/correction/fix.dart'; |
| import 'package:analysis_server/src/services/correction/fix_internal.dart'; |
| import 'package:analysis_server/src/services/linter/lint_names.dart'; |
| import 'package:analyzer/dart/analysis/results.dart'; |
| import 'package:analyzer/error/error.dart'; |
| import 'package:analyzer/src/error/codes.dart'; |
| import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart'; |
| |
| /// A fix producer that produces changes to fix multiple diagnostics. |
| class BulkFixProcessor { |
| /// A map from the name of a lint rule to a generator used to create the |
| /// correction producer used to build a fix for that diagnostic. The |
| /// generators used for non-lint diagnostics are in the [nonLintProducerMap]. |
| static const Map<String, ProducerGenerator> lintProducerMap = { |
| LintNames.annotate_overrides: AddOverride.newInstance, |
| LintNames.avoid_annotating_with_dynamic: RemoveTypeAnnotation.newInstance, |
| LintNames.avoid_empty_else: RemoveEmptyElse.newInstance, |
| LintNames.avoid_init_to_null: RemoveInitializer.newInstance, |
| LintNames.avoid_redundant_argument_values: RemoveArgument.newInstance, |
| LintNames.avoid_return_types_on_setters: RemoveTypeAnnotation.newInstance, |
| LintNames.avoid_single_cascade_in_expression_statements: |
| ReplaceCascadeWithDot.newInstance, |
| LintNames.avoid_types_on_closure_parameters: |
| RemoveTypeAnnotation.newInstance, |
| LintNames.await_only_futures: RemoveAwait.newInstance, |
| LintNames.curly_braces_in_flow_control_structures: |
| UseCurlyBraces.newInstance, |
| LintNames.empty_catches: RemoveEmptyCatch.newInstance, |
| LintNames.empty_constructor_bodies: RemoveEmptyConstructorBody.newInstance, |
| LintNames.empty_statements: RemoveEmptyStatement.newInstance, |
| LintNames.hash_and_equals: CreateMethod.equalsOrHashCode, |
| LintNames.no_duplicate_case_values: RemoveDuplicateCase.newInstance, |
| LintNames.null_closures: ReplaceNullWithClosure.newInstance, |
| LintNames.omit_local_variable_types: ReplaceWithVar.newInstance, |
| LintNames.prefer_adjacent_string_concatenation: RemoveOperator.newInstance, |
| LintNames.prefer_conditional_assignment: |
| ReplaceWithConditionalAssignment.newInstance, |
| LintNames.prefer_contains: ConvertToContains.newInstance, |
| LintNames.prefer_equal_for_default_values: |
| ReplaceColonWithEquals.newInstance, |
| LintNames.prefer_final_fields: MakeFinal.newInstance, |
| LintNames.prefer_generic_function_type_aliases: |
| ConvertToGenericFunctionSyntax.newInstance, |
| LintNames.prefer_if_elements_to_conditional_expressions: |
| ConvertConditionalExpressionToIfElement.newInstance, |
| LintNames.prefer_if_null_operators: ConvertToIfNull.newInstance, |
| LintNames.prefer_is_empty: ReplaceWithIsEmpty.newInstance, |
| LintNames.prefer_is_not_empty: UesIsNotEmpty.newInstance, |
| LintNames.prefer_iterable_whereType: ConvertToWhereType.newInstance, |
| LintNames.prefer_single_quotes: ConvertToSingleQuotes.newInstance, |
| LintNames.prefer_spread_collections: ConvertAddAllToSpread.newInstance, |
| LintNames.slash_for_doc_comments: ConvertDocumentationIntoLine.newInstance, |
| LintNames.type_init_formals: RemoveTypeAnnotation.newInstance, |
| LintNames.unawaited_futures: AddAwait.newInstance, |
| LintNames.unnecessary_const: RemoveUnnecessaryConst.newInstance, |
| LintNames.unnecessary_lambdas: ReplaceWithTearOff.newInstance, |
| LintNames.unnecessary_new: RemoveUnnecessaryNew.newInstance, |
| LintNames.unnecessary_overrides: RemoveMethodDeclaration.newInstance, |
| LintNames.unnecessary_this: RemoveThisExpression.newInstance, |
| LintNames.use_rethrow_when_possible: UseRethrow.newInstance, |
| }; |
| |
| /// A map from an error code to a generator used to create the correction |
| /// producer used to build a fix for that diagnostic. The generators used for |
| /// lint rules are in the [lintProducerMap]. |
| static const Map<ErrorCode, ProducerGenerator> nonLintProducerMap = {}; |
| |
| final DartChangeWorkspace workspace; |
| |
| /// The change builder used to build the changes required to fix the |
| /// diagnostics. |
| ChangeBuilder builder; |
| |
| BulkFixProcessor(this.workspace) { |
| builder = ChangeBuilder(workspace: workspace); |
| } |
| |
| Future<ChangeBuilder> fixErrorsInLibraries(List<String> libraryPaths) async { |
| for (var path in libraryPaths) { |
| var session = workspace.getSession(path); |
| var libraryResult = await session.getResolvedLibrary(path); |
| await _fixErrorsInLibrary(libraryResult); |
| } |
| return builder; |
| } |
| |
| Future<void> _fixErrorsInLibrary(ResolvedLibraryResult libraryResult) async { |
| for (var unitResult in libraryResult.units) { |
| final fixContext = DartFixContextImpl( |
| workspace, |
| unitResult, |
| null, |
| (name) => [], |
| ); |
| for (var error in unitResult.errors) { |
| await _fixSingleError(fixContext, unitResult, error); |
| } |
| } |
| } |
| |
| Future<void> _fixSingleError(DartFixContext fixContext, |
| ResolvedUnitResult unitResult, AnalysisError error) async { |
| var context = CorrectionProducerContext( |
| dartFixContext: fixContext, |
| diagnostic: error, |
| resolvedResult: unitResult, |
| selectionOffset: error.offset, |
| selectionLength: error.length, |
| workspace: workspace, |
| ); |
| |
| var setupSuccess = context.setupCompute(); |
| if (!setupSuccess) { |
| return; |
| } |
| |
| Future<void> compute(CorrectionProducer producer) async { |
| producer.configure(context); |
| await producer.compute(builder); |
| } |
| |
| var errorCode = error.errorCode; |
| if (errorCode is LintCode) { |
| var generator = lintProducerMap[errorCode.name]; |
| if (generator != null) { |
| await compute(generator()); |
| } |
| } else { |
| var generator = nonLintProducerMap[errorCode]; |
| if (generator != null) { |
| await compute(generator()); |
| } |
| } |
| } |
| } |