bulk fix for `prefer_collection_literals`

Change-Id: Idc83fdc00296388f9e7b0eb35ae4d195577906ef
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/164401
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Phil Quitslund <pquitslund@google.com>
diff --git a/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart b/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
index ac0d56c..78b882b 100644
--- a/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
+++ b/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
@@ -20,8 +20,11 @@
 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_int_literal.dart';
+import 'package:analysis_server/src/services/correction/dart/convert_to_list_literal.dart';
+import 'package:analysis_server/src/services/correction/dart/convert_to_map_literal.dart';
 import 'package:analysis_server/src/services/correction/dart/convert_to_null_aware.dart';
 import 'package:analysis_server/src/services/correction/dart/convert_to_relative_import.dart';
+import 'package:analysis_server/src/services/correction/dart/convert_to_set_literal.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';
@@ -63,70 +66,167 @@
 
 /// 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.diagnostic_describe_all_properties:
-        AddDiagnosticPropertyReference.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.non_constant_identifier_names: RenameToCamelCase.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_const_constructors_in_immutables: AddConst.newInstance,
-    LintNames.prefer_const_declarations: ReplaceFinalWithConst.newInstance,
-    LintNames.prefer_contains: ConvertToContains.newInstance,
-    LintNames.prefer_equal_for_default_values:
-        ReplaceColonWithEquals.newInstance,
-    LintNames.prefer_final_fields: MakeFinal.newInstance,
-    LintNames.prefer_final_locals: MakeFinal.newInstance,
-    LintNames.prefer_for_elements_to_map_fromIterable:
-        ConvertMapFromIterableToForLiteral.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_int_literals: ConvertToIntLiteral.newInstance,
-    LintNames.prefer_is_empty: ReplaceWithIsEmpty.newInstance,
-    LintNames.prefer_is_not_empty: UesIsNotEmpty.newInstance,
-    LintNames.prefer_iterable_whereType: ConvertToWhereType.newInstance,
-    LintNames.prefer_null_aware_operators: ConvertToNullAware.newInstance,
-    LintNames.prefer_relative_imports: ConvertToRelativeImport.newInstance,
-    LintNames.prefer_single_quotes: ConvertToSingleQuotes.newInstance,
-    LintNames.prefer_spread_collections: ConvertAddAllToSpread.newInstance,
-    LintNames.slash_for_doc_comments: ConvertDocumentationIntoLine.newInstance,
-    LintNames.sort_child_properties_last: SortChildPropertyLast.newInstance,
-    LintNames.type_init_formals: RemoveTypeAnnotation.newInstance,
-    LintNames.unawaited_futures: AddAwait.newInstance,
-    LintNames.unnecessary_brace_in_string_interps:
-        RemoveInterpolationBraces.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 the name of a lint rule to a list of generators used to create
+  /// the correction producer used to build a fix for that diagnostic. Most
+  /// entries will have only one generator.  In cases where there is more than
+  /// one, they will be applied in series and the expectation is that only one
+  /// will produce a change for a given fix. If more than one change is produced
+  /// the result will almost certainly be invalid code. The generators used for
+  /// non-lint diagnostics are in the [nonLintProducerMap].
+  static const Map<String, List<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.diagnostic_describe_all_properties: [
+      AddDiagnosticPropertyReference.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.non_constant_identifier_names: [
+      RenameToCamelCase.newInstance,
+    ],
+    LintNames.null_closures: [
+      ReplaceNullWithClosure.newInstance,
+    ],
+    LintNames.omit_local_variable_types: [
+      ReplaceWithVar.newInstance,
+    ],
+    LintNames.prefer_adjacent_string_concatenation: [
+      RemoveOperator.newInstance,
+    ],
+    LintNames.prefer_collection_literals: [
+      ConvertToListLiteral.newInstance,
+      ConvertToMapLiteral.newInstance,
+      ConvertToSetLiteral.newInstance,
+    ],
+    LintNames.prefer_conditional_assignment: [
+      ReplaceWithConditionalAssignment.newInstance,
+    ],
+    LintNames.prefer_const_constructors_in_immutables: [
+      AddConst.newInstance,
+    ],
+    LintNames.prefer_const_declarations: [
+      ReplaceFinalWithConst.newInstance,
+    ],
+    LintNames.prefer_contains: [
+      ConvertToContains.newInstance,
+    ],
+    LintNames.prefer_equal_for_default_values: [
+      ReplaceColonWithEquals.newInstance,
+    ],
+    LintNames.prefer_final_fields: [
+      MakeFinal.newInstance,
+    ],
+    LintNames.prefer_final_locals: [
+      MakeFinal.newInstance,
+    ],
+    LintNames.prefer_for_elements_to_map_fromIterable: [
+      ConvertMapFromIterableToForLiteral.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_int_literals: [
+      ConvertToIntLiteral.newInstance,
+    ],
+    LintNames.prefer_is_empty: [
+      ReplaceWithIsEmpty.newInstance,
+    ],
+    LintNames.prefer_is_not_empty: [
+      UesIsNotEmpty.newInstance,
+    ],
+    LintNames.prefer_iterable_whereType: [
+      ConvertToWhereType.newInstance,
+    ],
+    LintNames.prefer_null_aware_operators: [
+      ConvertToNullAware.newInstance,
+    ],
+    LintNames.prefer_relative_imports: [
+      ConvertToRelativeImport.newInstance,
+    ],
+    LintNames.prefer_single_quotes: [
+      ConvertToSingleQuotes.newInstance,
+    ],
+    LintNames.prefer_spread_collections: [
+      ConvertAddAllToSpread.newInstance,
+    ],
+    LintNames.slash_for_doc_comments: [
+      ConvertDocumentationIntoLine.newInstance,
+    ],
+    LintNames.sort_child_properties_last: [
+      SortChildPropertyLast.newInstance,
+    ],
+    LintNames.type_init_formals: [
+      RemoveTypeAnnotation.newInstance,
+    ],
+    LintNames.unawaited_futures: [
+      AddAwait.newInstance,
+    ],
+    LintNames.unnecessary_brace_in_string_interps: [
+      RemoveInterpolationBraces.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
@@ -190,9 +290,11 @@
 
     var errorCode = error.errorCode;
     if (errorCode is LintCode) {
-      var generator = lintProducerMap[errorCode.name];
-      if (generator != null) {
-        await compute(generator());
+      var generators = lintProducerMap[errorCode.name];
+      if (generators != null) {
+        for (var generator in generators) {
+          await compute(generator());
+        }
       }
     } else {
       var generator = nonLintProducerMap[errorCode];
diff --git a/pkg/analysis_server/test/src/services/correction/fix/bulk/convert_to_list_literal_test.dart b/pkg/analysis_server/test/src/services/correction/fix/bulk/convert_to_list_literal_test.dart
new file mode 100644
index 0000000..8810f14
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/bulk/convert_to_list_literal_test.dart
@@ -0,0 +1,31 @@
+// 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 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'bulk_fix_processor.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ConvertToListLiteralTest);
+  });
+}
+
+@reflectiveTest
+class ConvertToListLiteralTest extends BulkFixProcessorTest {
+  @override
+  String get lintCode => LintNames.prefer_collection_literals;
+
+  Future<void> test_singleFile() async {
+    await resolveTestUnit('''
+List l = List();
+var l2 = List<int>();
+''');
+    await assertHasFix('''
+List l = [];
+var l2 = <int>[];
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/bulk/convert_to_map_literal_test.dart b/pkg/analysis_server/test/src/services/correction/fix/bulk/convert_to_map_literal_test.dart
new file mode 100644
index 0000000..066755e
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/bulk/convert_to_map_literal_test.dart
@@ -0,0 +1,31 @@
+// 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 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'bulk_fix_processor.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ConvertToMapLiteralTest);
+  });
+}
+
+@reflectiveTest
+class ConvertToMapLiteralTest extends BulkFixProcessorTest {
+  @override
+  String get lintCode => LintNames.prefer_collection_literals;
+
+  Future<void> test_singleFile() async {
+    await resolveTestUnit('''
+Map m = Map();
+var m2 = Map<String, int>();
+''');
+    await assertHasFix('''
+Map m = {};
+var m2 = <String, int>{};
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/bulk/convert_to_set_literal_test.dart b/pkg/analysis_server/test/src/services/correction/fix/bulk/convert_to_set_literal_test.dart
new file mode 100644
index 0000000..526e697
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/bulk/convert_to_set_literal_test.dart
@@ -0,0 +1,31 @@
+// 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 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'bulk_fix_processor.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ConvertToSetLiteralTest);
+  });
+}
+
+@reflectiveTest
+class ConvertToSetLiteralTest extends BulkFixProcessorTest {
+  @override
+  String get lintCode => LintNames.prefer_collection_literals;
+
+  Future<void> test_singleFile() async {
+    await resolveTestUnit('''
+Set s = Set();
+var s1 = Set<int>();
+''');
+    await assertHasFix('''
+Set s = {};
+var s1 = <int>{};
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/bulk/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/bulk/test_all.dart
index 4d7e35b..fd34894 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/bulk/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/bulk/test_all.dart
@@ -19,8 +19,11 @@
 import 'convert_to_if_element_test.dart' as convert_to_if_element;
 import 'convert_to_if_null_test.dart' as convert_to_if_null;
 import 'convert_to_int_literal_test.dart' as convert_to_int_literal;
+import 'convert_to_list_literal_test.dart' as convert_to_list_literal;
+import 'convert_to_map_literal_test.dart' as convert_to_map_literal;
 import 'convert_to_null_aware_test.dart' as convert_to_null_aware;
 import 'convert_to_relative_import_test.dart' as convert_to_relative_import;
+import 'convert_to_set_literal_test.dart' as convert_to_set_literal;
 import 'convert_to_single_quoted_strings_test.dart'
     as convert_to_single_quoted_strings;
 import 'convert_to_spread_test.dart' as convert_to_spread;
@@ -70,8 +73,11 @@
     convert_to_if_element.main();
     convert_to_if_null.main();
     convert_to_int_literal.main();
+    convert_to_list_literal.main();
+    convert_to_map_literal.main();
     convert_to_null_aware.main();
     convert_to_relative_import.main();
+    convert_to_set_literal.main();
     convert_to_single_quoted_strings.main();
     convert_to_spread.main();
     convert_to_where_type.main();