Add a quick fix for the MISSING_ENUM_CONSTANT_IN_SWITCH diagnostic (issue 36290)

Change-Id: I6a18fff7c61c93b3444899213da9c447122b76c2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/97780
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index 3bb80d7..a83e2fe 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -133,6 +133,8 @@
       appliedTogetherMessage: "Add all casts in file");
   static const ADD_FIELD_FORMAL_PARAMETERS = const FixKind(
       'ADD_FIELD_FORMAL_PARAMETERS', 70, "Add final field formal parameters");
+  static const ADD_MISSING_ENUM_CASE_CLAUSES = const FixKind(
+      'ADD_MISSING_ENUM_CASE_CLAUSES', 50, 'Add missing case clauses');
   static const ADD_MISSING_PARAMETER_NAMED = const FixKind(
       'ADD_MISSING_PARAMETER_NAMED', 70, "Add named parameter '{0}'");
   static const ADD_MISSING_PARAMETER_POSITIONAL = const FixKind(
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 1aa5bbf..05d16f0 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -209,9 +209,6 @@
   String get eol => utils.endOfLine;
 
   Future<List<Fix>> compute() async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
-
     node = new NodeLocator2(errorOffset).searchWithin(unit);
     coveredNode = new NodeLocator2(errorOffset, errorOffset + errorLength - 1)
         .searchWithin(unit);
@@ -561,6 +558,9 @@
         CompileTimeErrorCode.MIXIN_APPLICATION_NOT_IMPLEMENTED_INTERFACE) {
       await _addFix_extendClassForMixin();
     }
+    if (errorCode == StaticWarningCode.MISSING_ENUM_CONSTANT_IN_SWITCH) {
+      await _addFix_addMissingEnumCaseClauses();
+    }
     // lints
     if (errorCode is LintCode) {
       String name = errorCode.name;
@@ -785,6 +785,69 @@
     }
   }
 
+  Future<void> _addFix_addMissingEnumCaseClauses() async {
+    SwitchStatement statement = node as SwitchStatement;
+    String enumName;
+    List<String> enumConstantNames = [];
+    DartType expressionType = statement.expression.staticType;
+    if (expressionType is InterfaceType) {
+      ClassElement enumElement = expressionType.element;
+      if (enumElement.isEnum) {
+        enumName = enumElement.name;
+        for (FieldElement field in enumElement.fields) {
+          if (!field.isSynthetic) {
+            enumConstantNames.add(field.name);
+          }
+        }
+      }
+    }
+    if (enumName == null) {
+      return;
+    }
+    for (SwitchMember member in statement.members) {
+      if (member is SwitchCase) {
+        Expression expression = member.expression;
+        if (expression is Identifier) {
+          Element element = expression.staticElement;
+          if (element is PropertyAccessorElement) {
+            enumConstantNames.remove(element.name);
+          }
+        }
+      }
+    }
+    if (enumConstantNames.isEmpty) {
+      return;
+    }
+
+    String statementIndent = utils.getLinePrefix(statement.offset);
+    String singleIndent = utils.getIndent(1);
+
+    DartChangeBuilder changeBuilder = _newDartChangeBuilder();
+    await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+      builder.addInsertion(utils.getLineThis(statement.end), (builder) {
+        for (String constantName in enumConstantNames) {
+          builder.write(statementIndent);
+          builder.write(singleIndent);
+          builder.write('case ');
+          builder.write(enumName);
+          builder.write('.');
+          builder.write(constantName);
+          builder.writeln(':');
+          builder.write(statementIndent);
+          builder.write(singleIndent);
+          builder.write(singleIndent);
+          builder.writeln('// TODO: Handle this case.');
+          builder.write(statementIndent);
+          builder.write(singleIndent);
+          builder.write(singleIndent);
+          builder.writeln('break;');
+        }
+      });
+    });
+    _addFixFromBuilder(
+        changeBuilder, DartFixKind.ADD_MISSING_ENUM_CASE_CLAUSES);
+  }
+
   Future<void> _addFix_addMissingParameter() async {
     // TODO(brianwilkerson) Determine whether this await is necessary.
     await null;
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_missing_enum_case_clauses_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_missing_enum_case_clauses_test.dart
new file mode 100644
index 0000000..f796f39
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_missing_enum_case_clauses_test.dart
@@ -0,0 +1,88 @@
+// Copyright (c) 2019, 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/correction/fix.dart';
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(AddMissingEnumCaseClausesTest);
+  });
+}
+
+@reflectiveTest
+class AddMissingEnumCaseClausesTest extends FixProcessorTest {
+  @override
+  FixKind get kind => DartFixKind.ADD_MISSING_ENUM_CASE_CLAUSES;
+
+  Future<void> assertHasFixWithFilter(String expected) async {
+    bool noError = true;
+    await assertHasFix(expected, errorFilter: (error) {
+      if (noError &&
+          error.errorCode ==
+              StaticWarningCode.MISSING_ENUM_CONSTANT_IN_SWITCH) {
+        noError = false;
+        return true;
+      }
+      return false;
+    });
+  }
+
+  test_empty() async {
+    await resolveTestUnit('''
+enum E {a, b, c}
+void f(E e) {
+  switch (e) {
+  }
+}
+''');
+    await assertHasFixWithFilter('''
+enum E {a, b, c}
+void f(E e) {
+  switch (e) {
+    case E.a:
+      // TODO: Handle this case.
+      break;
+    case E.b:
+      // TODO: Handle this case.
+      break;
+    case E.c:
+      // TODO: Handle this case.
+      break;
+  }
+}
+''');
+  }
+
+  test_nonEmpty() async {
+    await resolveTestUnit('''
+enum E {a, b, c}
+void f(E e) {
+  switch (e) {
+    case E.a:
+      break;
+  }
+}
+''');
+    await assertHasFixWithFilter('''
+enum E {a, b, c}
+void f(E e) {
+  switch (e) {
+    case E.a:
+      break;
+    case E.b:
+      // TODO: Handle this case.
+      break;
+    case E.c:
+      // TODO: Handle this case.
+      break;
+  }
+}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
index 1f49a54..e9ea84e 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
@@ -8,6 +8,8 @@
 import 'add_await_test.dart' as add_await;
 import 'add_explicit_cast_test.dart' as add_explicit_cast;
 import 'add_field_formal_parameters_test.dart' as add_field_formal_parameters;
+import 'add_missing_enum_case_clauses_test.dart'
+    as add_missing_enum_case_clauses;
 import 'add_missing_parameter_named_test.dart' as add_missing_parameter_named;
 import 'add_missing_parameter_positional_test.dart'
     as add_missing_parameter_positional;
@@ -110,6 +112,7 @@
     add_await.main();
     add_explicit_cast.main();
     add_field_formal_parameters.main();
+    add_missing_enum_case_clauses.main();
     add_missing_parameter_named.main();
     add_missing_parameter_positional.main();
     add_missing_parameter_required.main();