Named arguments to construct messages (#442)

diff --git a/protoc_plugin/lib/base_type.dart b/protoc_plugin/lib/base_type.dart
index 7559c7e..8bb6d8f 100644
--- a/protoc_plugin/lib/base_type.dart
+++ b/protoc_plugin/lib/base_type.dart
@@ -55,6 +55,9 @@
   String getRepeatedDartType(FileGenerator fileGen) =>
       "$_coreImportPrefix.List<${getDartType(fileGen)}>";
 
+  String getRepeatedDartTypeIterable(FileGenerator fileGen) =>
+      "$_coreImportPrefix.Iterable<${getDartType(fileGen)}>";
+
   factory BaseType(FieldDescriptorProto field, GenerationContext ctx) {
     String constSuffix;
 
diff --git a/protoc_plugin/lib/message_generator.dart b/protoc_plugin/lib/message_generator.dart
index 3e94ad2..79e46d1 100644
--- a/protoc_plugin/lib/message_generator.dart
+++ b/protoc_plugin/lib/message_generator.dart
@@ -360,7 +360,44 @@
       out.printlnAnnotated('${classname}._() : super();', [
         NamedLocation(name: classname, fieldPathSegment: fieldPath, start: 0)
       ]);
-      out.println('factory ${classname}() => create();');
+      out.print('factory $classname(');
+      if (_fieldList.isNotEmpty) {
+        out.println('{');
+        for (final field in _fieldList) {
+          _emitDeprecatedIf(field.isDeprecated, out);
+          if (field.isRepeated && !field.isMapField) {
+            out.println(
+                '  ${field.baseType.getRepeatedDartTypeIterable(fileGen)} ${field.memberNames.fieldName},');
+          } else {
+            out.println(
+                '  ${field.getDartType(fileGen)} ${field.memberNames.fieldName},');
+          }
+        }
+        out.print('}');
+      }
+      if (_fieldList.isNotEmpty) {
+        out.println(') {');
+        out.println('  final _result = create();');
+        for (final field in _fieldList) {
+          out.println('  if (${field.memberNames.fieldName} != null) {');
+          if (field.isDeprecated) {
+            out.println(
+                '    // ignore: deprecated_member_use_from_same_package');
+          }
+          if (field.isRepeated || field.isMapField) {
+            out.println(
+                '    _result.${field.memberNames.fieldName}.addAll(${field.memberNames.fieldName});');
+          } else {
+            out.println(
+                '    _result.${field.memberNames.fieldName} = ${field.memberNames.fieldName};');
+          }
+          out.println('  }');
+        }
+        out.println('  return _result;');
+        out.println('}');
+      } else {
+        out.println(') => create();');
+      }
       out.println(
           'factory ${classname}.fromBuffer($_coreImportPrefix.List<$_coreImportPrefix.int> i,'
           ' [$_protobufImportPrefix.ExtensionRegistry r = $_protobufImportPrefix.ExtensionRegistry.EMPTY])'
diff --git a/protoc_plugin/test/goldens/imports.pb b/protoc_plugin/test/goldens/imports.pb
index 30eacac..3168eda 100644
--- a/protoc_plugin/test/goldens/imports.pb
+++ b/protoc_plugin/test/goldens/imports.pb
@@ -21,7 +21,23 @@
   ;
 
   M._() : super();
-  factory M() => create();
+  factory M({
+    M m,
+    $1.M m1,
+    $2.M m2,
+  }) {
+    final _result = create();
+    if (m != null) {
+      _result.m = m;
+    }
+    if (m1 != null) {
+      _result.m1 = m1;
+    }
+    if (m2 != null) {
+      _result.m2 = m2;
+    }
+    return _result;
+  }
   factory M.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
   factory M.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
   @$core.Deprecated(
diff --git a/protoc_plugin/test/goldens/int64.pb b/protoc_plugin/test/goldens/int64.pb
index e06d161..ee98cb5 100644
--- a/protoc_plugin/test/goldens/int64.pb
+++ b/protoc_plugin/test/goldens/int64.pb
@@ -17,7 +17,15 @@
   ;
 
   Int64._() : super();
-  factory Int64() => create();
+  factory Int64({
+    $fixnum.Int64 value,
+  }) {
+    final _result = create();
+    if (value != null) {
+      _result.value = value;
+    }
+    return _result;
+  }
   factory Int64.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
   factory Int64.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
   @$core.Deprecated(
diff --git a/protoc_plugin/test/goldens/messageGenerator b/protoc_plugin/test/goldens/messageGenerator
index 8998343..cca679d 100644
--- a/protoc_plugin/test/goldens/messageGenerator
+++ b/protoc_plugin/test/goldens/messageGenerator
@@ -7,7 +7,29 @@
   ;
 
   PhoneNumber._() : super();
-  factory PhoneNumber() => create();
+  factory PhoneNumber({
+    $core.String number,
+    PhoneNumber_PhoneType type,
+    $core.String name,
+  @$core.Deprecated('This field is deprecated.')
+    $core.String deprecatedField,
+  }) {
+    final _result = create();
+    if (number != null) {
+      _result.number = number;
+    }
+    if (type != null) {
+      _result.type = type;
+    }
+    if (name != null) {
+      _result.name = name;
+    }
+    if (deprecatedField != null) {
+      // ignore: deprecated_member_use_from_same_package
+      _result.deprecatedField = deprecatedField;
+    }
+    return _result;
+  }
   factory PhoneNumber.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
   factory PhoneNumber.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
   @$core.Deprecated(
diff --git a/protoc_plugin/test/goldens/messageGenerator.meta b/protoc_plugin/test/goldens/messageGenerator.meta
index cd6a52d..16ea2ff 100644
--- a/protoc_plugin/test/goldens/messageGenerator.meta
+++ b/protoc_plugin/test/goldens/messageGenerator.meta
@@ -18,8 +18,8 @@
   path: 2
   path: 1
   sourceFile: 
-  begin: 2247
-  end: 2253
+  begin: 2782
+  end: 2788
 }
 annotation: {
   path: 4
@@ -27,8 +27,8 @@
   path: 2
   path: 1
   sourceFile: 
-  begin: 2295
-  end: 2301
+  begin: 2830
+  end: 2836
 }
 annotation: {
   path: 4
@@ -36,8 +36,8 @@
   path: 2
   path: 1
   sourceFile: 
-  begin: 2374
-  end: 2383
+  begin: 2909
+  end: 2918
 }
 annotation: {
   path: 4
@@ -45,8 +45,8 @@
   path: 2
   path: 1
   sourceFile: 
-  begin: 2426
-  end: 2437
+  begin: 2961
+  end: 2972
 }
 annotation: {
   path: 4
@@ -54,8 +54,8 @@
   path: 2
   path: 0
   sourceFile: 
-  begin: 2507
-  end: 2511
+  begin: 3042
+  end: 3046
 }
 annotation: {
   path: 4
@@ -63,8 +63,8 @@
   path: 2
   path: 0
   sourceFile: 
-  begin: 2552
-  end: 2556
+  begin: 3087
+  end: 3091
 }
 annotation: {
   path: 4
@@ -72,8 +72,8 @@
   path: 2
   path: 0
   sourceFile: 
-  begin: 2635
-  end: 2642
+  begin: 3170
+  end: 3177
 }
 annotation: {
   path: 4
@@ -81,8 +81,8 @@
   path: 2
   path: 0
   sourceFile: 
-  begin: 2685
-  end: 2694
+  begin: 3220
+  end: 3229
 }
 annotation: {
   path: 4
@@ -90,8 +90,8 @@
   path: 2
   path: 2
   sourceFile: 
-  begin: 2755
-  end: 2759
+  begin: 3290
+  end: 3294
 }
 annotation: {
   path: 4
@@ -99,8 +99,8 @@
   path: 2
   path: 2
   sourceFile: 
-  begin: 2806
-  end: 2810
+  begin: 3341
+  end: 3345
 }
 annotation: {
   path: 4
@@ -108,51 +108,51 @@
   path: 2
   path: 2
   sourceFile: 
-  begin: 2883
-  end: 2890
-}
-annotation: {
-  path: 4
-  path: 0
-  path: 2
-  path: 2
-  sourceFile: 
-  begin: 2933
-  end: 2942
-}
-annotation: {
-  path: 4
-  path: 0
-  path: 2
-  path: 3
-  sourceFile: 
-  begin: 3052
-  end: 3067
-}
-annotation: {
-  path: 4
-  path: 0
-  path: 2
-  path: 3
-  sourceFile: 
-  begin: 3158
-  end: 3173
-}
-annotation: {
-  path: 4
-  path: 0
-  path: 2
-  path: 3
-  sourceFile: 
-  begin: 3295
-  end: 3313
-}
-annotation: {
-  path: 4
-  path: 0
-  path: 2
-  path: 3
-  sourceFile: 
-  begin: 3405
+  begin: 3418
   end: 3425
 }
+annotation: {
+  path: 4
+  path: 0
+  path: 2
+  path: 2
+  sourceFile: 
+  begin: 3468
+  end: 3477
+}
+annotation: {
+  path: 4
+  path: 0
+  path: 2
+  path: 3
+  sourceFile: 
+  begin: 3587
+  end: 3602
+}
+annotation: {
+  path: 4
+  path: 0
+  path: 2
+  path: 3
+  sourceFile: 
+  begin: 3693
+  end: 3708
+}
+annotation: {
+  path: 4
+  path: 0
+  path: 2
+  path: 3
+  sourceFile: 
+  begin: 3830
+  end: 3848
+}
+annotation: {
+  path: 4
+  path: 0
+  path: 2
+  path: 3
+  sourceFile: 
+  begin: 3940
+  end: 3960
+}
diff --git a/protoc_plugin/test/goldens/oneMessage.pb b/protoc_plugin/test/goldens/oneMessage.pb
index d732da9..2a79ae9 100644
--- a/protoc_plugin/test/goldens/oneMessage.pb
+++ b/protoc_plugin/test/goldens/oneMessage.pb
@@ -17,7 +17,23 @@
   ;
 
   PhoneNumber._() : super();
-  factory PhoneNumber() => create();
+  factory PhoneNumber({
+    $core.String number,
+    $core.int type,
+    $core.String name,
+  }) {
+    final _result = create();
+    if (number != null) {
+      _result.number = number;
+    }
+    if (type != null) {
+      _result.type = type;
+    }
+    if (name != null) {
+      _result.name = name;
+    }
+    return _result;
+  }
   factory PhoneNumber.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
   factory PhoneNumber.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
   @$core.Deprecated(
diff --git a/protoc_plugin/test/goldens/oneMessage.pb.meta b/protoc_plugin/test/goldens/oneMessage.pb.meta
index 9cdc405..9b6716d 100644
--- a/protoc_plugin/test/goldens/oneMessage.pb.meta
+++ b/protoc_plugin/test/goldens/oneMessage.pb.meta
@@ -18,8 +18,8 @@
   path: 2
   path: 0
   sourceFile: test
-  begin: 2373
-  end: 2379
+  begin: 2666
+  end: 2672
 }
 annotation: {
   path: 4
@@ -27,8 +27,8 @@
   path: 2
   path: 0
   sourceFile: test
-  begin: 2421
-  end: 2427
+  begin: 2714
+  end: 2720
 }
 annotation: {
   path: 4
@@ -36,8 +36,8 @@
   path: 2
   path: 0
   sourceFile: test
-  begin: 2500
-  end: 2509
+  begin: 2793
+  end: 2802
 }
 annotation: {
   path: 4
@@ -45,8 +45,8 @@
   path: 2
   path: 0
   sourceFile: test
-  begin: 2552
-  end: 2563
+  begin: 2845
+  end: 2856
 }
 annotation: {
   path: 4
@@ -54,8 +54,8 @@
   path: 2
   path: 1
   sourceFile: test
-  begin: 2621
-  end: 2625
+  begin: 2914
+  end: 2918
 }
 annotation: {
   path: 4
@@ -63,8 +63,8 @@
   path: 2
   path: 1
   sourceFile: test
-  begin: 2667
-  end: 2671
+  begin: 2960
+  end: 2964
 }
 annotation: {
   path: 4
@@ -72,8 +72,8 @@
   path: 2
   path: 1
   sourceFile: test
-  begin: 2746
-  end: 2753
+  begin: 3039
+  end: 3046
 }
 annotation: {
   path: 4
@@ -81,8 +81,8 @@
   path: 2
   path: 1
   sourceFile: test
-  begin: 2796
-  end: 2805
+  begin: 3089
+  end: 3098
 }
 annotation: {
   path: 4
@@ -90,8 +90,8 @@
   path: 2
   path: 2
   sourceFile: test
-  begin: 2866
-  end: 2870
+  begin: 3159
+  end: 3163
 }
 annotation: {
   path: 4
@@ -99,8 +99,8 @@
   path: 2
   path: 2
   sourceFile: test
-  begin: 2917
-  end: 2921
+  begin: 3210
+  end: 3214
 }
 annotation: {
   path: 4
@@ -108,8 +108,8 @@
   path: 2
   path: 2
   sourceFile: test
-  begin: 2994
-  end: 3001
+  begin: 3287
+  end: 3294
 }
 annotation: {
   path: 4
@@ -117,6 +117,6 @@
   path: 2
   path: 2
   sourceFile: test
-  begin: 3044
-  end: 3053
+  begin: 3337
+  end: 3346
 }