diff --git a/protoc_plugin/CHANGELOG.md b/protoc_plugin/CHANGELOG.md index e5fad1f2..4ee43218 100644 --- a/protoc_plugin/CHANGELOG.md +++ b/protoc_plugin/CHANGELOG.md @@ -1,3 +1,9 @@ +## 22.0.2-wip + +* Fix factory argument types for protobuf `Map` fields. ([#975]) + +[#975]: https://github.com/google/protobuf.dart/issues/975 + ## 22.0.1 * Bump `protobuf` constraint to `^4.0.0` diff --git a/protoc_plugin/lib/src/message_generator.dart b/protoc_plugin/lib/src/message_generator.dart index b3020c8f..f05d16de 100644 --- a/protoc_plugin/lib/src/message_generator.dart +++ b/protoc_plugin/lib/src/message_generator.dart @@ -446,6 +446,12 @@ class MessageGenerator extends ProtobufContainer { if (field.isRepeated && !field.isMapField) { out.println( ' ${field.baseType.getRepeatedDartTypeIterable(fileGen)}? ${field.memberNames!.fieldName},'); + } else if (field.isMapField) { + final keyType = field.getDartMapKeyType(); + final valueType = field.getDartMapValueType(); + out.println( + ' $coreImportPrefix.Iterable<$coreImportPrefix.MapEntry<$keyType, $valueType>>? ' + '${field.memberNames!.fieldName},'); } else { out.println( ' ${field.getDartType()}? ${field.memberNames!.fieldName},'); @@ -459,9 +465,12 @@ class MessageGenerator extends ProtobufContainer { if (field.isDeprecated) { out.println(' // ignore: deprecated_member_use_from_same_package'); } - if (field.isRepeated || field.isMapField) { + if (field.isRepeated && !field.isMapField) { out.println( ' \$result.${field.memberNames!.fieldName}.addAll(${field.memberNames!.fieldName});'); + } else if (field.isMapField) { + out.println( + ' \$result.${field.memberNames!.fieldName}.addEntries(${field.memberNames!.fieldName});'); } else { out.println( ' \$result.${field.memberNames!.fieldName} = ${field.memberNames!.fieldName};'); diff --git a/protoc_plugin/lib/src/protobuf_field.dart b/protoc_plugin/lib/src/protobuf_field.dart index b4ca5d1d..7906cbec 100644 --- a/protoc_plugin/lib/src/protobuf_field.dart +++ b/protoc_plugin/lib/src/protobuf_field.dart @@ -140,18 +140,36 @@ class ProtobufField { // for example in package:protobuf/src/protobuf/mixins/well_known.dart. } - /// Returns the expression to use for the Dart type. + /// Returns the type to use for the Dart field type. String getDartType() { if (isMapField) { - final d = baseType.generator as MessageGenerator; - final keyType = d._fieldList[0].baseType.getDartType(parent.fileGen!); - final valueType = d._fieldList[1].baseType.getDartType(parent.fileGen!); + final keyType = getDartMapKeyType(); + final valueType = getDartMapValueType(); return '$protobufImportPrefix.PbMap<$keyType, $valueType>'; } if (isRepeated) return baseType.getRepeatedDartType(parent.fileGen!); return baseType.getDartType(parent.fileGen!); } + /// Only for map fields: returns the type to use for Dart map field key type. + String getDartMapKeyType() { + assert(isMapField); + return (baseType.generator as MessageGenerator) + ._fieldList[0] + .baseType + .getDartType(parent.fileGen!); + } + + /// Only for map fields: returns the type to use for Dart map field value + /// type. + String getDartMapValueType() { + assert(isMapField); + return (baseType.generator as MessageGenerator) + ._fieldList[1] + .baseType + .getDartType(parent.fileGen!); + } + /// Returns the tag number of the underlying proto field. int get number => descriptor.number; diff --git a/protoc_plugin/pubspec.yaml b/protoc_plugin/pubspec.yaml index 9e58fd3a..95c33d3b 100644 --- a/protoc_plugin/pubspec.yaml +++ b/protoc_plugin/pubspec.yaml @@ -1,5 +1,5 @@ name: protoc_plugin -version: 22.0.1 +version: 22.0.2-wip description: A protobuf protoc compiler plugin used to generate Dart code. repository: https://github.com/google/protobuf.dart/tree/master/protoc_plugin diff --git a/protoc_plugin/test/map_field_test.dart b/protoc_plugin/test/map_field_test.dart index 038ec671..790023fd 100644 --- a/protoc_plugin/test/map_field_test.dart +++ b/protoc_plugin/test/map_field_test.dart @@ -7,6 +7,7 @@ import 'dart:convert'; import 'package:protobuf/protobuf.dart'; import 'package:test/test.dart'; +import '../out/protos/constructor_args/map_field.pb.dart' as with_constructors; import '../out/protos/map_field.pb.dart'; void main() { @@ -454,4 +455,18 @@ void main() { msg.int32ToInt32Field[0] = 1; }, throwsA(const TypeMatcher())); }); + + test('Constructor map arguments accept key-value iterators', () { + final msg = with_constructors.TestMap( + stringToInt32Field: [ + MapEntry('a', 1), + MapEntry('b', 2), + MapEntry('a', 3) + ], + int32ToStringField: {1: 'hi'}.entries, + ); + expect(msg.stringToInt32Field['a'], 3); + expect(msg.stringToInt32Field['b'], 2); + expect(msg.int32ToStringField[1], 'hi'); + }); }