Align the hashCode of a message with an empty unknown field-set with that of no unknown field set (#648)

Port of cl/308005673
diff --git a/protobuf/lib/src/protobuf/field_set.dart b/protobuf/lib/src/protobuf/field_set.dart
index 45e4d7e..844558c 100644
--- a/protobuf/lib/src/protobuf/field_set.dart
+++ b/protobuf/lib/src/protobuf/field_set.dart
@@ -675,9 +675,7 @@
     }
 
     // Hash with unknown fields.
-    if (_hasUnknownFields) {
-      hash = _HashUtils._combine(hash, _unknownFields.hashCode);
-    }
+    hash = _HashUtils._combine(hash, _unknownFields?.hashCode ?? 0);
 
     if (_isReadOnly && _hashCodesCanBeMemoized) {
       _frozenState = hash;
diff --git a/protoc_plugin/test/extension_test.dart b/protoc_plugin/test/extension_test.dart
index c4b668a..5925251 100644
--- a/protoc_plugin/test/extension_test.dart
+++ b/protoc_plugin/test/extension_test.dart
@@ -3,6 +3,7 @@
 // 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.
 
+import 'dart:typed_data';
 import 'package:protobuf/protobuf.dart';
 import 'package:test/test.dart';
 
@@ -547,4 +548,15 @@
     expect(withUnknownFields.stringMap.length, reparsed.stringMap.length);
     expect(withUnknownFields.stringMap[0], reparsed.stringMap[0]);
   });
+
+  test('consistent hashcode for reparsed messages with extensions', () {
+    final r = ExtensionRegistry()..add(Extend_unittest.outer);
+    final m = TestAllExtensions()
+      ..setExtension(
+          Extend_unittest.outer, Outer()..inner = (Inner()..value = 'hello'));
+    final Uint8List b = m.writeToBuffer();
+    final c = TestAllExtensions.fromBuffer(b);
+    final d = r.reparseMessage(c);
+    expect(m.hashCode, d.hashCode);
+  });
 }
diff --git a/protoc_plugin/test/unknown_field_set_test.dart b/protoc_plugin/test/unknown_field_set_test.dart
index e8b36b6..7ca5efd 100755
--- a/protoc_plugin/test/unknown_field_set_test.dart
+++ b/protoc_plugin/test/unknown_field_set_test.dart
@@ -316,4 +316,13 @@
 
     _checkNotEqual(f1, f2);
   });
+
+  test(
+      'consistent hashcode for messages with no unknown fields set and an empty unknown field set',
+      () {
+    final m = TestAllExtensions();
+    // Force an unknown field set.
+    final m2 = TestAllExtensions()..unknownFields;
+    expect(m.hashCode, m2.hashCode);
+  });
 }