Mangle extension, enum and top-level names so they don't collide with dart keywords (#289)

diff --git a/protoc_plugin/CHANGELOG.md b/protoc_plugin/CHANGELOG.md
index 2b48b7b..a2d59e6 100644
--- a/protoc_plugin/CHANGELOG.md
+++ b/protoc_plugin/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 18.0.2
+
+* Fix mangling of extension names, message type names, and enum names that are Dart keywords.
+
+  Now you can have an extension called `is` and an enum called `class`.
+
 ## 18.0.1
 
 * Add a `bin/protoc-gen-dart.bat` script making it easier to compile on windows using a local
diff --git a/protoc_plugin/Makefile b/protoc_plugin/Makefile
index 797cbfa..6d6fd08 100644
--- a/protoc_plugin/Makefile
+++ b/protoc_plugin/Makefile
@@ -43,6 +43,8 @@
 	non_nested_extension \
 	oneof \
 	reserved_names \
+	reserved_names_extension \
+	reserved_names_message \
 	duplicate_names_import \
 	package1 \
 	package2 \
diff --git a/protoc_plugin/lib/enum_generator.dart b/protoc_plugin/lib/enum_generator.dart
index c51ea77..f3c1a9f 100644
--- a/protoc_plugin/lib/enum_generator.dart
+++ b/protoc_plugin/lib/enum_generator.dart
@@ -41,7 +41,7 @@
             ? descriptor.name
             : '${parent.fullName}.${descriptor.name}',
         _descriptor = descriptor {
-    final usedNames = reservedEnumNames;
+    final usedNames = Set<String>()..addAll(reservedEnumNames);
     for (var i = 0; i < descriptor.value.length; i++) {
       EnumValueDescriptorProto value = descriptor.value[i];
       EnumValueDescriptorProto canonicalValue =
diff --git a/protoc_plugin/lib/file_generator.dart b/protoc_plugin/lib/file_generator.dart
index d120d57..91c357c 100644
--- a/protoc_plugin/lib/file_generator.dart
+++ b/protoc_plugin/lib/file_generator.dart
@@ -117,12 +117,12 @@
   /// Used to avoid collisions after names have been mangled to match the Dart
   /// style.
   final Set<String> usedTopLevelNames = Set<String>()
-    ..addAll(toplevelReservedCapitalizedNames);
+    ..addAll(forbiddenTopLevelNames);
 
   /// Used to avoid collisions in the service file after names have been mangled
   /// to match the dart style.
   final Set<String> usedTopLevelServiceNames = Set<String>()
-    ..addAll(toplevelReservedCapitalizedNames);
+    ..addAll(forbiddenTopLevelNames);
 
   final Set<String> usedExtensionNames = Set<String>()
     ..addAll(forbiddenExtensionNames);
@@ -158,7 +158,7 @@
     }
     for (var i = 0; i < descriptor.extension.length; i++) {
       extensionGenerators.add(ExtensionGenerator.topLevel(
-          descriptor.extension[i], this, usedTopLevelNames, i));
+          descriptor.extension[i], this, usedExtensionNames, i));
     }
     for (ServiceDescriptorProto service in descriptor.service) {
       if (options.useGrpc) {
diff --git a/protoc_plugin/lib/names.dart b/protoc_plugin/lib/names.dart
index d85d757..0373187 100644
--- a/protoc_plugin/lib/names.dart
+++ b/protoc_plugin/lib/names.dart
@@ -199,6 +199,7 @@
 /// generated subclasses.
 Set<String> get reservedEnumNames => Set<String>()
   ..addAll(ProtobufEnum_reservedNames)
+  ..addAll(_dartReservedWords)
   ..addAll(_protobufEnumNames);
 
 Iterable<String> enumSuffixes() sync* {
@@ -446,13 +447,12 @@
 
 final _dartFieldNameExpr = RegExp(r'^[a-z]\w+$');
 
-/// Names that would collide with capitalized core Dart names as top-level
-/// identifiers.
-final List<String> toplevelReservedCapitalizedNames = const <String>[
+/// Names that would collide as top-level identifiers.
+final List<String> forbiddenTopLevelNames = <String>[
   'List',
   'Function',
   'Map',
-];
+]..addAll(_dartReservedWords);
 
 final List<String> reservedMemberNames = <String>[]
   ..addAll(_dartReservedWords)
diff --git a/protoc_plugin/pubspec.yaml b/protoc_plugin/pubspec.yaml
index 2eaa85e..1138584 100644
--- a/protoc_plugin/pubspec.yaml
+++ b/protoc_plugin/pubspec.yaml
@@ -1,5 +1,5 @@
 name: protoc_plugin
-version: 18.0.1
+version: 18.0.2
 author: Dart Team <misc@dartlang.org>
 description: Protoc compiler plugin to generate Dart code
 homepage: https://github.com/dart-lang/protobuf
diff --git a/protoc_plugin/test/generated_message_test.dart b/protoc_plugin/test/generated_message_test.dart
index c008f2d..c0db210 100755
--- a/protoc_plugin/test/generated_message_test.dart
+++ b/protoc_plugin/test/generated_message_test.dart
@@ -13,6 +13,8 @@
 import '../out/protos/google/protobuf/unittest_optimize_for.pb.dart';
 import '../out/protos/multiple_files_test.pb.dart';
 import '../out/protos/reserved_names.pb.dart';
+import '../out/protos/reserved_names_extension.pb.dart';
+import '../out/protos/reserved_names_message.pb.dart';
 import '../out/protos/duplicate_names_import.pb.dart';
 import '../out/protos/package1.pb.dart' as p1;
 import '../out/protos/package2.pb.dart' as p2;
@@ -694,6 +696,116 @@
     message.with_33 = 1;
   });
 
+  test('testReservedWordsRequired', () {
+    MessageWithReservedEnum message = MessageWithReservedEnum();
+    message.enum_1 = ReservedEnum.assert_;
+    message.enum_1 = ReservedEnum.break_;
+    message.enum_1 = ReservedEnum.case_;
+    message.enum_1 = ReservedEnum.catch_;
+    message.enum_1 = ReservedEnum.class_;
+    message.enum_1 = ReservedEnum.const_;
+    message.enum_1 = ReservedEnum.continue_;
+    message.enum_1 = ReservedEnum.default_;
+    message.enum_1 = ReservedEnum.do_;
+    message.enum_1 = ReservedEnum.else_;
+    message.enum_1 = ReservedEnum.enum_;
+    message.enum_1 = ReservedEnum.extends_;
+    message.enum_1 = ReservedEnum.false_;
+    message.enum_1 = ReservedEnum.final_;
+    message.enum_1 = ReservedEnum.finally_;
+    message.enum_1 = ReservedEnum.for_;
+    message.enum_1 = ReservedEnum.if_;
+    message.enum_1 = ReservedEnum.in_;
+    message.enum_1 = ReservedEnum.is_;
+    message.enum_1 = ReservedEnum.new_;
+    message.enum_1 = ReservedEnum.null_;
+    message.enum_1 = ReservedEnum.rethrow_;
+    message.enum_1 = ReservedEnum.return_;
+    message.enum_1 = ReservedEnum.super_;
+    message.enum_1 = ReservedEnum.switch_;
+    message.enum_1 = ReservedEnum.this_;
+    message.enum_1 = ReservedEnum.throw_;
+    message.enum_1 = ReservedEnum.true_;
+    message.enum_1 = ReservedEnum.try_;
+    message.enum_1 = ReservedEnum.var_;
+    message.enum_1 = ReservedEnum.void_;
+    message.enum_1 = ReservedEnum.while_;
+    message.enum_1 = ReservedEnum.with_;
+  });
+
+  test('testReservedWordsExtension', () {
+    ExtendMe message = ExtendMe();
+    message.setExtension(Reserved_names_extension.assert_1001, 1);
+    message.setExtension(Reserved_names_extension.break_1002, 1);
+    message.setExtension(Reserved_names_extension.case_1003, 1);
+    message.setExtension(Reserved_names_extension.catch_1004, 1);
+    message.setExtension(Reserved_names_extension.class_1005, 1);
+    message.setExtension(Reserved_names_extension.const_1006, 1);
+    message.setExtension(Reserved_names_extension.continue_1007, 1);
+    message.setExtension(Reserved_names_extension.default_1008, 1);
+    message.setExtension(Reserved_names_extension.do_1009, 1);
+    message.setExtension(Reserved_names_extension.else_1010, 1);
+    message.setExtension(Reserved_names_extension.enum_1011, 1);
+    message.setExtension(Reserved_names_extension.extends_1012, 1);
+    message.setExtension(Reserved_names_extension.false_1013, 1);
+    message.setExtension(Reserved_names_extension.final_1014, 1);
+    message.setExtension(Reserved_names_extension.finally_1015, 1);
+    message.setExtension(Reserved_names_extension.for_1016, 1);
+    message.setExtension(Reserved_names_extension.if_1017, 1);
+    message.setExtension(Reserved_names_extension.in_1018, 1);
+    message.setExtension(Reserved_names_extension.is_1019, 1);
+    message.setExtension(Reserved_names_extension.new_1020, 1);
+    message.setExtension(Reserved_names_extension.null_1021, 1);
+    message.setExtension(Reserved_names_extension.rethrow_1022, 1);
+    message.setExtension(Reserved_names_extension.return_1023, 1);
+    message.setExtension(Reserved_names_extension.super_1024, 1);
+    message.setExtension(Reserved_names_extension.switch_1025, 1);
+    message.setExtension(Reserved_names_extension.this_1026, 1);
+    message.setExtension(Reserved_names_extension.throw_1027, 1);
+    message.setExtension(Reserved_names_extension.true_1028, 1);
+    message.setExtension(Reserved_names_extension.try_1029, 1);
+    message.setExtension(Reserved_names_extension.var_1030, 1);
+    message.setExtension(Reserved_names_extension.void_1031, 1);
+    message.setExtension(Reserved_names_extension.while_1032, 1);
+    message.setExtension(Reserved_names_extension.with_1033, 1);
+  });
+
+  test('testReservedWordsMessage', () {
+    assert_();
+    break_();
+    case_();
+    catch_();
+    class_();
+    const_();
+    continue_();
+    default_();
+    do_();
+    else_();
+    enum_();
+    extends_();
+    false_();
+    final_();
+    finally_();
+    for_();
+    if_();
+    in_();
+    is_();
+    new_();
+    null_();
+    rethrow_();
+    return_();
+    super_();
+    switch_();
+    this_();
+    throw_();
+    true_();
+    try_();
+    var_();
+    void_();
+    while_();
+    with_();
+  });
+
   test('testImportDuplicatenames', () {
     M message = M();
     message.m1 = p1.M();
diff --git a/protoc_plugin/test/protos/reserved_names.proto b/protoc_plugin/test/protos/reserved_names.proto
index fcee7c5..dff00aa 100644
--- a/protoc_plugin/test/protos/reserved_names.proto
+++ b/protoc_plugin/test/protos/reserved_names.proto
@@ -251,3 +251,43 @@
   required int32 while = 32;
   required int32 with = 33;
 }
+
+message MessageWithReservedEnum {
+  optional ReservedEnum enum = 1;
+}
+
+enum ReservedEnum {
+  assert = 0;
+  break = 1;
+  case = 2;
+  catch = 3;
+  class = 4;
+  const = 5;
+  continue = 6;
+  default = 7;
+  do = 8;
+  else = 9;
+  enum = 10;
+  extends = 11;
+  false = 12;
+  final = 13;
+  finally = 14;
+  for = 15;
+  if = 16;
+  in = 17;
+  is = 18;
+  new = 19;
+  null = 20;
+  rethrow = 21;
+  return = 22;
+  super = 23;
+  switch = 24;
+  this = 25;
+  throw = 26;
+  true = 27;
+  try = 28;
+  var = 29;
+  void = 30;
+  while = 31;
+  with = 32;
+}
diff --git a/protoc_plugin/test/protos/reserved_names_extension.proto b/protoc_plugin/test/protos/reserved_names_extension.proto
new file mode 100644
index 0000000..bf43916
--- /dev/null
+++ b/protoc_plugin/test/protos/reserved_names_extension.proto
@@ -0,0 +1,47 @@
+// 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.
+
+syntax = "proto2";
+
+package reserved_names_extension;
+
+message ExtendMe {
+  extensions 1000 to max;
+}
+
+extend ExtendMe {
+  optional int32 assert = 1001;
+  optional int32 break = 1002;
+  optional int32 case = 1003;
+  optional int32 catch = 1004;
+  optional int32 class = 1005;
+  optional int32 const = 1006;
+  optional int32 continue = 1007;
+  optional int32 default = 1008;
+  optional int32 do = 1009;
+  optional int32 else = 1010;
+  optional int32 enum = 1011;
+  optional int32 extends = 1012;
+  optional int32 false = 1013;
+  optional int32 final = 1014;
+  optional int32 finally = 1015;
+  optional int32 for = 1016;
+  optional int32 if = 1017;
+  optional int32 in = 1018;
+  optional int32 is = 1019;
+  optional int32 new = 1020;
+  optional int32 null = 1021;
+  optional int32 rethrow = 1022;
+  optional int32 return = 1023;
+  optional int32 super = 1024;
+  optional int32 switch = 1025;
+  optional int32 this = 1026;
+  optional int32 throw = 1027;
+  optional int32 true = 1028;
+  optional int32 try = 1029;
+  optional int32 var = 1030;
+  optional int32 void = 1031;
+  optional int32 while = 1032;
+  optional int32 with = 1033;
+}
\ No newline at end of file
diff --git a/protoc_plugin/test/protos/reserved_names_message.proto b/protoc_plugin/test/protos/reserved_names_message.proto
new file mode 100644
index 0000000..aa072f5
--- /dev/null
+++ b/protoc_plugin/test/protos/reserved_names_message.proto
@@ -0,0 +1,74 @@
+// 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.
+
+syntax = "proto2";
+
+package reserved_names_messages;
+
+message assert {
+}
+message break {
+}
+message case {
+}
+message catch {
+}
+message class {
+}
+message const {
+}
+message continue {
+}
+message default {
+}
+message do {
+}
+message else {
+}
+message enum {
+}
+message extends {
+}
+message false {
+}
+message final {
+}
+message finally {
+}
+message for {
+}
+message if {
+}
+message in {
+}
+message is {
+}
+message new {
+}
+message null {
+}
+message rethrow {
+}
+message return {
+}
+message super {
+}
+message switch {
+}
+message this {
+}
+message throw {
+}
+message true {
+}
+message try {
+}
+message var {
+}
+message void {
+}
+message while {
+}
+message with {
+}
\ No newline at end of file