Don't create BuilderInfo object for map entries in PBMap constructor. (#179)

diff --git a/protobuf/CHANGELOG.md b/protobuf/CHANGELOG.md
index 395691e..79d0ad6 100644
--- a/protobuf/CHANGELOG.md
+++ b/protobuf/CHANGELOG.md
@@ -1,3 +1,14 @@
+## 0.12.0
+
+* Breaking change: Changed `BuilderInfo.m()` to take class and package name of the protobuf message representing the map
+  entry. Also changed `BuilderInfo.addMapField` as well as the constructors `PbMap` and `MapFieldInfo.map` to take a map
+  entry BuilderInfo object.
+
+  This mostly affects generated code, which should now be built with protoc_plugin 15.0.0 or newer.
+
+  With this change we avoid creating a map entry BuilderInfo object for each PbMap instance, instead it is passed
+  through the static BuilderInfo object in the generated subclasses of GeneratedMessage.
+
 ## 0.11.0
 
 * Breaking change: changed semantics of `GeneratedMessage.toBuilder()` to only make a shallow copy.
@@ -5,7 +16,7 @@
   `GeneratedMessage` has a new abstract method: `createEmptyInstance()` that subclasses must
   implement.
 
-  Proto files must be rebuilt using protoc_plugin 0.15.0 or newer.
+  Proto files must be rebuilt using protoc_plugin 14.0.0 or newer.
 
 ## 0.10.8
 
diff --git a/protobuf/lib/src/protobuf/builder_info.dart b/protobuf/lib/src/protobuf/builder_info.dart
index 513ec4e..c63c2b1 100644
--- a/protobuf/lib/src/protobuf/builder_info.dart
+++ b/protobuf/lib/src/protobuf/builder_info.dart
@@ -34,17 +34,11 @@
         defaultOrMaker, subBuilder, valueOf, enumValues));
   }
 
-  void addMapField<K, V>(
-      int tagNumber,
-      String name,
-      int keyFieldType,
-      int valueFieldType,
-      CreateBuilderFunc valueCreator,
-      ValueOfFunc valueOf,
-      List<ProtobufEnum> enumValues) {
+  void addMapField<K, V>(int tagNumber, String name, int keyFieldType,
+      int valueFieldType, BuilderInfo mapEntryBuilderInfo) {
     var index = byIndex.length;
     _addField(MapFieldInfo<K, V>.map(name, tagNumber, index, PbFieldType.M,
-        keyFieldType, valueFieldType, valueCreator, valueOf, enumValues));
+        keyFieldType, valueFieldType, mapEntryBuilderInfo));
   }
 
   void addRepeated<T>(
@@ -134,12 +128,20 @@
   }
 
   // Map field.
-  void m<K, V>(int tagNumber, String name, int keyFieldType, int valueFieldType,
+  void m<K, V>(int tagNumber, String name, String entryClassName,
+      int keyFieldType, int valueFieldType,
       [CreateBuilderFunc valueCreator,
       ValueOfFunc valueOf,
-      List<ProtobufEnum> enumValues]) {
-    addMapField<K, V>(tagNumber, name, keyFieldType, valueFieldType,
-        valueCreator, valueOf, enumValues);
+      List<ProtobufEnum> enumValues,
+      PackageName packageName = const PackageName('')]) {
+    BuilderInfo mapEntryBuilderInfo = BuilderInfo(entryClassName,
+        package: packageName)
+      ..add(PbMap._keyFieldNumber, 'key', keyFieldType, null, null, null, null)
+      ..add(PbMap._valueFieldNumber, 'value', valueFieldType, null,
+          valueCreator, valueOf, enumValues);
+
+    addMapField<K, V>(
+        tagNumber, name, keyFieldType, valueFieldType, mapEntryBuilderInfo);
   }
 
   bool containsTagNumber(int tagNumber) => fieldInfo.containsKey(tagNumber);
diff --git a/protobuf/lib/src/protobuf/field_info.dart b/protobuf/lib/src/protobuf/field_info.dart
index c977a96..0f7eb4b 100644
--- a/protobuf/lib/src/protobuf/field_info.dart
+++ b/protobuf/lib/src/protobuf/field_info.dart
@@ -8,6 +8,9 @@
 class FieldInfo<T> {
   FrozenPbList<T> _emptyList;
 
+  // BuilderInfo used when creating a field set for a map field.
+  final BuilderInfo _mapEntryBuilderInfo;
+
   final String name;
   final int tagNumber;
   final int index; // index of the field's value. Null for extensions.
@@ -39,7 +42,8 @@
       [dynamic defaultOrMaker, this.subBuilder, this.valueOf, this.enumValues])
       : this.type = type,
         this.makeDefault = findMakeDefault(type, defaultOrMaker),
-        this.check = null {
+        this.check = null,
+        _mapEntryBuilderInfo = null {
     assert(type != 0);
     assert(!_isGroupOrMessage(type) || subBuilder != null);
     assert(!_isEnum(type) || valueOf != null);
@@ -49,7 +53,8 @@
       this.check, this.subBuilder,
       [this.valueOf, this.enumValues])
       : this.type = type,
-        this.makeDefault = (() => new PbList<T>(check: check)) {
+        this.makeDefault = (() => new PbList<T>(check: check)),
+        _mapEntryBuilderInfo = null {
     assert(name != null);
     assert(tagNumber != null);
     assert(_isRepeated(type));
@@ -59,7 +64,11 @@
 
   FieldInfo._map(
       this.name, this.tagNumber, this.index, int type, this.makeDefault,
-      [dynamic defaultOrMaker, this.subBuilder, this.valueOf, this.enumValues])
+      [dynamic defaultOrMaker,
+      this.subBuilder,
+      this.valueOf,
+      this.enumValues,
+      this._mapEntryBuilderInfo])
       : this.type = type,
         this.check = null {
     assert(name != null);
@@ -169,19 +178,19 @@
   CreateBuilderFunc valueCreator;
 
   MapFieldInfo.map(String name, int tagNumber, int index, int type,
-      this.keyFieldType, this.valueFieldType,
-      [this.valueCreator, ValueOfFunc valueOf, List<ProtobufEnum> enumValues])
+      this.keyFieldType, this.valueFieldType, BuilderInfo mapEntryBuilderInfo)
       : super._map(
             name,
             tagNumber,
             index,
             type,
-            () => PbMap<K, V>(keyFieldType, valueFieldType, valueCreator,
-                valueOf, enumValues),
+            () =>
+                PbMap<K, V>(keyFieldType, valueFieldType, mapEntryBuilderInfo),
             null,
             null,
-            valueOf,
-            enumValues) {
+            null,
+            null,
+            mapEntryBuilderInfo) {
     assert(name != null);
     assert(tagNumber != null);
     assert(_isMapField(type));
diff --git a/protobuf/lib/src/protobuf/field_set.dart b/protobuf/lib/src/protobuf/field_set.dart
index 6cd4e7c..4723b04 100644
--- a/protobuf/lib/src/protobuf/field_set.dart
+++ b/protobuf/lib/src/protobuf/field_set.dart
@@ -198,8 +198,8 @@
   Map<K, V> _getDefaultMap<K, V>(MapFieldInfo<K, V> fi) {
     assert(fi.isMapField);
     if (_isReadOnly)
-      return PbMap<K, V>.unmodifiable(PbMap<K, V>(fi.keyFieldType,
-          fi.valueFieldType, fi.valueCreator, fi.valueOf, fi.enumValues));
+      return PbMap<K, V>.unmodifiable(PbMap<K, V>(
+          fi.keyFieldType, fi.valueFieldType, fi._mapEntryBuilderInfo));
 
     var value = fi._createMapField(_message);
     _setNonExtensionFieldUnchecked(fi, value);
diff --git a/protobuf/lib/src/protobuf/generated_message.dart b/protobuf/lib/src/protobuf/generated_message.dart
index 23f46a2..c78e11d 100644
--- a/protobuf/lib/src/protobuf/generated_message.dart
+++ b/protobuf/lib/src/protobuf/generated_message.dart
@@ -270,8 +270,8 @@
 
   /// Creates a Map representing a map field.
   Map<K, V> createMapField<K, V>(int tagNumber, MapFieldInfo<K, V> fi) {
-    return PbMap<K, V>(fi.keyFieldType, fi.valueFieldType, fi.valueCreator,
-        fi.valueOf, fi.enumValues);
+    return PbMap<K, V>(
+        fi.keyFieldType, fi.valueFieldType, fi._mapEntryBuilderInfo);
   }
 
   /// Returns the value of a field, ignoring any defaults.
diff --git a/protobuf/lib/src/protobuf/pb_map.dart b/protobuf/lib/src/protobuf/pb_map.dart
index f991df4..d8a5110 100644
--- a/protobuf/lib/src/protobuf/pb_map.dart
+++ b/protobuf/lib/src/protobuf/pb_map.dart
@@ -16,16 +16,9 @@
   bool _isReadonly = false;
   _FieldSet _entryFieldSet;
 
-  PbMap(this.keyFieldType, this.valueFieldType,
-      [CreateBuilderFunc valueCreator,
-      ValueOfFunc valueOf,
-      List<ProtobufEnum> enumValues])
+  PbMap(this.keyFieldType, this.valueFieldType, BuilderInfo entryBuilderInfo)
       : _wrappedMap = <K, V>{} {
-    BuilderInfo entryInfo = new BuilderInfo("entry")
-      ..add(_keyFieldNumber, "key", keyFieldType, null, null, null, null)
-      ..add(_valueFieldNumber, "value", valueFieldType, null, valueCreator,
-          valueOf, enumValues);
-    _entryFieldSet = new _FieldSet(null, entryInfo, null);
+    _entryFieldSet = new _FieldSet(null, entryBuilderInfo, null);
   }
 
   PbMap.unmodifiable(PbMap other)
diff --git a/protobuf/pubspec.yaml b/protobuf/pubspec.yaml
index 01dc101..05ba43e 100644
--- a/protobuf/pubspec.yaml
+++ b/protobuf/pubspec.yaml
@@ -1,5 +1,5 @@
 name: protobuf
-version: 0.11.0
+version: 0.12.0
 author: Dart Team <misc@dartlang.org>
 description: >
   Runtime library for protocol buffers support.
diff --git a/protoc_plugin/CHANGELOG.md b/protoc_plugin/CHANGELOG.md
index 291e204..bc3e592 100644
--- a/protoc_plugin/CHANGELOG.md
+++ b/protoc_plugin/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 15.0.0
+
+*  Breaking change: Changed BuilderInfo call for map fields to include the BuilderInfo object for map entries.
+   Generated files require package:protobuf version 0.12.0 or newer.
+
 ## 14.0.1
 
 * Remove the benchmark from the protoc_package. It now lives in
diff --git a/protoc_plugin/lib/message_generator.dart b/protoc_plugin/lib/message_generator.dart
index df96853..8a3b8f1 100644
--- a/protoc_plugin/lib/message_generator.dart
+++ b/protoc_plugin/lib/message_generator.dart
@@ -290,7 +290,8 @@
           ';', () {
         for (ProtobufField field in _fieldList) {
           var dartFieldName = field.memberNames.fieldName;
-          out.println(field.generateBuilderInfoCall(fileGen, dartFieldName));
+          out.println(
+              field.generateBuilderInfoCall(fileGen, dartFieldName, package));
         }
 
         for (int oneof = 0; oneof < _oneofFields.length; oneof++) {
diff --git a/protoc_plugin/lib/protobuf_field.dart b/protoc_plugin/lib/protobuf_field.dart
index 3482161..e055c01 100644
--- a/protoc_plugin/lib/protobuf_field.dart
+++ b/protoc_plugin/lib/protobuf_field.dart
@@ -115,7 +115,8 @@
   /// Returns Dart code adding this field to a BuilderInfo object.
   /// The call will start with ".." and a method name.
   /// [fileGen] represents the .proto file where the code will be evaluated.
-  String generateBuilderInfoCall(FileGenerator fileGen, String dartFieldName) {
+  String generateBuilderInfoCall(
+      FileGenerator fileGen, String dartFieldName, String package) {
     String quotedName = "'$dartFieldName'";
     String type = baseType.getDartType(fileGen);
 
@@ -127,18 +128,18 @@
       String valueType = value.baseType.getDartType(fileGen);
       String keyTypeConstant = key.typeConstant;
       String valTypeConstant = value.typeConstant;
+      String valueCreator = (value.baseType.isMessage || value.baseType.isGroup)
+          ? '$valueType.create'
+          : 'null';
+      String valueOf = value.baseType.isEnum ? '$valueType.valueOf' : 'null';
+      String enumValues = value.baseType.isEnum ? '$valueType.values' : 'null';
+      String mapEntryClassName = "'${generator.messageName}'";
+      String packageClause = package == ''
+          ? ''
+          : ", const $_protobufImportPrefix.PackageName(\'$package\')";
 
-      if (value.baseType.isMessage || value.baseType.isGroup) {
-        return '..m<$keyType, $valueType>($number, $quotedName, '
-            '$keyTypeConstant, $valTypeConstant, $valueType.create)';
-      }
-      if (value.baseType.isEnum) {
-        return '..m<$keyType, $valueType>($number, $quotedName, '
-            '$keyTypeConstant, $valTypeConstant, null, $valueType.valueOf, '
-            '$valueType.values)';
-      }
-      return '..m<$keyType, $valueType>($number, $quotedName, '
-          '$keyTypeConstant, $valTypeConstant)';
+      return '..m<$keyType, $valueType>($number, $quotedName, $mapEntryClassName,'
+          '$keyTypeConstant, $valTypeConstant, $valueCreator, $valueOf, $enumValues $packageClause)';
     }
 
     if (isRepeated) {
diff --git a/protoc_plugin/pubspec.yaml b/protoc_plugin/pubspec.yaml
index c5c5e30..debcc92 100644
--- a/protoc_plugin/pubspec.yaml
+++ b/protoc_plugin/pubspec.yaml
@@ -1,5 +1,5 @@
 name: protoc_plugin
-version: 14.0.1
+version: 15.0.0
 author: Dart Team <misc@dartlang.org>
 description: Protoc compiler plugin to generate Dart code
 homepage: https://github.com/dart-lang/protobuf
@@ -10,7 +10,7 @@
 dependencies:
   fixnum: ^0.10.5
   path: ^1.0.0
-  protobuf: ^0.11.0
+  protobuf: ^0.12.0
   dart_style: ^1.0.6
 
 dev_dependencies: