Rename mixin protos and add a check for undefined mixin name

ImportedMixins => Imports
imported_mixins => imports

Also regenerate checked-in code.

BUG=
R=frederikmutzel@google.com

Review URL: https://chromiumcodereview.appspot.com//2103743002 .
diff --git a/lib/code_generator.dart b/lib/code_generator.dart
index 2f3f92c..9c9182e 100644
--- a/lib/code_generator.dart
+++ b/lib/code_generator.dart
@@ -63,7 +63,7 @@
 
       // Generate the .pb.dart file if requested.
       for (var gen in generators) {
-        var name = gen._fileDescriptor.name;
+        var name = gen.descriptor.name;
         if (request.fileToGenerate.contains(name)) {
           response.file.addAll(gen.generateFiles(config));
         }
diff --git a/lib/file_generator.dart b/lib/file_generator.dart
index a921786..8f8d2f2 100644
--- a/lib/file_generator.dart
+++ b/lib/file_generator.dart
@@ -18,15 +18,14 @@
   /// Does not check for existence of import files or classes.
   static Map<String, PbMixin> _getDeclaredMixins(FileDescriptorProto desc) {
     String mixinError(String error) =>
-        'Option "mixins" in file ${desc.name}: $error';
+        'Option "mixins" in ${desc.name}: $error';
 
     if (!desc.hasOptions() ||
-        !desc.options.hasExtension(Dart_options.importedMixins)) {
+        !desc.options.hasExtension(Dart_options.imports)) {
       return <String, PbMixin>{};
     }
     var dartMixins = <String, DartMixin>{};
-    ImportedMixins importedMixins =
-        desc.options.getExtension(Dart_options.importedMixins);
+    Imports importedMixins = desc.options.getExtension(Dart_options.imports);
     for (DartMixin mixin in importedMixins.mixins) {
       if (dartMixins.containsKey(mixin.name)) {
         throw mixinError('Duplicate mixin name: "${mixin.name}"');
@@ -89,7 +88,7 @@
     return pbMixins;
   }
 
-  final FileDescriptorProto _fileDescriptor;
+  final FileDescriptorProto descriptor;
 
   // The relative path used to import the .proto file, as a URI.
   final Uri protoFileUri;
@@ -104,7 +103,7 @@
   bool _linked = false;
 
   FileGenerator(FileDescriptorProto descriptor)
-      : _fileDescriptor = descriptor,
+      : descriptor = descriptor,
         protoFileUri = new Uri.file(descriptor.name) {
     if (protoFileUri.isAbsolute) {
       // protoc should never generate an import with an absolute path.
@@ -122,17 +121,17 @@
     }
 
     // Load and register all enum and message types.
-    for (EnumDescriptorProto enumType in _fileDescriptor.enumType) {
+    for (EnumDescriptorProto enumType in descriptor.enumType) {
       enumGenerators.add(new EnumGenerator(enumType, this));
     }
-    for (DescriptorProto messageType in _fileDescriptor.messageType) {
+    for (DescriptorProto messageType in descriptor.messageType) {
       messageGenerators.add(new MessageGenerator(
           messageType, this, declaredMixins, defaultMixin));
     }
-    for (FieldDescriptorProto extension in _fileDescriptor.extension) {
+    for (FieldDescriptorProto extension in descriptor.extension) {
       extensionGenerators.add(new ExtensionGenerator(extension, this));
     }
-    for (ServiceDescriptorProto service in _fileDescriptor.service) {
+    for (ServiceDescriptorProto service in descriptor.service) {
       var serviceGen = new ServiceGenerator(service, this);
       serviceGenerators.add(serviceGen);
       clientApiGenerators.add(new ClientApiGenerator(serviceGen));
@@ -154,9 +153,9 @@
     _linked = true;
   }
 
-  String get package => _fileDescriptor.package;
+  String get package => descriptor.package;
   String get classname => '';
-  String get fqname => '.${_fileDescriptor.package}';
+  String get fqname => '.${descriptor.package}';
   FileGenerator get fileGen => this;
 
   // Extract the filename from a URI and remove the extension.
@@ -176,7 +175,7 @@
     if (!_linked) throw new StateError("not linked");
 
     makeFile(String extension, String content) {
-      Uri protoUrl = new Uri.file(_fileDescriptor.name);
+      Uri protoUrl = new Uri.file(descriptor.name);
       Uri dartUrl = config.outputPathFor(protoUrl, extension);
       return new CodeGeneratorResponse_File()
         ..name = dartUrl.path
@@ -235,7 +234,7 @@
 
     // We only add the dart:async import if there are services in the
     // FileDescriptorProto.
-    if (_fileDescriptor.service.isNotEmpty) {
+    if (descriptor.service.isNotEmpty) {
       out.println("import 'dart:async';\n");
     }
 
@@ -461,7 +460,7 @@
   ///
   /// (This should be unique to avoid warnings about duplicate Dart libraries.)
   void _writeLibraryHeading(IndentingWriter out, [String extension]) {
-    Uri filePath = new Uri.file(_fileDescriptor.name);
+    Uri filePath = new Uri.file(descriptor.name);
     if (filePath.isAbsolute) {
       // protoc should never generate a file descriptor with an absolute path.
       throw "FAILURE: File with an absolute path is not supported";
@@ -469,11 +468,11 @@
 
     var libraryName = _fileNameWithoutExtension(filePath).replaceAll('-', '_');
     if (extension != null) libraryName += "_$extension";
-    if (_fileDescriptor.package != '') {
+    if (descriptor.package != '') {
       // Two .protos can be in the same proto package.
       // It isn't unique enough to use as a Dart library name.
       // But we can prepend it.
-      libraryName = _fileDescriptor.package + "_" + libraryName;
+      libraryName = descriptor.package + "_" + libraryName;
     }
     out.println('''
 ///
diff --git a/lib/linker.dart b/lib/linker.dart
index 5bca6d9..fa1ab9d 100644
--- a/lib/linker.dart
+++ b/lib/linker.dart
@@ -48,7 +48,7 @@
   /// Makes info about a .pb.dart file available for reference,
   /// using the filename given to us by protoc.
   void registerProtoFile(FileGenerator f) {
-    _files[f._fileDescriptor.name] = f;
+    _files[f.descriptor.name] = f;
   }
 
   /// Makes a message, group, or enum available for reference.
diff --git a/lib/message_generator.dart b/lib/message_generator.dart
index 40c6028..1177151 100644
--- a/lib/message_generator.dart
+++ b/lib/message_generator.dart
@@ -9,19 +9,19 @@
   ///
   /// First searches [declaredMixins], then internal mixins declared by
   /// [findMixin].
-  static PbMixin _getMixin(DescriptorProto desc,
+  static PbMixin _getMixin(DescriptorProto desc, FileDescriptorProto file,
       Map<String, PbMixin> declaredMixins, PbMixin defaultMixin) {
-    PbMixin getMixinByName(String name) {
-      if (name.isEmpty) return null; // don't use a mixin (override any default)
-      return declaredMixins[name] ?? findMixin(name);
-    }
-
     if (!desc.hasOptions() || !desc.options.hasExtension(Dart_options.mixin)) {
       return defaultMixin;
     }
 
     String name = desc.options.getExtension(Dart_options.mixin);
-    return getMixinByName(name);
+    if (name.isEmpty) return null; // don't use any mixins (override default)
+    var mixin = declaredMixins[name] ?? findMixin(name);
+    if (mixin == null) {
+      throw '${desc.name} in ${file.name}: mixin "$name" not found';
+    }
+    return mixin;
   }
 
   final String classname;
@@ -49,7 +49,8 @@
             : (parent.fqname == '.'
                 ? '.${descriptor.name}'
                 : '${parent.fqname}.${descriptor.name}'),
-        mixin = _getMixin(descriptor, declaredMixins, defaultMixin) {
+        mixin = _getMixin(descriptor, parent.fileGen.descriptor, declaredMixins,
+            defaultMixin) {
     for (EnumDescriptorProto e in _descriptor.enumType) {
       _enumGenerators.add(new EnumGenerator(e, this));
     }
diff --git a/lib/src/dart_options.pb.dart b/lib/src/dart_options.pb.dart
index 92961dd..b843737 100644
--- a/lib/src/dart_options.pb.dart
+++ b/lib/src/dart_options.pb.dart
@@ -5,30 +5,6 @@
 
 import 'package:protobuf/protobuf.dart';
 
-class DartOptions extends GeneratedMessage {
-  static final BuilderInfo _i = new BuilderInfo('DartOptions')
-    ..hasRequiredFields = false
-  ;
-
-  DartOptions() : super();
-  DartOptions.fromBuffer(List<int> i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
-  DartOptions.fromJson(String i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
-  DartOptions clone() => new DartOptions()..mergeFromMessage(this);
-  BuilderInfo get info_ => _i;
-  static DartOptions create() => new DartOptions();
-  static PbList<DartOptions> createRepeated() => new PbList<DartOptions>();
-  static DartOptions getDefault() {
-    if (_defaultInstance == null) _defaultInstance = new _ReadonlyDartOptions();
-    return _defaultInstance;
-  }
-  static DartOptions _defaultInstance;
-  static void $checkItem(DartOptions v) {
-    if (v is !DartOptions) checkItemFailed(v, 'DartOptions');
-  }
-}
-
-class _ReadonlyDartOptions extends DartOptions with ReadonlyMessageMixin {}
-
 class DartMixin extends GeneratedMessage {
   static final BuilderInfo _i = new BuilderInfo('DartMixin')
     ..a/*<String>*/(1, 'name', PbFieldType.OS)
@@ -71,44 +47,42 @@
 
 class _ReadonlyDartMixin extends DartMixin with ReadonlyMessageMixin {}
 
-class ImportedMixins extends GeneratedMessage {
-  static final BuilderInfo _i = new BuilderInfo('ImportedMixins')
+class Imports extends GeneratedMessage {
+  static final BuilderInfo _i = new BuilderInfo('Imports')
     ..pp/*<DartMixin>*/(1, 'mixins', PbFieldType.PM, DartMixin.$checkItem, DartMixin.create)
     ..hasRequiredFields = false
   ;
 
-  ImportedMixins() : super();
-  ImportedMixins.fromBuffer(List<int> i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
-  ImportedMixins.fromJson(String i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
-  ImportedMixins clone() => new ImportedMixins()..mergeFromMessage(this);
+  Imports() : super();
+  Imports.fromBuffer(List<int> i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
+  Imports.fromJson(String i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
+  Imports clone() => new Imports()..mergeFromMessage(this);
   BuilderInfo get info_ => _i;
-  static ImportedMixins create() => new ImportedMixins();
-  static PbList<ImportedMixins> createRepeated() => new PbList<ImportedMixins>();
-  static ImportedMixins getDefault() {
-    if (_defaultInstance == null) _defaultInstance = new _ReadonlyImportedMixins();
+  static Imports create() => new Imports();
+  static PbList<Imports> createRepeated() => new PbList<Imports>();
+  static Imports getDefault() {
+    if (_defaultInstance == null) _defaultInstance = new _ReadonlyImports();
     return _defaultInstance;
   }
-  static ImportedMixins _defaultInstance;
-  static void $checkItem(ImportedMixins v) {
-    if (v is !ImportedMixins) checkItemFailed(v, 'ImportedMixins');
+  static Imports _defaultInstance;
+  static void $checkItem(Imports v) {
+    if (v is !Imports) checkItemFailed(v, 'Imports');
   }
 
   List<DartMixin> get mixins => $_get(0, 1, null);
 }
 
-class _ReadonlyImportedMixins extends ImportedMixins with ReadonlyMessageMixin {}
+class _ReadonlyImports extends Imports with ReadonlyMessageMixin {}
 
 class Dart_options {
-  static final Extension importedMixins = new Extension<ImportedMixins>('FileOptions', 'importedMixins', 28125061, PbFieldType.OM, ImportedMixins.getDefault, ImportedMixins.create);
+  static final Extension imports = new Extension<Imports>('FileOptions', 'imports', 28125061, PbFieldType.OM, Imports.getDefault, Imports.create);
   static final Extension defaultMixin = new Extension<String>('FileOptions', 'defaultMixin', 96128839, PbFieldType.OS);
   static final Extension mixin = new Extension<String>('MessageOptions', 'mixin', 96128839, PbFieldType.OS);
-  static final Extension override = new Extension<bool>('FieldOptions', 'override', 28205290, PbFieldType.OB);
   static final Extension dartName = new Extension<String>('FieldOptions', 'dartName', 28700919, PbFieldType.OS);
   static void registerAllExtensions(ExtensionRegistry registry) {
-    registry.add(importedMixins);
+    registry.add(imports);
     registry.add(defaultMixin);
     registry.add(mixin);
-    registry.add(override);
     registry.add(dartName);
   }
 }
diff --git a/lib/src/descriptor.pb.dart b/lib/src/descriptor.pb.dart
index 228d477..63980a9 100644
--- a/lib/src/descriptor.pb.dart
+++ b/lib/src/descriptor.pb.dart
@@ -6,6 +6,10 @@
 import 'package:fixnum/fixnum.dart';
 import 'package:protobuf/protobuf.dart';
 
+import 'descriptor.pbenum.dart';
+
+export 'descriptor.pbenum.dart';
+
 class FileDescriptorSet extends GeneratedMessage {
   static final BuilderInfo _i = new BuilderInfo('FileDescriptorSet')
     ..pp/*<FileDescriptorProto>*/(1, 'file', PbFieldType.PM, FileDescriptorProto.$checkItem, FileDescriptorProto.create)
@@ -186,76 +190,6 @@
 
 class _ReadonlyDescriptorProto extends DescriptorProto with ReadonlyMessageMixin {}
 
-class FieldDescriptorProto_Type extends ProtobufEnum {
-  static const FieldDescriptorProto_Type TYPE_DOUBLE = const FieldDescriptorProto_Type._(1, 'TYPE_DOUBLE');
-  static const FieldDescriptorProto_Type TYPE_FLOAT = const FieldDescriptorProto_Type._(2, 'TYPE_FLOAT');
-  static const FieldDescriptorProto_Type TYPE_INT64 = const FieldDescriptorProto_Type._(3, 'TYPE_INT64');
-  static const FieldDescriptorProto_Type TYPE_UINT64 = const FieldDescriptorProto_Type._(4, 'TYPE_UINT64');
-  static const FieldDescriptorProto_Type TYPE_INT32 = const FieldDescriptorProto_Type._(5, 'TYPE_INT32');
-  static const FieldDescriptorProto_Type TYPE_FIXED64 = const FieldDescriptorProto_Type._(6, 'TYPE_FIXED64');
-  static const FieldDescriptorProto_Type TYPE_FIXED32 = const FieldDescriptorProto_Type._(7, 'TYPE_FIXED32');
-  static const FieldDescriptorProto_Type TYPE_BOOL = const FieldDescriptorProto_Type._(8, 'TYPE_BOOL');
-  static const FieldDescriptorProto_Type TYPE_STRING = const FieldDescriptorProto_Type._(9, 'TYPE_STRING');
-  static const FieldDescriptorProto_Type TYPE_GROUP = const FieldDescriptorProto_Type._(10, 'TYPE_GROUP');
-  static const FieldDescriptorProto_Type TYPE_MESSAGE = const FieldDescriptorProto_Type._(11, 'TYPE_MESSAGE');
-  static const FieldDescriptorProto_Type TYPE_BYTES = const FieldDescriptorProto_Type._(12, 'TYPE_BYTES');
-  static const FieldDescriptorProto_Type TYPE_UINT32 = const FieldDescriptorProto_Type._(13, 'TYPE_UINT32');
-  static const FieldDescriptorProto_Type TYPE_ENUM = const FieldDescriptorProto_Type._(14, 'TYPE_ENUM');
-  static const FieldDescriptorProto_Type TYPE_SFIXED32 = const FieldDescriptorProto_Type._(15, 'TYPE_SFIXED32');
-  static const FieldDescriptorProto_Type TYPE_SFIXED64 = const FieldDescriptorProto_Type._(16, 'TYPE_SFIXED64');
-  static const FieldDescriptorProto_Type TYPE_SINT32 = const FieldDescriptorProto_Type._(17, 'TYPE_SINT32');
-  static const FieldDescriptorProto_Type TYPE_SINT64 = const FieldDescriptorProto_Type._(18, 'TYPE_SINT64');
-
-  static const List<FieldDescriptorProto_Type> values = const <FieldDescriptorProto_Type> [
-    TYPE_DOUBLE,
-    TYPE_FLOAT,
-    TYPE_INT64,
-    TYPE_UINT64,
-    TYPE_INT32,
-    TYPE_FIXED64,
-    TYPE_FIXED32,
-    TYPE_BOOL,
-    TYPE_STRING,
-    TYPE_GROUP,
-    TYPE_MESSAGE,
-    TYPE_BYTES,
-    TYPE_UINT32,
-    TYPE_ENUM,
-    TYPE_SFIXED32,
-    TYPE_SFIXED64,
-    TYPE_SINT32,
-    TYPE_SINT64,
-  ];
-
-  static final Map<int, dynamic> _byValue = ProtobufEnum.initByValue(values);
-  static FieldDescriptorProto_Type valueOf(int value) => _byValue[value] as FieldDescriptorProto_Type;
-  static void $checkItem(FieldDescriptorProto_Type v) {
-    if (v is !FieldDescriptorProto_Type) checkItemFailed(v, 'FieldDescriptorProto_Type');
-  }
-
-  const FieldDescriptorProto_Type._(int v, String n) : super(v, n);
-}
-
-class FieldDescriptorProto_Label extends ProtobufEnum {
-  static const FieldDescriptorProto_Label LABEL_OPTIONAL = const FieldDescriptorProto_Label._(1, 'LABEL_OPTIONAL');
-  static const FieldDescriptorProto_Label LABEL_REQUIRED = const FieldDescriptorProto_Label._(2, 'LABEL_REQUIRED');
-  static const FieldDescriptorProto_Label LABEL_REPEATED = const FieldDescriptorProto_Label._(3, 'LABEL_REPEATED');
-
-  static const List<FieldDescriptorProto_Label> values = const <FieldDescriptorProto_Label> [
-    LABEL_OPTIONAL,
-    LABEL_REQUIRED,
-    LABEL_REPEATED,
-  ];
-
-  static final Map<int, dynamic> _byValue = ProtobufEnum.initByValue(values);
-  static FieldDescriptorProto_Label valueOf(int value) => _byValue[value] as FieldDescriptorProto_Label;
-  static void $checkItem(FieldDescriptorProto_Label v) {
-    if (v is !FieldDescriptorProto_Label) checkItemFailed(v, 'FieldDescriptorProto_Label');
-  }
-
-  const FieldDescriptorProto_Label._(int v, String n) : super(v, n);
-}
-
 class FieldDescriptorProto extends GeneratedMessage {
   static final BuilderInfo _i = new BuilderInfo('FieldDescriptorProto')
     ..a/*<String>*/(1, 'name', PbFieldType.OS)
@@ -541,26 +475,6 @@
 
 class _ReadonlyStreamDescriptorProto extends StreamDescriptorProto with ReadonlyMessageMixin {}
 
-class FileOptions_OptimizeMode extends ProtobufEnum {
-  static const FileOptions_OptimizeMode SPEED = const FileOptions_OptimizeMode._(1, 'SPEED');
-  static const FileOptions_OptimizeMode CODE_SIZE = const FileOptions_OptimizeMode._(2, 'CODE_SIZE');
-  static const FileOptions_OptimizeMode LITE_RUNTIME = const FileOptions_OptimizeMode._(3, 'LITE_RUNTIME');
-
-  static const List<FileOptions_OptimizeMode> values = const <FileOptions_OptimizeMode> [
-    SPEED,
-    CODE_SIZE,
-    LITE_RUNTIME,
-  ];
-
-  static final Map<int, dynamic> _byValue = ProtobufEnum.initByValue(values);
-  static FileOptions_OptimizeMode valueOf(int value) => _byValue[value] as FileOptions_OptimizeMode;
-  static void $checkItem(FileOptions_OptimizeMode v) {
-    if (v is !FileOptions_OptimizeMode) checkItemFailed(v, 'FileOptions_OptimizeMode');
-  }
-
-  const FileOptions_OptimizeMode._(int v, String n) : super(v, n);
-}
-
 class FileOptions extends GeneratedMessage {
   static final BuilderInfo _i = new BuilderInfo('FileOptions')
     ..a/*<String>*/(1, 'javaPackage', PbFieldType.OS)
@@ -675,22 +589,6 @@
 
 class _ReadonlyMessageOptions extends MessageOptions with ReadonlyMessageMixin {}
 
-class FieldOptions_CType extends ProtobufEnum {
-  static const FieldOptions_CType STRING = const FieldOptions_CType._(0, 'STRING');
-
-  static const List<FieldOptions_CType> values = const <FieldOptions_CType> [
-    STRING,
-  ];
-
-  static final Map<int, dynamic> _byValue = ProtobufEnum.initByValue(values);
-  static FieldOptions_CType valueOf(int value) => _byValue[value] as FieldOptions_CType;
-  static void $checkItem(FieldOptions_CType v) {
-    if (v is !FieldOptions_CType) checkItemFailed(v, 'FieldOptions_CType');
-  }
-
-  const FieldOptions_CType._(int v, String n) : super(v, n);
-}
-
 class FieldOptions extends GeneratedMessage {
   static final BuilderInfo _i = new BuilderInfo('FieldOptions')
     ..e/*<FieldOptions_CType>*/(1, 'ctype', PbFieldType.OE, FieldOptions_CType.STRING, FieldOptions_CType.valueOf)
@@ -1043,309 +941,3 @@
 
 class _ReadonlySourceCodeInfo extends SourceCodeInfo with ReadonlyMessageMixin {}
 
-const FileDescriptorSet$json = const {
-  '1': 'FileDescriptorSet',
-  '2': const [
-    const {'1': 'file', '3': 1, '4': 3, '5': 11, '6': '.proto2.FileDescriptorProto'},
-  ],
-};
-
-const FileDescriptorProto$json = const {
-  '1': 'FileDescriptorProto',
-  '2': const [
-    const {'1': 'name', '3': 1, '4': 1, '5': 9},
-    const {'1': 'package', '3': 2, '4': 1, '5': 9},
-    const {'1': 'dependency', '3': 3, '4': 3, '5': 9},
-    const {'1': 'public_dependency', '3': 10, '4': 3, '5': 5},
-    const {'1': 'weak_dependency', '3': 11, '4': 3, '5': 5},
-    const {'1': 'message_type', '3': 4, '4': 3, '5': 11, '6': '.proto2.DescriptorProto'},
-    const {'1': 'enum_type', '3': 5, '4': 3, '5': 11, '6': '.proto2.EnumDescriptorProto'},
-    const {'1': 'service', '3': 6, '4': 3, '5': 11, '6': '.proto2.ServiceDescriptorProto'},
-    const {'1': 'extension', '3': 7, '4': 3, '5': 11, '6': '.proto2.FieldDescriptorProto'},
-    const {'1': 'options', '3': 8, '4': 1, '5': 11, '6': '.proto2.FileOptions'},
-    const {'1': 'source_code_info', '3': 9, '4': 1, '5': 11, '6': '.proto2.SourceCodeInfo'},
-  ],
-};
-
-const DescriptorProto$json = const {
-  '1': 'DescriptorProto',
-  '2': const [
-    const {'1': 'name', '3': 1, '4': 1, '5': 9},
-    const {'1': 'field', '3': 2, '4': 3, '5': 11, '6': '.proto2.FieldDescriptorProto'},
-    const {'1': 'extension', '3': 6, '4': 3, '5': 11, '6': '.proto2.FieldDescriptorProto'},
-    const {'1': 'nested_type', '3': 3, '4': 3, '5': 11, '6': '.proto2.DescriptorProto'},
-    const {'1': 'enum_type', '3': 4, '4': 3, '5': 11, '6': '.proto2.EnumDescriptorProto'},
-    const {'1': 'extension_range', '3': 5, '4': 3, '5': 11, '6': '.proto2.DescriptorProto.ExtensionRange'},
-    const {'1': 'options', '3': 7, '4': 1, '5': 11, '6': '.proto2.MessageOptions'},
-  ],
-  '3': const [DescriptorProto_ExtensionRange$json],
-};
-
-const DescriptorProto_ExtensionRange$json = const {
-  '1': 'ExtensionRange',
-  '2': const [
-    const {'1': 'start', '3': 1, '4': 1, '5': 5},
-    const {'1': 'end', '3': 2, '4': 1, '5': 5},
-  ],
-};
-
-const FieldDescriptorProto$json = const {
-  '1': 'FieldDescriptorProto',
-  '2': const [
-    const {'1': 'name', '3': 1, '4': 1, '5': 9},
-    const {'1': 'number', '3': 3, '4': 1, '5': 5},
-    const {'1': 'label', '3': 4, '4': 1, '5': 14, '6': '.proto2.FieldDescriptorProto.Label'},
-    const {'1': 'type', '3': 5, '4': 1, '5': 14, '6': '.proto2.FieldDescriptorProto.Type'},
-    const {'1': 'type_name', '3': 6, '4': 1, '5': 9},
-    const {'1': 'extendee', '3': 2, '4': 1, '5': 9},
-    const {'1': 'default_value', '3': 7, '4': 1, '5': 9},
-    const {'1': 'options', '3': 8, '4': 1, '5': 11, '6': '.proto2.FieldOptions'},
-  ],
-  '4': const [FieldDescriptorProto_Type$json, FieldDescriptorProto_Label$json],
-};
-
-const FieldDescriptorProto_Type$json = const {
-  '1': 'Type',
-  '2': const [
-    const {'1': 'TYPE_DOUBLE', '2': 1},
-    const {'1': 'TYPE_FLOAT', '2': 2},
-    const {'1': 'TYPE_INT64', '2': 3},
-    const {'1': 'TYPE_UINT64', '2': 4},
-    const {'1': 'TYPE_INT32', '2': 5},
-    const {'1': 'TYPE_FIXED64', '2': 6},
-    const {'1': 'TYPE_FIXED32', '2': 7},
-    const {'1': 'TYPE_BOOL', '2': 8},
-    const {'1': 'TYPE_STRING', '2': 9},
-    const {'1': 'TYPE_GROUP', '2': 10},
-    const {'1': 'TYPE_MESSAGE', '2': 11},
-    const {'1': 'TYPE_BYTES', '2': 12},
-    const {'1': 'TYPE_UINT32', '2': 13},
-    const {'1': 'TYPE_ENUM', '2': 14},
-    const {'1': 'TYPE_SFIXED32', '2': 15},
-    const {'1': 'TYPE_SFIXED64', '2': 16},
-    const {'1': 'TYPE_SINT32', '2': 17},
-    const {'1': 'TYPE_SINT64', '2': 18},
-  ],
-};
-
-const FieldDescriptorProto_Label$json = const {
-  '1': 'Label',
-  '2': const [
-    const {'1': 'LABEL_OPTIONAL', '2': 1},
-    const {'1': 'LABEL_REQUIRED', '2': 2},
-    const {'1': 'LABEL_REPEATED', '2': 3},
-  ],
-};
-
-const EnumDescriptorProto$json = const {
-  '1': 'EnumDescriptorProto',
-  '2': const [
-    const {'1': 'name', '3': 1, '4': 1, '5': 9},
-    const {'1': 'value', '3': 2, '4': 3, '5': 11, '6': '.proto2.EnumValueDescriptorProto'},
-    const {'1': 'options', '3': 3, '4': 1, '5': 11, '6': '.proto2.EnumOptions'},
-  ],
-};
-
-const EnumValueDescriptorProto$json = const {
-  '1': 'EnumValueDescriptorProto',
-  '2': const [
-    const {'1': 'name', '3': 1, '4': 1, '5': 9},
-    const {'1': 'number', '3': 2, '4': 1, '5': 5},
-    const {'1': 'options', '3': 3, '4': 1, '5': 11, '6': '.proto2.EnumValueOptions'},
-  ],
-};
-
-const ServiceDescriptorProto$json = const {
-  '1': 'ServiceDescriptorProto',
-  '2': const [
-    const {'1': 'name', '3': 1, '4': 1, '5': 9},
-    const {'1': 'method', '3': 2, '4': 3, '5': 11, '6': '.proto2.MethodDescriptorProto'},
-    const {'1': 'stream', '3': 4, '4': 3, '5': 11, '6': '.proto2.StreamDescriptorProto'},
-    const {'1': 'options', '3': 3, '4': 1, '5': 11, '6': '.proto2.ServiceOptions'},
-  ],
-};
-
-const MethodDescriptorProto$json = const {
-  '1': 'MethodDescriptorProto',
-  '2': const [
-    const {'1': 'name', '3': 1, '4': 1, '5': 9},
-    const {'1': 'input_type', '3': 2, '4': 1, '5': 9},
-    const {'1': 'output_type', '3': 3, '4': 1, '5': 9},
-    const {'1': 'options', '3': 4, '4': 1, '5': 11, '6': '.proto2.MethodOptions'},
-  ],
-};
-
-const StreamDescriptorProto$json = const {
-  '1': 'StreamDescriptorProto',
-  '2': const [
-    const {'1': 'name', '3': 1, '4': 1, '5': 9},
-    const {'1': 'client_message_type', '3': 2, '4': 1, '5': 9},
-    const {'1': 'server_message_type', '3': 3, '4': 1, '5': 9},
-    const {'1': 'options', '3': 4, '4': 1, '5': 11, '6': '.proto2.StreamOptions'},
-  ],
-};
-
-const FileOptions$json = const {
-  '1': 'FileOptions',
-  '2': const [
-    const {'1': 'java_package', '3': 1, '4': 1, '5': 9},
-    const {'1': 'java_outer_classname', '3': 8, '4': 1, '5': 9},
-    const {'1': 'java_multiple_files', '3': 10, '4': 1, '5': 8, '7': 'false'},
-    const {'1': 'java_generate_equals_and_hash', '3': 20, '4': 1, '5': 8, '7': 'false'},
-    const {'1': 'optimize_for', '3': 9, '4': 1, '5': 14, '6': '.proto2.FileOptions.OptimizeMode', '7': 'SPEED'},
-    const {'1': 'cc_generic_services', '3': 16, '4': 1, '5': 8, '7': 'false'},
-    const {'1': 'java_generic_services', '3': 17, '4': 1, '5': 8, '7': 'false'},
-    const {'1': 'py_generic_services', '3': 18, '4': 1, '5': 8, '7': 'false'},
-    const {'1': 'uninterpreted_option', '3': 999, '4': 3, '5': 11, '6': '.proto2.UninterpretedOption'},
-  ],
-  '4': const [FileOptions_OptimizeMode$json],
-  '5': const [
-    const {'1': 1000, '2': 536870912},
-  ],
-};
-
-const FileOptions_OptimizeMode$json = const {
-  '1': 'OptimizeMode',
-  '2': const [
-    const {'1': 'SPEED', '2': 1},
-    const {'1': 'CODE_SIZE', '2': 2},
-    const {'1': 'LITE_RUNTIME', '2': 3},
-  ],
-};
-
-const MessageOptions$json = const {
-  '1': 'MessageOptions',
-  '2': const [
-    const {'1': 'message_set_wire_format', '3': 1, '4': 1, '5': 8, '7': 'false'},
-    const {'1': 'no_standard_descriptor_accessor', '3': 2, '4': 1, '5': 8, '7': 'false'},
-    const {'1': 'uninterpreted_option', '3': 999, '4': 3, '5': 11, '6': '.proto2.UninterpretedOption'},
-  ],
-  '5': const [
-    const {'1': 1000, '2': 536870912},
-  ],
-};
-
-const FieldOptions$json = const {
-  '1': 'FieldOptions',
-  '2': const [
-    const {'1': 'ctype', '3': 1, '4': 1, '5': 14, '6': '.proto2.FieldOptions.CType', '7': 'STRING'},
-    const {'1': 'packed', '3': 2, '4': 1, '5': 8},
-    const {'1': 'lazy', '3': 5, '4': 1, '5': 8, '7': 'false'},
-    const {'1': 'deprecated', '3': 3, '4': 1, '5': 8, '7': 'false'},
-    const {'1': 'experimental_map_key', '3': 9, '4': 1, '5': 9},
-    const {'1': 'uninterpreted_option', '3': 999, '4': 3, '5': 11, '6': '.proto2.UninterpretedOption'},
-  ],
-  '4': const [FieldOptions_CType$json],
-  '5': const [
-    const {'1': 1000, '2': 536870912},
-  ],
-};
-
-const FieldOptions_CType$json = const {
-  '1': 'CType',
-  '2': const [
-    const {'1': 'STRING', '2': 0},
-  ],
-};
-
-const EnumOptions$json = const {
-  '1': 'EnumOptions',
-  '2': const [
-    const {'1': 'allow_alias', '3': 2, '4': 1, '5': 8, '7': 'true'},
-    const {'1': 'uninterpreted_option', '3': 999, '4': 3, '5': 11, '6': '.proto2.UninterpretedOption'},
-  ],
-  '5': const [
-    const {'1': 1000, '2': 536870912},
-  ],
-};
-
-const EnumValueOptions$json = const {
-  '1': 'EnumValueOptions',
-  '2': const [
-    const {'1': 'uninterpreted_option', '3': 999, '4': 3, '5': 11, '6': '.proto2.UninterpretedOption'},
-  ],
-  '5': const [
-    const {'1': 1000, '2': 536870912},
-  ],
-};
-
-const ServiceOptions$json = const {
-  '1': 'ServiceOptions',
-  '2': const [
-    const {'1': 'uninterpreted_option', '3': 999, '4': 3, '5': 11, '6': '.proto2.UninterpretedOption'},
-  ],
-  '5': const [
-    const {'1': 1000, '2': 536870912},
-  ],
-};
-
-const MethodOptions$json = const {
-  '1': 'MethodOptions',
-  '2': const [
-    const {'1': 'uninterpreted_option', '3': 999, '4': 3, '5': 11, '6': '.proto2.UninterpretedOption'},
-  ],
-  '5': const [
-    const {'1': 1000, '2': 536870912},
-  ],
-};
-
-const StreamOptions$json = const {
-  '1': 'StreamOptions',
-  '2': const [
-    const {'1': 'uninterpreted_option', '3': 999, '4': 3, '5': 11, '6': '.proto2.UninterpretedOption'},
-  ],
-  '5': const [
-    const {'1': 1000, '2': 536870912},
-  ],
-};
-
-const UninterpretedOption$json = const {
-  '1': 'UninterpretedOption',
-  '2': const [
-    const {'1': 'name', '3': 2, '4': 3, '5': 11, '6': '.proto2.UninterpretedOption.NamePart'},
-    const {'1': 'identifier_value', '3': 3, '4': 1, '5': 9},
-    const {'1': 'positive_int_value', '3': 4, '4': 1, '5': 4},
-    const {'1': 'negative_int_value', '3': 5, '4': 1, '5': 3},
-    const {'1': 'double_value', '3': 6, '4': 1, '5': 1},
-    const {'1': 'string_value', '3': 7, '4': 1, '5': 12},
-    const {'1': 'aggregate_value', '3': 8, '4': 1, '5': 9},
-  ],
-  '3': const [UninterpretedOption_NamePart$json],
-};
-
-const UninterpretedOption_NamePart$json = const {
-  '1': 'NamePart',
-  '2': const [
-    const {'1': 'name_part', '3': 1, '4': 2, '5': 9},
-    const {'1': 'is_extension', '3': 2, '4': 2, '5': 8},
-  ],
-};
-
-const SourceCodeInfo$json = const {
-  '1': 'SourceCodeInfo',
-  '2': const [
-    const {'1': 'location', '3': 1, '4': 3, '5': 11, '6': '.proto2.SourceCodeInfo.Location'},
-  ],
-  '3': const [SourceCodeInfo_Location$json],
-};
-
-const SourceCodeInfo_Location$json = const {
-  '1': 'Location',
-  '2': const [
-    const {
-      '1': 'path',
-      '3': 1,
-      '4': 3,
-      '5': 5,
-      '8': const {'2': true},
-    },
-    const {
-      '1': 'span',
-      '3': 2,
-      '4': 3,
-      '5': 5,
-      '8': const {'2': true},
-    },
-  ],
-};
-
diff --git a/lib/src/descriptor.pbenum.dart b/lib/src/descriptor.pbenum.dart
new file mode 100644
index 0000000..a817340
--- /dev/null
+++ b/lib/src/descriptor.pbenum.dart
@@ -0,0 +1,113 @@
+///
+//  Generated code. Do not modify.
+///
+library proto2_descriptor_pbenum;
+
+import 'package:protobuf/protobuf.dart';
+
+class FieldDescriptorProto_Type extends ProtobufEnum {
+  static const FieldDescriptorProto_Type TYPE_DOUBLE = const FieldDescriptorProto_Type._(1, 'TYPE_DOUBLE');
+  static const FieldDescriptorProto_Type TYPE_FLOAT = const FieldDescriptorProto_Type._(2, 'TYPE_FLOAT');
+  static const FieldDescriptorProto_Type TYPE_INT64 = const FieldDescriptorProto_Type._(3, 'TYPE_INT64');
+  static const FieldDescriptorProto_Type TYPE_UINT64 = const FieldDescriptorProto_Type._(4, 'TYPE_UINT64');
+  static const FieldDescriptorProto_Type TYPE_INT32 = const FieldDescriptorProto_Type._(5, 'TYPE_INT32');
+  static const FieldDescriptorProto_Type TYPE_FIXED64 = const FieldDescriptorProto_Type._(6, 'TYPE_FIXED64');
+  static const FieldDescriptorProto_Type TYPE_FIXED32 = const FieldDescriptorProto_Type._(7, 'TYPE_FIXED32');
+  static const FieldDescriptorProto_Type TYPE_BOOL = const FieldDescriptorProto_Type._(8, 'TYPE_BOOL');
+  static const FieldDescriptorProto_Type TYPE_STRING = const FieldDescriptorProto_Type._(9, 'TYPE_STRING');
+  static const FieldDescriptorProto_Type TYPE_GROUP = const FieldDescriptorProto_Type._(10, 'TYPE_GROUP');
+  static const FieldDescriptorProto_Type TYPE_MESSAGE = const FieldDescriptorProto_Type._(11, 'TYPE_MESSAGE');
+  static const FieldDescriptorProto_Type TYPE_BYTES = const FieldDescriptorProto_Type._(12, 'TYPE_BYTES');
+  static const FieldDescriptorProto_Type TYPE_UINT32 = const FieldDescriptorProto_Type._(13, 'TYPE_UINT32');
+  static const FieldDescriptorProto_Type TYPE_ENUM = const FieldDescriptorProto_Type._(14, 'TYPE_ENUM');
+  static const FieldDescriptorProto_Type TYPE_SFIXED32 = const FieldDescriptorProto_Type._(15, 'TYPE_SFIXED32');
+  static const FieldDescriptorProto_Type TYPE_SFIXED64 = const FieldDescriptorProto_Type._(16, 'TYPE_SFIXED64');
+  static const FieldDescriptorProto_Type TYPE_SINT32 = const FieldDescriptorProto_Type._(17, 'TYPE_SINT32');
+  static const FieldDescriptorProto_Type TYPE_SINT64 = const FieldDescriptorProto_Type._(18, 'TYPE_SINT64');
+
+  static const List<FieldDescriptorProto_Type> values = const <FieldDescriptorProto_Type> [
+    TYPE_DOUBLE,
+    TYPE_FLOAT,
+    TYPE_INT64,
+    TYPE_UINT64,
+    TYPE_INT32,
+    TYPE_FIXED64,
+    TYPE_FIXED32,
+    TYPE_BOOL,
+    TYPE_STRING,
+    TYPE_GROUP,
+    TYPE_MESSAGE,
+    TYPE_BYTES,
+    TYPE_UINT32,
+    TYPE_ENUM,
+    TYPE_SFIXED32,
+    TYPE_SFIXED64,
+    TYPE_SINT32,
+    TYPE_SINT64,
+  ];
+
+  static final Map<int, dynamic> _byValue = ProtobufEnum.initByValue(values);
+  static FieldDescriptorProto_Type valueOf(int value) => _byValue[value] as FieldDescriptorProto_Type;
+  static void $checkItem(FieldDescriptorProto_Type v) {
+    if (v is !FieldDescriptorProto_Type) checkItemFailed(v, 'FieldDescriptorProto_Type');
+  }
+
+  const FieldDescriptorProto_Type._(int v, String n) : super(v, n);
+}
+
+class FieldDescriptorProto_Label extends ProtobufEnum {
+  static const FieldDescriptorProto_Label LABEL_OPTIONAL = const FieldDescriptorProto_Label._(1, 'LABEL_OPTIONAL');
+  static const FieldDescriptorProto_Label LABEL_REQUIRED = const FieldDescriptorProto_Label._(2, 'LABEL_REQUIRED');
+  static const FieldDescriptorProto_Label LABEL_REPEATED = const FieldDescriptorProto_Label._(3, 'LABEL_REPEATED');
+
+  static const List<FieldDescriptorProto_Label> values = const <FieldDescriptorProto_Label> [
+    LABEL_OPTIONAL,
+    LABEL_REQUIRED,
+    LABEL_REPEATED,
+  ];
+
+  static final Map<int, dynamic> _byValue = ProtobufEnum.initByValue(values);
+  static FieldDescriptorProto_Label valueOf(int value) => _byValue[value] as FieldDescriptorProto_Label;
+  static void $checkItem(FieldDescriptorProto_Label v) {
+    if (v is !FieldDescriptorProto_Label) checkItemFailed(v, 'FieldDescriptorProto_Label');
+  }
+
+  const FieldDescriptorProto_Label._(int v, String n) : super(v, n);
+}
+
+class FileOptions_OptimizeMode extends ProtobufEnum {
+  static const FileOptions_OptimizeMode SPEED = const FileOptions_OptimizeMode._(1, 'SPEED');
+  static const FileOptions_OptimizeMode CODE_SIZE = const FileOptions_OptimizeMode._(2, 'CODE_SIZE');
+  static const FileOptions_OptimizeMode LITE_RUNTIME = const FileOptions_OptimizeMode._(3, 'LITE_RUNTIME');
+
+  static const List<FileOptions_OptimizeMode> values = const <FileOptions_OptimizeMode> [
+    SPEED,
+    CODE_SIZE,
+    LITE_RUNTIME,
+  ];
+
+  static final Map<int, dynamic> _byValue = ProtobufEnum.initByValue(values);
+  static FileOptions_OptimizeMode valueOf(int value) => _byValue[value] as FileOptions_OptimizeMode;
+  static void $checkItem(FileOptions_OptimizeMode v) {
+    if (v is !FileOptions_OptimizeMode) checkItemFailed(v, 'FileOptions_OptimizeMode');
+  }
+
+  const FileOptions_OptimizeMode._(int v, String n) : super(v, n);
+}
+
+class FieldOptions_CType extends ProtobufEnum {
+  static const FieldOptions_CType STRING = const FieldOptions_CType._(0, 'STRING');
+
+  static const List<FieldOptions_CType> values = const <FieldOptions_CType> [
+    STRING,
+  ];
+
+  static final Map<int, dynamic> _byValue = ProtobufEnum.initByValue(values);
+  static FieldOptions_CType valueOf(int value) => _byValue[value] as FieldOptions_CType;
+  static void $checkItem(FieldOptions_CType v) {
+    if (v is !FieldOptions_CType) checkItemFailed(v, 'FieldOptions_CType');
+  }
+
+  const FieldOptions_CType._(int v, String n) : super(v, n);
+}
+
diff --git a/lib/src/plugin.pb.dart b/lib/src/plugin.pb.dart
index 8a6a34d..ff4e2f9 100644
--- a/lib/src/plugin.pb.dart
+++ b/lib/src/plugin.pb.dart
@@ -4,6 +4,7 @@
 library proto2.compiler_plugin;
 
 import 'package:protobuf/protobuf.dart';
+
 import 'descriptor.pb.dart' as proto2;
 
 class CodeGeneratorRequest extends GeneratedMessage {
@@ -116,30 +117,3 @@
 
 class _ReadonlyCodeGeneratorResponse extends CodeGeneratorResponse with ReadonlyMessageMixin {}
 
-const CodeGeneratorRequest$json = const {
-  '1': 'CodeGeneratorRequest',
-  '2': const [
-    const {'1': 'file_to_generate', '3': 1, '4': 3, '5': 9},
-    const {'1': 'parameter', '3': 2, '4': 1, '5': 9},
-    const {'1': 'proto_file', '3': 15, '4': 3, '5': 11, '6': '.proto2.FileDescriptorProto'},
-  ],
-};
-
-const CodeGeneratorResponse$json = const {
-  '1': 'CodeGeneratorResponse',
-  '2': const [
-    const {'1': 'error', '3': 1, '4': 1, '5': 9},
-    const {'1': 'file', '3': 15, '4': 3, '5': 11, '6': '.proto2.compiler.CodeGeneratorResponse.File'},
-  ],
-  '3': const [CodeGeneratorResponse_File$json],
-};
-
-const CodeGeneratorResponse_File$json = const {
-  '1': 'File',
-  '2': const [
-    const {'1': 'name', '3': 1, '4': 1, '5': 9},
-    const {'1': 'insertion_point', '3': 2, '4': 1, '5': 9},
-    const {'1': 'content', '3': 15, '4': 1, '5': 9},
-  ],
-};
-
diff --git a/test/protos/dart_options.proto b/test/protos/dart_options.proto
index 7de2170..8056518 100644
--- a/test/protos/dart_options.proto
+++ b/test/protos/dart_options.proto
@@ -3,44 +3,46 @@
 
 package dart_options;
 
-// This file must be modified for google internal use,
+// This file must be modified for Google internal use,
 // because custom options only work when the package name
 // agrees with the version of protoc we are using.
 // (The import statement and "google.protobuf." prefix need to be changed.)
 
 import "descriptor_2_5_opensource.proto";
 
-// A mixin to be applied in the 'with' clause of a generated proto in dart.
+// A mixin that can be used in the 'with' clause of the generated Dart class
+// for a proto message.
 message DartMixin {
-  // Class name of the mixin class.
+  // The name of the mixin class.
   optional string name = 1;
 
-  // File from which the mixin class is imported.
+  // A URI pointing to the Dart library that defines the mixin.
   // The generated Dart code will use this in an import statement.
   optional string import_from = 2;
 
-  // Used to apply multiple mixins to a proto.
-  // The mixin listed in parent will always be applied before this one,
-  // making the generated proto implement both mixins.
+  // The name of another mixin to be applied ahead of this one.
+  // The generated class for the message will inherit from all mixins
+  // in the parent chain.
   optional string parent = 3;
 }
 
-// Defines mixins imported from dart files to be used on messages in this file.
-message ImportedMixins {
+// Defines additional Dart imports to be used with messages in this file.
+message Imports {
 
-  // The DartMixins to be imported.
+  // Mixins to be used on messages in this file.
+  // These mixins are in addition to internally defined mixins (e.g PbMapMixin)
+  // and may override them.
+  //
+  // Warning: mixins are experimental. The protoc Dart plugin doesn't check
+  // for name conflicts between mixin class members and generated class members,
+  // so the generated code may contain errors. Therefore, running dartanalyzer
+  // on the generated file is a good idea.
   repeated DartMixin mixins = 1;
 }
 
 extend google.protobuf.FileOptions {
 
-  // Defines the named mixins to be used on messages in this file.
-  // These mixins are in addition to internally defined mixins (e.g PbMapMixin)
-  // and may override them.
-  // Warning: there is no checking at compile time for name conflicts between
-  // identifiers defined in the mixin and proto-generated identifiers.
-  // Running dartanalyzer on the generated file might find some of them.
-  optional ImportedMixins imported_mixins = 28125061;
+  optional Imports imports = 28125061;
 
   // Applies the named mixin to all messages in this file.
   // (May be overridden by the "mixin" option on a message.)
diff --git a/test/protos/mixins.proto b/test/protos/mixins.proto
index fccd674..48352a8 100644
--- a/test/protos/mixins.proto
+++ b/test/protos/mixins.proto
@@ -2,7 +2,7 @@
 
 import "dart_options.proto";
 
-option (dart_options.imported_mixins) = {
+option (dart_options.imports) = {
   mixins: [{
     name: "Mixin1"
     import_from: "package:protoc_plugin/testing/mixins.dart"