Browse Source

Merge branch 'master' into expand-wildcards

Laszlo Csomor 6 năm trước cách đây
mục cha
commit
ea61636cbc
100 tập tin đã thay đổi với 3712 bổ sung1027 xóa
  1. 24 2
      BUILD
  2. 2 0
      Makefile.am
  3. 42 0
      Protobuf-C++.podspec
  4. 62 0
      build_files_updated_unittest.sh
  5. 1 0
      cmake/extract_includes.bat.in
  6. 1 1
      cmake/libprotobuf-lite.cmake
  7. 11 3
      cmake/tests.cmake
  8. 222 74
      conformance/binary_json_conformance_suite.cc
  9. 6 0
      conformance/binary_json_conformance_suite.h
  10. 8 3
      conformance/conformance_objc.m
  11. 38 5
      conformance/conformance_test.cc
  12. 4 2
      conformance/conformance_test.h
  13. 57 13
      conformance/failure_list_js.txt
  14. 4 0
      conformance/failure_list_objc.txt
  15. 36 4
      conformance/failure_list_php.txt
  16. 38 4
      conformance/failure_list_php_c.txt
  17. 38 8
      conformance/failure_list_ruby.txt
  18. 39 9
      conformance/failure_list_ruby_mac.txt
  19. 6 0
      csharp/compatibility_tests/v3.0.0/test.sh
  20. BIN
      csharp/src/Google.Protobuf.Test/testprotos.pb
  21. 181 16
      csharp/src/Google.Protobuf/FieldCodec.cs
  22. 1 1
      csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs
  23. 480 91
      java/core/src/main/java/com/google/protobuf/FieldSet.java
  24. 90 20
      java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
  25. 2 1
      java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java
  26. 181 15
      java/core/src/main/java/com/google/protobuf/TextFormat.java
  27. 160 0
      java/core/src/main/java/com/google/protobuf/TypeRegistry.java
  28. 154 0
      java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
  29. 5 1
      java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java
  30. 191 0
      java/core/src/test/java/com/google/protobuf/TextFormatTest.java
  31. 70 0
      java/core/src/test/java/com/google/protobuf/TypeRegistryTest.java
  32. 0 2
      java/core/src/test/proto/com/google/protobuf/test_extra_interfaces.proto
  33. 1 0
      java/lite/pom.xml
  34. 113 27
      java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
  35. 50 1
      java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
  36. 54 54
      js/binary/decoder.js
  37. 52 27
      js/binary/decoder_test.js
  38. 34 0
      js/binary/reader.js
  39. 20 0
      js/binary/reader_test.js
  40. 43 24
      js/binary/utils.js
  41. 106 110
      js/binary/utils_test.js
  42. 98 0
      js/binary/writer.js
  43. 71 0
      js/binary/writer_test.js
  44. 6 2
      js/map.js
  45. 72 26
      js/message.js
  46. 1 0
      js/message_test.js
  47. 9 0
      js/test.proto
  48. 18 1
      kokoro/linux/bazel/build.sh
  49. 0 1
      kokoro/release/python/linux/build_artifacts.sh
  50. 0 1
      kokoro/release/python/macos/build_artifacts.sh
  51. 1 1
      objectivec/google/protobuf/Duration.pbobjc.h
  52. 26 2
      protobuf_deps.bzl
  53. 7 0
      python/google/protobuf/internal/message_test.py
  54. 1 1
      python/google/protobuf/internal/python_message.py
  55. 2 2
      python/google/protobuf/internal/well_known_types.py
  56. 9 0
      python/google/protobuf/internal/well_known_types_test.py
  57. 2 3
      python/google/protobuf/pyext/map_container.cc
  58. 4 2
      python/google/protobuf/pyext/message.cc
  59. 8 0
      ruby/ext/google/protobuf_c/map.c
  60. 2 2
      ruby/ext/google/protobuf_c/message.c
  61. 14 0
      ruby/tests/basic.rb
  62. 54 0
      ruby/tests/well_known_types_test.rb
  63. 5 3
      src/Makefile.am
  64. 13 13
      src/google/protobuf/any.pb.cc
  65. 36 8
      src/google/protobuf/any.pb.h
  66. 0 1
      src/google/protobuf/any_lite.cc
  67. 0 1
      src/google/protobuf/any_test.cc
  68. 84 100
      src/google/protobuf/api.pb.cc
  69. 129 28
      src/google/protobuf/api.pb.h
  70. 1 1
      src/google/protobuf/arena.h
  71. 1 3
      src/google/protobuf/compiler/command_line_interface.cc
  72. 2 3
      src/google/protobuf/compiler/command_line_interface_unittest.cc
  73. 0 2
      src/google/protobuf/compiler/cpp/cpp_extension.cc
  74. 0 1
      src/google/protobuf/compiler/cpp/cpp_field.cc
  75. 79 20
      src/google/protobuf/compiler/cpp/cpp_file.cc
  76. 2 1
      src/google/protobuf/compiler/cpp/cpp_file.h
  77. 0 2
      src/google/protobuf/compiler/cpp/cpp_generator.cc
  78. 22 12
      src/google/protobuf/compiler/cpp/cpp_helpers.cc
  79. 14 1
      src/google/protobuf/compiler/cpp/cpp_helpers.h
  80. 51 16
      src/google/protobuf/compiler/cpp/cpp_message.cc
  81. 53 95
      src/google/protobuf/compiler/cpp/cpp_message_field.cc
  82. 0 1
      src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
  83. 103 70
      src/google/protobuf/compiler/cpp/cpp_string_field.cc
  84. 1 1
      src/google/protobuf/compiler/csharp/csharp_doc_comment.cc
  85. 1 1
      src/google/protobuf/compiler/csharp/csharp_helpers.h
  86. 1 1
      src/google/protobuf/compiler/csharp/csharp_names.h
  87. 5 5
      src/google/protobuf/compiler/csharp/csharp_reflection_class.cc
  88. 1 4
      src/google/protobuf/compiler/importer.cc
  89. 0 1
      src/google/protobuf/compiler/java/java_context.cc
  90. 47 33
      src/google/protobuf/compiler/java/java_doc_comment.cc
  91. 20 22
      src/google/protobuf/compiler/java/java_doc_comment.h
  92. 8 3
      src/google/protobuf/compiler/java/java_enum.cc
  93. 1 2
      src/google/protobuf/compiler/java/java_enum_field.cc
  94. 0 1
      src/google/protobuf/compiler/java/java_enum_field_lite.cc
  95. 0 1
      src/google/protobuf/compiler/java/java_enum_lite.cc
  96. 0 1
      src/google/protobuf/compiler/java/java_extension.cc
  97. 0 1
      src/google/protobuf/compiler/java/java_field.cc
  98. 0 1
      src/google/protobuf/compiler/java/java_file.cc
  99. 0 3
      src/google/protobuf/compiler/java/java_helpers.cc
  100. 0 2
      src/google/protobuf/compiler/java/java_message.cc

+ 24 - 2
BUILD

@@ -1,5 +1,9 @@
 # Bazel (https://bazel.build/) BUILD file for Protobuf.
 
+load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test", "objc_library")
+load("@rules_java//java:defs.bzl", "java_library")
+load("@rules_proto//proto:defs.bzl", "proto_lang_toolchain", "proto_library")
+
 licenses(["notice"])
 
 exports_files(["LICENSE"])
@@ -103,10 +107,10 @@ LINK_OPTS = select({
 load(
     ":protobuf.bzl",
     "cc_proto_library",
-    "py_proto_library",
     "internal_copied_filegroup",
     "internal_gen_well_known_protos_java",
     "internal_protobuf_py_tests",
+    "py_proto_library",
 )
 
 cc_library(
@@ -493,6 +497,7 @@ cc_proto_library(
 COMMON_TEST_SRCS = [
     # AUTOGEN(common_test_srcs)
     "src/google/protobuf/arena_test_util.cc",
+    "src/google/protobuf/map_test_util.inc",
     "src/google/protobuf/test_util.cc",
     "src/google/protobuf/test_util.inc",
     "src/google/protobuf/testing/file.cc",
@@ -605,7 +610,7 @@ cc_test(
         "src/google/protobuf/wire_format_unittest.cc",
     ] + select({
         "//conditions:default": [
-            # Doesn't pass on Windows with MSVC
+            # AUTOGEN(non_msvc_test_srcs)
             "src/google/protobuf/compiler/command_line_interface_unittest.cc",
         ],
         ":msvc": [],
@@ -1216,3 +1221,20 @@ cc_binary(
         ":text_format_conformance_suite",
     ],
 )
+
+sh_test(
+    name = "build_files_updated_unittest",
+    srcs = [
+        "build_files_updated_unittest.sh",
+    ],
+    data = [
+        "BUILD",
+        "cmake/extract_includes.bat.in",
+        "cmake/libprotobuf.cmake",
+        "cmake/libprotobuf-lite.cmake",
+        "cmake/libprotoc.cmake",
+        "cmake/tests.cmake",
+        "src/Makefile.am",
+        "update_file_lists.sh",
+    ],
+)

+ 2 - 0
Makefile.am

@@ -339,6 +339,7 @@ java_EXTRA_DIST=
   java/core/src/main/java/com/google/protobuf/TextFormatEscaper.java               \
   java/core/src/main/java/com/google/protobuf/TextFormatParseInfoTree.java         \
   java/core/src/main/java/com/google/protobuf/TextFormatParseLocation.java         \
+  java/core/src/main/java/com/google/protobuf/TypeRegistry.java                    \
   java/core/src/main/java/com/google/protobuf/UninitializedMessageException.java   \
   java/core/src/main/java/com/google/protobuf/UnknownFieldSchema.java              \
   java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java                 \
@@ -435,6 +436,7 @@ java_EXTRA_DIST=
   java/core/src/test/java/com/google/protobuf/TextFormatParseInfoTreeTest.java     \
   java/core/src/test/java/com/google/protobuf/TextFormatParseLocationTest.java     \
   java/core/src/test/java/com/google/protobuf/TextFormatTest.java                  \
+  java/core/src/test/java/com/google/protobuf/TypeRegistryTest.java                \
   java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java            \
   java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java             \
   java/core/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java  \

+ 42 - 0
Protobuf-C++.podspec

@@ -0,0 +1,42 @@
+Pod::Spec.new do |s|
+  s.name     = 'Protobuf-C++'
+  s.version  = '3.9.0-rc1'
+  s.summary  = 'Protocol Buffers v3 runtime library for C++.'
+  s.homepage = 'https://github.com/google/protobuf'
+  s.license  = '3-Clause BSD License'
+  s.authors  = { 'The Protocol Buffers contributors' => 'protobuf@googlegroups.com' }
+  s.cocoapods_version = '>= 1.0'
+
+  s.source = { :git => 'https://github.com/google/protobuf.git',
+               :tag => "v#{s.version}" }
+
+  s.source_files = 'src/google/protobuf/*.{h,cc,inc}',
+                   'src/google/protobuf/stubs/*.{h,cc}',
+                   'src/google/protobuf/io/*.{h,cc}',
+                   'src/google/protobuf/util/*.{h,cc}',
+                   'src/google/protobuf/util/internal/*.{h,cc}'
+
+  # Excluding all the tests in the directories above
+  s.exclude_files = 'src/google/**/*_test.{h,cc,inc}',
+                    'src/google/**/*_unittest.{h,cc}',
+                    'src/google/protobuf/test_util*.{h,cc}',
+                    'src/google/protobuf/map_lite_test_util.{h,cc}',
+                    'src/google/protobuf/map_test_util*.{h,cc,inc}'
+
+  s.header_mappings_dir = 'src'
+
+  s.ios.deployment_target = '7.0'
+  s.osx.deployment_target = '10.9'
+  s.tvos.deployment_target = '9.0'
+  s.watchos.deployment_target = '2.0'
+
+  s.pod_target_xcconfig = {
+    # Do not let src/google/protobuf/stubs/time.h override system API
+    'USE_HEADERMAP' => 'NO',
+    'ALWAYS_SEARCH_USER_PATHS' => 'NO',
+
+    # Configure tool is not being used for Xcode. When building, assume pthread is supported.
+    'GCC_PREPROCESSOR_DEFINITIONS' => '"$(inherited)" "HAVE_PTHREAD=1"',
+  }
+
+end

+ 62 - 0
build_files_updated_unittest.sh

@@ -0,0 +1,62 @@
+#!/bin/bash
+
+# This script verifies that BUILD files and cmake files are in sync with src/Makefile.am
+
+set -eo pipefail
+
+if [ "$(uname)" != "Linux" ]; then
+  echo "build_files_updated_unittest only supported on Linux. Skipping..."
+  exit 0
+fi
+
+# Keep in sync with files needed by update_file_lists.sh
+generated_files=(
+  "BUILD"
+  "cmake/extract_includes.bat.in"
+  "cmake/libprotobuf-lite.cmake"
+  "cmake/libprotobuf.cmake"
+  "cmake/libprotoc.cmake"
+  "cmake/tests.cmake"
+  "src/Makefile.am"
+)
+
+# If we're running in Bazel, use the Bazel-provided temp-dir.
+if [ -n "${TEST_TMPDIR}" ]; then
+  # Env-var TEST_TMPDIR is set, assume that this is Bazel.
+  # Bazel may have opinions whether we are allowed to delete TEST_TMPDIR.
+  test_root="${TEST_TMPDIR}/build_files_updated_unittest"
+  mkdir "${test_root}"
+else
+  # Seems like we're not executed by Bazel.
+  test_root=$(mktemp -d)
+fi
+
+# From now on, fail if there are any unbound variables.
+set -u
+
+# Remove artifacts after test is finished.
+function cleanup {
+  rm -rf "${test_root}"
+}
+trap cleanup EXIT
+
+# Create golden dir and add snapshot of current state.
+golden_dir="${test_root}/golden"
+mkdir -p "${golden_dir}/cmake" "${golden_dir}/src"
+for file in ${generated_files[@]}; do
+  cp "${file}" "${golden_dir}/${file}"
+done
+
+# Create test dir, copy current state into it, and execute update script.
+test_dir="${test_root}/test"
+cp -R "${golden_dir}" "${test_dir}"
+
+cp "update_file_lists.sh" "${test_dir}/update_file_lists.sh"
+chmod +x "${test_dir}/update_file_lists.sh"
+cd "${test_root}/test"
+bash "${test_dir}/update_file_lists.sh"
+
+# Test whether there are any differences
+for file in ${generated_files[@]}; do
+  diff "${golden_dir}/${file}" "${test_dir}/${file}"
+done

+ 1 - 0
cmake/extract_includes.bat.in

@@ -92,6 +92,7 @@ copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\fastmem.h" incl
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\hash.h" include\google\protobuf\stubs\hash.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\logging.h" include\google\protobuf\stubs\logging.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\macros.h" include\google\protobuf\stubs\macros.h
+copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\map_util.h" include\google\protobuf\stubs\map_util.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\mutex.h" include\google\protobuf\stubs\mutex.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\once.h" include\google\protobuf\stubs\once.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\platform_macros.h" include\google\protobuf\stubs\platform_macros.h

+ 1 - 1
cmake/libprotobuf-lite.cmake

@@ -10,7 +10,7 @@ set(libprotobuf_lite_files
   ${protobuf_source_dir}/src/google/protobuf/io/io_win32.cc
   ${protobuf_source_dir}/src/google/protobuf/io/strtod.cc
   ${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream.cc
-   ${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream_impl.cc
+  ${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream_impl.cc
   ${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
   ${protobuf_source_dir}/src/google/protobuf/message_lite.cc
   ${protobuf_source_dir}/src/google/protobuf/parse_context.cc

+ 11 - 3
cmake/tests.cmake

@@ -132,7 +132,6 @@ set(tests_files
   ${protobuf_source_dir}/src/google/protobuf/arena_unittest.cc
   ${protobuf_source_dir}/src/google/protobuf/arenastring_unittest.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/annotation_test_util.cc
-  ${protobuf_source_dir}/src/google/protobuf/compiler/command_line_interface_unittest.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_move_unittest.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc
@@ -203,12 +202,21 @@ set(tests_files
   ${protobuf_source_dir}/src/google/protobuf/wire_format_unittest.cc
 )
 
+set(non_msvc_tests_files
+  ${protobuf_source_dir}/src/google/protobuf/compiler/command_line_interface_unittest.cc
+)
+
+set(all_tests_files
+  ${tests_files}
+  ${non_msvc_tests_files}
+)
+
 if(protobuf_ABSOLUTE_TEST_PLUGIN_PATH)
   add_compile_options(-DGOOGLE_PROTOBUF_TEST_PLUGIN_PATH="$<TARGET_FILE:test_plugin>")
 endif()
 
 if(MINGW)
-  set_source_files_properties(${tests_files} PROPERTIES COMPILE_FLAGS "-Wno-narrowing")
+  set_source_files_properties(${all_tests_files} PROPERTIES COMPILE_FLAGS "-Wno-narrowing")
 
   # required for tests on MinGW Win64
   if (CMAKE_SIZEOF_VOID_P EQUAL 8)
@@ -218,7 +226,7 @@ if(MINGW)
 
 endif()
 
-add_executable(tests ${tests_files} ${common_test_files} ${tests_proto_files} ${lite_test_proto_files})
+add_executable(tests ${all_tests_files} ${common_test_files} ${tests_proto_files} ${lite_test_proto_files})
 target_link_libraries(tests libprotoc libprotobuf gmock_main)
 
 set(test_plugin_files

+ 222 - 74
conformance/binary_json_conformance_suite.cc

@@ -149,10 +149,6 @@ string tag(uint32_t fieldnum, char wire_type) {
   return varint((fieldnum << 3) | wire_type);
 }
 
-string submsg(uint32_t fn, const string& buf) {
-  return cat( tag(fn, WireFormatLite::WIRETYPE_LENGTH_DELIMITED), delim(buf) );
-}
-
 #define UNKNOWN_FIELD 666
 
 const FieldDescriptor* GetFieldForType(FieldDescriptor::Type type,
@@ -375,12 +371,21 @@ void BinaryAndJsonConformanceSuite::RunValidProtobufTest(
 void BinaryAndJsonConformanceSuite::RunValidBinaryProtobufTest(
     const string& test_name, ConformanceLevel level,
     const string& input_protobuf, bool is_proto3) {
+  RunValidBinaryProtobufTest(
+      test_name, level, input_protobuf, input_protobuf, is_proto3);
+}
+
+void BinaryAndJsonConformanceSuite::RunValidBinaryProtobufTest(
+    const string& test_name, ConformanceLevel level,
+    const string& input_protobuf,
+    const string& expected_protobuf,
+    bool is_proto3) {
   std::unique_ptr<Message> prototype = NewTestMessage(is_proto3);
   ConformanceRequestSetting setting(
       level, conformance::PROTOBUF, conformance::PROTOBUF,
       conformance::BINARY_TEST,
       *prototype, test_name, input_protobuf);
-  RunValidBinaryInputTest(setting, input_protobuf);
+  RunValidBinaryInputTest(setting, expected_protobuf, true);
 }
 
 void BinaryAndJsonConformanceSuite::RunValidProtobufTestWithMessage(
@@ -594,27 +599,149 @@ void BinaryAndJsonConformanceSuite::TestValidDataForType(
     const FieldDescriptor* field = GetFieldForType(type, false, is_proto3);
     const FieldDescriptor* rep_field = GetFieldForType(type, true, is_proto3);
 
-    RunValidProtobufTest("ValidDataScalar" + type_name, REQUIRED,
-                         cat(tag(field->number(), wire_type), values[0].first),
-                         field->name() + ": " + values[0].second, is_proto3);
-
-    string proto;
-    string text = field->name() + ": " + values.back().second;
+    // Test singular data for singular fields.
     for (size_t i = 0; i < values.size(); i++) {
-      proto += cat(tag(field->number(), wire_type), values[i].first);
+      string proto =
+          cat(tag(field->number(), wire_type), values[i].first);
+      string expected_proto =
+          cat(tag(field->number(), wire_type), values[i].second);
+      std::unique_ptr<Message> test_message = NewTestMessage(is_proto3);
+      test_message->MergeFromString(expected_proto);
+      string text = test_message->DebugString();
+
+      RunValidProtobufTest(StrCat("ValidDataScalar", type_name, "[", i, "]"),
+                           REQUIRED, proto, text, is_proto3);
+    }
+
+    // Test repeated data for singular fields.
+    // For scalar message fields, repeated values are merged, which is tested
+    // separately.
+    if (type != FieldDescriptor::TYPE_MESSAGE) {
+      string proto;
+      for (size_t i = 0; i < values.size(); i++) {
+        proto += cat(tag(field->number(), wire_type), values[i].first);
+      }
+      string expected_proto =
+          cat(tag(field->number(), wire_type), values.back().second);
+      std::unique_ptr<Message> test_message = NewTestMessage(is_proto3);
+      test_message->MergeFromString(expected_proto);
+      string text = test_message->DebugString();
+
+      RunValidProtobufTest("RepeatedScalarSelectsLast" + type_name, REQUIRED,
+                           proto, text, is_proto3);
+    }
+
+    // Test repeated fields.
+    if (FieldDescriptor::IsTypePackable(type)) {
+      string packed_proto;
+      string unpacked_proto;
+      string packed_proto_expected;
+      string unpacked_proto_expected;
+
+      for (size_t i = 0; i < values.size(); i++) {
+        unpacked_proto +=
+            cat(tag(rep_field->number(), wire_type), values[i].first);
+        unpacked_proto_expected +=
+            cat(tag(rep_field->number(), wire_type), values[i].second);
+        packed_proto += values[i].first;
+        packed_proto_expected += values[i].second;
+      }
+      packed_proto =
+          cat(tag(rep_field->number(),
+                  WireFormatLite::WIRETYPE_LENGTH_DELIMITED),
+              delim(packed_proto));
+      packed_proto_expected =
+          cat(tag(rep_field->number(),
+                  WireFormatLite::WIRETYPE_LENGTH_DELIMITED),
+              delim(packed_proto_expected));
+
+      std::unique_ptr<Message> test_message = NewTestMessage(is_proto3);
+      test_message->MergeFromString(packed_proto_expected);
+      string text = test_message->DebugString();
+
+      // Ensures both packed and unpacked data can be parsed.
+      RunValidProtobufTest(
+          StrCat("ValidDataRepeated", type_name, ".UnpackedInput"),
+          REQUIRED, unpacked_proto, text, is_proto3);
+      RunValidProtobufTest(
+          StrCat("ValidDataRepeated", type_name, ".PackedInput"),
+          REQUIRED, packed_proto, text, is_proto3);
+
+      // proto2 should encode as unpacked by default and proto3 should encode as
+      // packed by default.
+      string expected_proto =
+          rep_field->is_packed() ? packed_proto_expected :
+                                   unpacked_proto_expected;
+      RunValidBinaryProtobufTest(
+          StrCat("ValidDataRepeated", type_name,
+                 ".UnpackedInput.DefaultOutput"),
+          RECOMMENDED,
+          unpacked_proto,
+          expected_proto, is_proto3);
+      RunValidBinaryProtobufTest(
+          StrCat("ValidDataRepeated", type_name,
+                 ".PackedInput.DefaultOutput"),
+          RECOMMENDED,
+          packed_proto,
+          expected_proto, is_proto3);
+    } else {
+      string proto;
+      string expected_proto;
+      for (size_t i = 0; i < values.size(); i++) {
+        proto += cat(tag(rep_field->number(), wire_type), values[i].first);
+        expected_proto +=
+            cat(tag(rep_field->number(), wire_type), values[i].second);
+      }
+      std::unique_ptr<Message> test_message = NewTestMessage(is_proto3);
+      test_message->MergeFromString(expected_proto);
+      string text = test_message->DebugString();
+
+      RunValidProtobufTest(
+          StrCat("ValidDataRepeated", type_name),
+          REQUIRED, proto, text, is_proto3);
     }
-    RunValidProtobufTest("RepeatedScalarSelectsLast" + type_name, REQUIRED,
-                         proto, text, is_proto3);
+  }
+}
 
-    proto.clear();
-    text.clear();
+void BinaryAndJsonConformanceSuite::TestValidDataForRepeatedScalarMessage() {
+  std::vector<std::string> values = {
+      delim(cat(tag(2, WireFormatLite::WIRETYPE_LENGTH_DELIMITED),
+                delim(cat(
+                    tag(1, WireFormatLite::WIRETYPE_VARINT), varint(1234),
+                    tag(2, WireFormatLite::WIRETYPE_VARINT), varint(1234),
+                    tag(31, WireFormatLite::WIRETYPE_VARINT), varint(1234)
+                )))),
+      delim(cat(tag(2, WireFormatLite::WIRETYPE_LENGTH_DELIMITED),
+                delim(cat(
+                    tag(1, WireFormatLite::WIRETYPE_VARINT), varint(4321),
+                    tag(3, WireFormatLite::WIRETYPE_VARINT), varint(4321),
+                    tag(31, WireFormatLite::WIRETYPE_VARINT), varint(4321)
+                )))),
+  };
+
+  const std::string expected =
+      R"({
+        corecursive: {
+          optional_int32: 4321,
+          optional_int64: 1234,
+          optional_uint32: 4321,
+          repeated_int32: [1234, 4321],
+        }
+      })";
 
+  for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) {
+    string proto;
+    const FieldDescriptor* field =
+        GetFieldForType(FieldDescriptor::TYPE_MESSAGE, false, is_proto3);
     for (size_t i = 0; i < values.size(); i++) {
-      proto += cat(tag(rep_field->number(), wire_type), values[i].first);
-      text += rep_field->name() + ": " + values[i].second + " ";
+      proto +=
+          cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED),
+              values[i]);
     }
-    RunValidProtobufTest("ValidDataRepeated" + type_name, REQUIRED,
-                         proto, text, is_proto3);
+
+    RunValidProtobufTest(
+        "RepeatedScalarMessageMerge", REQUIRED, proto,
+        field->name() + ": " + expected, is_proto3);
   }
 }
 
@@ -714,88 +841,109 @@ void BinaryAndJsonConformanceSuite::RunSuiteImpl() {
   uint32 kUint32Max = 4294967295UL;
 
   TestValidDataForType(FieldDescriptor::TYPE_DOUBLE, {
-    {dbl(0.1), "0.1"},
-    {dbl(1.7976931348623157e+308), "1.7976931348623157e+308"},
-    {dbl(2.22507385850720138309e-308), "2.22507385850720138309e-308"}
+    {dbl(0.1), dbl(0.1)},
+    {dbl(1.7976931348623157e+308), dbl(1.7976931348623157e+308)},
+    {dbl(2.22507385850720138309e-308), dbl(2.22507385850720138309e-308)}
   });
   TestValidDataForType(FieldDescriptor::TYPE_FLOAT, {
-    {flt(0.1), "0.1"},
-    {flt(1.00000075e-36), "1.00000075e-36"},
-    {flt(3.402823e+38), "3.402823e+38"},  // 3.40282347e+38
-    {flt(1.17549435e-38f), "1.17549435e-38"}
+    {flt(0.1), flt(0.1)},
+    {flt(1.00000075e-36), flt(1.00000075e-36)},
+    {flt(3.402823e+38), flt(3.402823e+38)},  // 3.40282347e+38
+    {flt(1.17549435e-38f), flt(1.17549435e-38)}
   });
   TestValidDataForType(FieldDescriptor::TYPE_INT64, {
-    {varint(12345), "12345"},
-    {varint(kInt64Max), std::to_string(kInt64Max)},
-    {varint(kInt64Min), std::to_string(kInt64Min)}
+    {varint(12345), varint(12345)},
+    {varint(kInt64Max), varint(kInt64Max)},
+    {varint(kInt64Min), varint(kInt64Min)}
   });
   TestValidDataForType(FieldDescriptor::TYPE_UINT64, {
-    {varint(12345), "12345"},
-    {varint(kUint64Max), std::to_string(kUint64Max)},
-    {varint(0), "0"}
+    {varint(12345), varint(12345)},
+    {varint(kUint64Max), varint(kUint64Max)},
+    {varint(0), varint(0)}
   });
   TestValidDataForType(FieldDescriptor::TYPE_INT32, {
-    {varint(12345), "12345"},
-    {longvarint(12345, 2), "12345"},
-    {longvarint(12345, 7), "12345"},
-    {varint(kInt32Max), std::to_string(kInt32Max)},
-    {varint(kInt32Min), std::to_string(kInt32Min)},
-    {varint(1LL << 33), std::to_string(static_cast<int32>(1LL << 33))},
-    {varint((1LL << 33) - 1),
-     std::to_string(static_cast<int32>((1LL << 33) - 1))},
+    {varint(12345), varint(12345)},
+    {longvarint(12345, 2), varint(12345)},
+    {longvarint(12345, 7), varint(12345)},
+    {varint(kInt32Max), varint(kInt32Max)},
+    {varint(kInt32Min), varint(kInt32Min)},
+    {varint(1LL << 33), varint(0)},
+    {varint((1LL << 33) - 1), varint(-1)},
   });
   TestValidDataForType(FieldDescriptor::TYPE_UINT32, {
-    {varint(12345), "12345"},
-    {longvarint(12345, 2), "12345"},
-    {longvarint(12345, 7), "12345"},
-    {varint(kUint32Max), std::to_string(kUint32Max)},  // UINT32_MAX
-    {varint(0), "0"},
-    {varint(1LL << 33), std::to_string(static_cast<uint32>(1LL << 33))},
-    {varint((1LL << 33) - 1),
-     std::to_string(static_cast<uint32>((1LL << 33) - 1))},
+    {varint(12345), varint(12345)},
+    {longvarint(12345, 2), varint(12345)},
+    {longvarint(12345, 7), varint(12345)},
+    {varint(kUint32Max), varint(kUint32Max)},  // UINT32_MAX
+    {varint(0), varint(0)},
+    {varint(1LL << 33), varint(0)},
+    {varint((1LL << 33) - 1), varint((1LL << 32) - 1)},
   });
   TestValidDataForType(FieldDescriptor::TYPE_FIXED64, {
-    {u64(12345), "12345"},
-    {u64(kUint64Max), std::to_string(kUint64Max)},
-    {u64(0), "0"}
+    {u64(12345), u64(12345)},
+    {u64(kUint64Max), u64(kUint64Max)},
+    {u64(0), u64(0)}
   });
   TestValidDataForType(FieldDescriptor::TYPE_FIXED32, {
-    {u32(12345), "12345"},
-    {u32(kUint32Max), std::to_string(kUint32Max)},  // UINT32_MAX
-    {u32(0), "0"}
+    {u32(12345), u32(12345)},
+    {u32(kUint32Max), u32(kUint32Max)},  // UINT32_MAX
+    {u32(0), u32(0)}
   });
   TestValidDataForType(FieldDescriptor::TYPE_SFIXED64, {
-    {u64(12345), "12345"},
-    {u64(kInt64Max), std::to_string(kInt64Max)},
-    {u64(kInt64Min), std::to_string(kInt64Min)}
+    {u64(12345), u64(12345)},
+    {u64(kInt64Max), u64(kInt64Max)},
+    {u64(kInt64Min), u64(kInt64Min)}
   });
   TestValidDataForType(FieldDescriptor::TYPE_SFIXED32, {
-    {u32(12345), "12345"},
-    {u32(kInt32Max), std::to_string(kInt32Max)},
-    {u32(kInt32Min), std::to_string(kInt32Min)}
+    {u32(12345), u32(12345)},
+    {u32(kInt32Max), u32(kInt32Max)},
+    {u32(kInt32Min), u32(kInt32Min)}
   });
   TestValidDataForType(FieldDescriptor::TYPE_BOOL, {
-    {varint(1), "true"},
-    {varint(0), "false"},
-    {varint(12345678), "true"}
+    {varint(1), varint(1)},
+    {varint(0), varint(0)},
+    {varint(12345678), varint(1)}
   });
   TestValidDataForType(FieldDescriptor::TYPE_SINT32, {
-    {zz32(12345), "12345"},
-    {zz32(kInt32Max), std::to_string(kInt32Max)},
-    {zz32(kInt32Min), std::to_string(kInt32Min)}
+    {zz32(12345), zz32(12345)},
+    {zz32(kInt32Max), zz32(kInt32Max)},
+    {zz32(kInt32Min), zz32(kInt32Min)}
   });
   TestValidDataForType(FieldDescriptor::TYPE_SINT64, {
-    {zz64(12345), "12345"},
-    {zz64(kInt64Max), std::to_string(kInt64Max)},
-    {zz64(kInt64Min), std::to_string(kInt64Min)}
+    {zz64(12345), zz64(12345)},
+    {zz64(kInt64Max), zz64(kInt64Max)},
+    {zz64(kInt64Min), zz64(kInt64Min)}
+  });
+  TestValidDataForType(FieldDescriptor::TYPE_STRING, {
+    {delim("Hello world!"), delim("Hello world!")},
+    {delim("\'\"\?\\\a\b\f\n\r\t\v"),
+     delim("\'\"\?\\\a\b\f\n\r\t\v")},  // escape
+    {delim("谷歌"), delim("谷歌")},  // Google in Chinese
+    {delim("\u8C37\u6B4C"), delim("谷歌")},  // unicode escape
+    {delim("\u8c37\u6b4c"), delim("谷歌")},  // lowercase unicode
+    {delim("\xF0\x9F\x98\x81"), delim("\xF0\x9F\x98\x81")},  // emoji: 😁
+    {delim(""), delim("")},
+  });
+  TestValidDataForType(FieldDescriptor::TYPE_BYTES, {
+    {delim("\x01\x02"), delim("\x01\x02")},
+    {delim("\xfb"), delim("\xfb")},
+    {delim(""), delim("")},
+  });
+  TestValidDataForType(FieldDescriptor::TYPE_ENUM, {
+    {varint(0), varint(0)},
+    {varint(1), varint(1)},
+    {varint(2), varint(2)},
+    {varint(-1), varint(-1)},
+  });
+  TestValidDataForRepeatedScalarMessage();
+  TestValidDataForType(FieldDescriptor::TYPE_MESSAGE, {
+    {delim(cat(tag(1, WireFormatLite::WIRETYPE_VARINT), varint(1234))),
+     delim(cat(tag(1, WireFormatLite::WIRETYPE_VARINT), varint(1234)))},
+    {delim(""), delim("")},
   });
 
   // TODO(haberman):
-  // TestValidDataForType(FieldDescriptor::TYPE_STRING
   // TestValidDataForType(FieldDescriptor::TYPE_GROUP
-  // TestValidDataForType(FieldDescriptor::TYPE_MESSAGE
-  // TestValidDataForType(FieldDescriptor::TYPE_BYTES
-  // TestValidDataForType(FieldDescriptor::TYPE_ENUM
 
   RunValidJsonTest("HelloWorld", REQUIRED,
                    "{\"optionalString\":\"Hello, World!\"}",

+ 6 - 0
conformance/binary_json_conformance_suite.h

@@ -63,6 +63,11 @@ class BinaryAndJsonConformanceSuite : public ConformanceTestSuite {
                                   ConformanceLevel level,
                                   const string& input_protobuf,
                                   bool is_proto3);
+  void RunValidBinaryProtobufTest(const string& test_name,
+                                  ConformanceLevel level,
+                                  const string& input_protobuf,
+                                  const string& expected_protobuf,
+                                  bool is_proto3);
   void RunValidProtobufTestWithMessage(
       const string& test_name, ConformanceLevel level,
       const Message *input,
@@ -109,6 +114,7 @@ class BinaryAndJsonConformanceSuite : public ConformanceTestSuite {
   void TestValidDataForType(
       google::protobuf::FieldDescriptor::Type,
       std::vector<std::pair<std::string, std::string>> values);
+  void TestValidDataForRepeatedScalarMessage();
 
   std::unique_ptr<google::protobuf::util::TypeResolver>
       type_resolver_;

+ 8 - 3
conformance/conformance_objc.m

@@ -68,7 +68,8 @@ static ConformanceResponse *DoTest(ConformanceRequest *request) {
 
   switch (request.payloadOneOfCase) {
     case ConformanceRequest_Payload_OneOfCase_GPBUnsetOneOfCase:
-      Die(@"Request didn't have a payload: %@", request);
+      response.runtimeError =
+          [NSString stringWithFormat:@"Request didn't have a payload: %@", request];
       break;
 
     case ConformanceRequest_Payload_OneOfCase_ProtobufPayload: {
@@ -78,7 +79,10 @@ static ConformanceResponse *DoTest(ConformanceRequest *request) {
       } else if ([request.messageType isEqual:@"protobuf_test_messages.proto2.TestAllTypesProto2"]) {
         msgClass = [TestAllTypesProto2 class];
       } else {
-        Die(@"Protobuf request had an unknown message_type: %@", request.messageType);
+        response.runtimeError =
+            [NSString stringWithFormat:
+                @"Protobuf request had an unknown message_type: %@", request.messageType];
+        break;
       }
       NSError *error = nil;
       testMessage = [msgClass parseFromData:request.protobufPayload error:&error];
@@ -108,7 +112,8 @@ static ConformanceResponse *DoTest(ConformanceRequest *request) {
     switch (request.requestedOutputFormat) {
       case WireFormat_GPBUnrecognizedEnumeratorValue:
       case WireFormat_Unspecified:
-        Die(@"Unrecognized/unspecified output format: %@", request);
+        response.runtimeError =
+            [NSString stringWithFormat:@"Unrecognized/unspecified output format: %@", request];
         break;
 
       case WireFormat_Protobuf:

+ 38 - 5
conformance/conformance_test.cc

@@ -54,6 +54,25 @@ using google::protobuf::util::MessageDifferencer;
 using google::protobuf::util::Status;
 using std::string;
 
+namespace {
+
+static string ToOctString(const string& binary_string) {
+  string oct_string;
+  for (size_t i = 0; i < binary_string.size(); i++) {
+    uint8_t c = binary_string.at(i);
+    uint8_t high = c / 64;
+    uint8_t mid = (c % 64) / 8;
+    uint8_t low = c % 8;
+    oct_string.push_back('\\');
+    oct_string.push_back('0' + high);
+    oct_string.push_back('0' + mid);
+    oct_string.push_back('0' + low);
+  }
+  return oct_string;
+}
+
+}
+
 namespace google {
 namespace protobuf {
 
@@ -220,18 +239,21 @@ void ConformanceTestSuite::RunValidInputTest(
 
 void ConformanceTestSuite::RunValidBinaryInputTest(
     const ConformanceRequestSetting& setting,
-    const string& equivalent_wire_format) {
+    const string& equivalent_wire_format,
+    bool require_same_wire_format) {
   const ConformanceRequest& request = setting.GetRequest();
   ConformanceResponse response;
   RunTest(setting.GetTestName(), request, &response);
-  VerifyResponse(setting, equivalent_wire_format, response, true);
+  VerifyResponse(setting, equivalent_wire_format, response,
+                 true, require_same_wire_format);
 }
 
 void ConformanceTestSuite::VerifyResponse(
     const ConformanceRequestSetting& setting,
     const string& equivalent_wire_format,
     const ConformanceResponse& response,
-    bool need_report_success) {
+    bool need_report_success,
+    bool require_same_wire_format) {
   Message* test_message = setting.GetTestMessage();
   const ConformanceRequest& request = setting.GetRequest();
   const string& test_name = setting.GetTestName();
@@ -270,8 +292,19 @@ void ConformanceTestSuite::VerifyResponse(
   string differences;
   differencer.ReportDifferencesToString(&differences);
 
-  bool check;
-  check = differencer.Compare(*reference_message, *test_message);
+  bool check = false;
+
+  if (require_same_wire_format) {
+    GOOGLE_DCHECK_EQ(response.result_case(),
+                    ConformanceResponse::kProtobufPayload);
+    const string& protobuf_payload =  response.protobuf_payload();
+    check = equivalent_wire_format == protobuf_payload;
+    differences = StrCat("Expect: ", ToOctString(equivalent_wire_format),
+                         ", but got: ", ToOctString(protobuf_payload));
+  } else {
+    check = differencer.Compare(*reference_message, *test_message);
+  }
+
   if (check) {
     if (need_report_success) {
       ReportSuccess(test_name);

+ 4 - 2
conformance/conformance_test.h

@@ -261,7 +261,8 @@ class ConformanceTestSuite {
       const ConformanceRequestSetting& setting,
       const string& equivalent_wire_format,
       const conformance::ConformanceResponse& response,
-      bool need_report_success);
+      bool need_report_success,
+      bool require_same_wire_format);
 
   void ReportSuccess(const std::string& test_name);
   void ReportFailure(const string& test_name,
@@ -276,7 +277,8 @@ class ConformanceTestSuite {
   void RunValidInputTest(const ConformanceRequestSetting& setting,
                          const string& equivalent_text_format);
   void RunValidBinaryInputTest(const ConformanceRequestSetting& setting,
-                               const string& equivalent_wire_format);
+                               const string& equivalent_wire_format,
+                               bool require_same_wire_format = false);
 
   void RunTest(const std::string& test_name,
                const conformance::ConformanceRequest& request,

+ 57 - 13
conformance/failure_list_js.txt

@@ -1,13 +1,57 @@
-Required.Proto3.ProtobufInput.ValidDataRepeated.BOOL.ProtobufOutput
-Required.Proto3.ProtobufInput.ValidDataRepeated.DOUBLE.ProtobufOutput
-Required.Proto3.ProtobufInput.ValidDataRepeated.FIXED32.ProtobufOutput
-Required.Proto3.ProtobufInput.ValidDataRepeated.FIXED64.ProtobufOutput
-Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.ProtobufOutput
-Required.Proto3.ProtobufInput.ValidDataRepeated.INT32.ProtobufOutput
-Required.Proto3.ProtobufInput.ValidDataRepeated.INT64.ProtobufOutput
-Required.Proto3.ProtobufInput.ValidDataRepeated.SFIXED32.ProtobufOutput
-Required.Proto3.ProtobufInput.ValidDataRepeated.SFIXED64.ProtobufOutput
-Required.Proto3.ProtobufInput.ValidDataRepeated.SINT32.ProtobufOutput
-Required.Proto3.ProtobufInput.ValidDataRepeated.SINT64.ProtobufOutput
-Required.Proto3.ProtobufInput.ValidDataRepeated.UINT32.ProtobufOutput
-Required.Proto3.ProtobufInput.ValidDataRepeated.UINT64.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.BOOL.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.DOUBLE.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.ENUM.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.FIXED32.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.FIXED64.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.FLOAT.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.INT32.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.INT64.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.SFIXED32.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.SFIXED64.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.SINT32.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.SINT64.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.UINT32.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.UINT64.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.BOOL.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.DOUBLE.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.ENUM.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED32.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED64.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT32.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT64.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED32.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED64.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT32.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT64.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT32.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.UnpackedInput.DefaultOutput.ProtobufOutput
+Required.Proto2.ProtobufInput.ValidDataRepeated.BOOL.PackedInput.ProtobufOutput
+Required.Proto2.ProtobufInput.ValidDataRepeated.DOUBLE.PackedInput.ProtobufOutput
+Required.Proto2.ProtobufInput.ValidDataRepeated.ENUM.PackedInput.ProtobufOutput
+Required.Proto2.ProtobufInput.ValidDataRepeated.FIXED32.PackedInput.ProtobufOutput
+Required.Proto2.ProtobufInput.ValidDataRepeated.FIXED64.PackedInput.ProtobufOutput
+Required.Proto2.ProtobufInput.ValidDataRepeated.FLOAT.PackedInput.ProtobufOutput
+Required.Proto2.ProtobufInput.ValidDataRepeated.INT32.PackedInput.ProtobufOutput
+Required.Proto2.ProtobufInput.ValidDataRepeated.INT64.PackedInput.ProtobufOutput
+Required.Proto2.ProtobufInput.ValidDataRepeated.SFIXED32.PackedInput.ProtobufOutput
+Required.Proto2.ProtobufInput.ValidDataRepeated.SFIXED64.PackedInput.ProtobufOutput
+Required.Proto2.ProtobufInput.ValidDataRepeated.SINT32.PackedInput.ProtobufOutput
+Required.Proto2.ProtobufInput.ValidDataRepeated.SINT64.PackedInput.ProtobufOutput
+Required.Proto2.ProtobufInput.ValidDataRepeated.UINT32.PackedInput.ProtobufOutput
+Required.Proto2.ProtobufInput.ValidDataRepeated.UINT64.PackedInput.ProtobufOutput
+Required.Proto3.ProtobufInput.RepeatedScalarMessageMerge.ProtobufOutput
+Required.Proto3.ProtobufInput.ValidDataRepeated.BOOL.UnpackedInput.ProtobufOutput
+Required.Proto3.ProtobufInput.ValidDataRepeated.DOUBLE.UnpackedInput.ProtobufOutput
+Required.Proto3.ProtobufInput.ValidDataRepeated.ENUM.UnpackedInput.ProtobufOutput
+Required.Proto3.ProtobufInput.ValidDataRepeated.FIXED32.UnpackedInput.ProtobufOutput
+Required.Proto3.ProtobufInput.ValidDataRepeated.FIXED64.UnpackedInput.ProtobufOutput
+Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.UnpackedInput.ProtobufOutput
+Required.Proto3.ProtobufInput.ValidDataRepeated.INT32.UnpackedInput.ProtobufOutput
+Required.Proto3.ProtobufInput.ValidDataRepeated.INT64.UnpackedInput.ProtobufOutput
+Required.Proto3.ProtobufInput.ValidDataRepeated.SFIXED32.UnpackedInput.ProtobufOutput
+Required.Proto3.ProtobufInput.ValidDataRepeated.SFIXED64.UnpackedInput.ProtobufOutput
+Required.Proto3.ProtobufInput.ValidDataRepeated.SINT32.UnpackedInput.ProtobufOutput
+Required.Proto3.ProtobufInput.ValidDataRepeated.SINT64.UnpackedInput.ProtobufOutput
+Required.Proto3.ProtobufInput.ValidDataRepeated.UINT32.UnpackedInput.ProtobufOutput
+Required.Proto3.ProtobufInput.ValidDataRepeated.UINT64.UnpackedInput.ProtobufOutput

+ 4 - 0
conformance/failure_list_objc.txt

@@ -1,2 +1,6 @@
 # JSON input or output tests are skipped (in conformance_objc.m) as mobile
 # platforms don't support JSON wire format to avoid code bloat.
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.ENUM.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto2.ProtobufInput.ValidDataRepeated.ENUM.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.ENUM.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.ENUM.UnpackedInput.DefaultOutput.ProtobufOutput

+ 36 - 4
conformance/failure_list_php.txt

@@ -4,17 +4,49 @@ Recommended.FieldMaskTooManyUnderscore.JsonOutput
 Recommended.Proto3.JsonInput.BytesFieldBase64Url.JsonOutput
 Recommended.Proto3.JsonInput.BytesFieldBase64Url.ProtobufOutput
 Recommended.Proto3.JsonInput.FieldMaskInvalidCharacter
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.BOOL.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.BOOL.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.DOUBLE.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.DOUBLE.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.ENUM.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.ENUM.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED32.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED32.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED64.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED64.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT32.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT32.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT64.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT64.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED32.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED32.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED64.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED64.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT32.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT32.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT64.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT64.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT32.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT32.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.UnpackedInput.DefaultOutput.ProtobufOutput
+Required.Proto3.JsonInput.DoubleFieldTooSmall
 Required.Proto3.JsonInput.FloatFieldTooLarge
 Required.Proto3.JsonInput.FloatFieldTooSmall
-Required.Proto3.JsonInput.DoubleFieldTooSmall
+Required.Proto3.JsonInput.Int32FieldLeadingSpace
 Required.Proto3.JsonInput.Int32FieldNotInteger
 Required.Proto3.JsonInput.Int64FieldNotInteger
+Required.Proto3.JsonInput.OneofFieldDuplicate
 Required.Proto3.JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotInt
 Required.Proto3.JsonInput.RepeatedListValue.JsonOutput
 Required.Proto3.JsonInput.RepeatedListValue.ProtobufOutput
 Required.Proto3.JsonInput.StringFieldNotAString
 Required.Proto3.JsonInput.Uint32FieldNotInteger
 Required.Proto3.JsonInput.Uint64FieldNotInteger
-Required.Proto3.JsonInput.Int32FieldLeadingSpace
-Required.Proto3.JsonInput.OneofFieldDuplicate
-Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.JsonOutput
+Required.Proto3.ProtobufInput.RepeatedScalarMessageMerge.JsonOutput
+Required.Proto3.ProtobufInput.RepeatedScalarMessageMerge.ProtobufOutput
+Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.PackedInput.JsonOutput
+Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.UnpackedInput.JsonOutput
+Required.Proto3.ProtobufInput.ValidDataScalar.FLOAT[1].JsonOutput

+ 38 - 4
conformance/failure_list_php_c.txt

@@ -17,10 +17,36 @@ Recommended.Proto3.JsonInput.StringFieldUnpairedLowSurrogate
 Recommended.Proto3.JsonInput.TimestampHas3FractionalDigits.Validator
 Recommended.Proto3.JsonInput.TimestampHas6FractionalDigits.Validator
 Recommended.Proto3.ProtobufInput.OneofZeroBytes.JsonOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.BOOL.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.BOOL.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.DOUBLE.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.DOUBLE.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.ENUM.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.ENUM.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED32.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED32.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED64.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED64.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT32.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT32.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT64.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT64.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED32.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED32.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED64.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED64.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT32.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT32.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT64.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT64.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT32.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT32.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.UnpackedInput.DefaultOutput.ProtobufOutput
 Required.DurationProtoInputTooLarge.JsonOutput
 Required.DurationProtoInputTooSmall.JsonOutput
-Required.TimestampProtoInputTooLarge.JsonOutput
-Required.TimestampProtoInputTooSmall.JsonOutput
 Required.Proto3.JsonInput.DoubleFieldMaxNegativeValue.JsonOutput
 Required.Proto3.JsonInput.DoubleFieldMaxNegativeValue.ProtobufOutput
 Required.Proto3.JsonInput.DoubleFieldMinPositiveValue.JsonOutput
@@ -34,11 +60,19 @@ Required.Proto3.JsonInput.FloatFieldNegativeInfinity.JsonOutput
 Required.Proto3.JsonInput.OneofFieldDuplicate
 Required.Proto3.JsonInput.OptionalWrapperTypesWithNonDefaultValue.JsonOutput
 Required.Proto3.JsonInput.OptionalWrapperTypesWithNonDefaultValue.ProtobufOutput
+Required.Proto3.JsonInput.RejectTopLevelNull
 Required.Proto3.JsonInput.StringFieldSurrogatePair.JsonOutput
 Required.Proto3.JsonInput.StringFieldSurrogatePair.ProtobufOutput
 Required.Proto3.ProtobufInput.DoubleFieldNormalizeQuietNan.JsonOutput
 Required.Proto3.ProtobufInput.DoubleFieldNormalizeSignalingNan.JsonOutput
 Required.Proto3.ProtobufInput.FloatFieldNormalizeQuietNan.JsonOutput
 Required.Proto3.ProtobufInput.FloatFieldNormalizeSignalingNan.JsonOutput
-Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.JsonOutput
-Required.Proto3.JsonInput.RejectTopLevelNull
+Required.Proto3.ProtobufInput.ValidDataRepeated.BYTES.JsonOutput
+Required.Proto3.ProtobufInput.ValidDataRepeated.BYTES.ProtobufOutput
+Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.PackedInput.JsonOutput
+Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.UnpackedInput.JsonOutput
+Required.Proto3.ProtobufInput.ValidDataRepeated.STRING.JsonOutput
+Required.Proto3.ProtobufInput.ValidDataRepeated.STRING.ProtobufOutput
+Required.Proto3.ProtobufInput.ValidDataScalar.FLOAT[1].JsonOutput
+Required.TimestampProtoInputTooLarge.JsonOutput
+Required.TimestampProtoInputTooSmall.JsonOutput

+ 38 - 8
conformance/failure_list_ruby.txt

@@ -15,6 +15,34 @@ Recommended.Proto3.JsonInput.StringFieldUnpairedHighSurrogate
 Recommended.Proto3.JsonInput.StringFieldUnpairedLowSurrogate
 Recommended.Proto3.JsonInput.TimestampHas3FractionalDigits.Validator
 Recommended.Proto3.JsonInput.TimestampHas6FractionalDigits.Validator
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.BOOL.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.BOOL.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.DOUBLE.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.DOUBLE.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.ENUM.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.ENUM.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED32.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED32.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED64.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED64.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT32.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT32.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT64.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT64.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED32.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED32.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED64.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED64.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT32.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT32.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT64.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT64.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT32.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT32.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.UnpackedInput.DefaultOutput.ProtobufOutput
 Required.DurationProtoInputTooLarge.JsonOutput
 Required.DurationProtoInputTooSmall.JsonOutput
 Required.Proto3.JsonInput.DoubleFieldMaxNegativeValue.JsonOutput
@@ -27,6 +55,12 @@ Required.Proto3.JsonInput.DurationRepeatedValue.JsonOutput
 Required.Proto3.JsonInput.FloatFieldInfinity.JsonOutput
 Required.Proto3.JsonInput.FloatFieldNan.JsonOutput
 Required.Proto3.JsonInput.FloatFieldNegativeInfinity.JsonOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonFalse.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonNull.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonNumber.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonObject.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonString.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonTrue.ProtobufOutput
 Required.Proto3.JsonInput.OneofFieldDuplicate
 Required.Proto3.JsonInput.OptionalBoolWrapper.JsonOutput
 Required.Proto3.JsonInput.OptionalBytesWrapper.JsonOutput
@@ -39,6 +73,7 @@ Required.Proto3.JsonInput.OptionalUint32Wrapper.JsonOutput
 Required.Proto3.JsonInput.OptionalUint64Wrapper.JsonOutput
 Required.Proto3.JsonInput.OptionalWrapperTypesWithNonDefaultValue.JsonOutput
 Required.Proto3.JsonInput.OptionalWrapperTypesWithNonDefaultValue.ProtobufOutput
+Required.Proto3.JsonInput.RejectTopLevelNull
 Required.Proto3.JsonInput.RepeatedBoolWrapper.JsonOutput
 Required.Proto3.JsonInput.RepeatedBytesWrapper.JsonOutput
 Required.Proto3.JsonInput.RepeatedDoubleWrapper.JsonOutput
@@ -54,13 +89,8 @@ Required.Proto3.ProtobufInput.DoubleFieldNormalizeQuietNan.JsonOutput
 Required.Proto3.ProtobufInput.DoubleFieldNormalizeSignalingNan.JsonOutput
 Required.Proto3.ProtobufInput.FloatFieldNormalizeQuietNan.JsonOutput
 Required.Proto3.ProtobufInput.FloatFieldNormalizeSignalingNan.JsonOutput
-Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.JsonOutput
+Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.PackedInput.JsonOutput
+Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.UnpackedInput.JsonOutput
+Required.Proto3.ProtobufInput.ValidDataScalar.FLOAT[1].JsonOutput
 Required.TimestampProtoInputTooLarge.JsonOutput
 Required.TimestampProtoInputTooSmall.JsonOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonFalse.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonNull.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonNumber.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonObject.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonString.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonTrue.ProtobufOutput
-Required.Proto3.JsonInput.RejectTopLevelNull

+ 39 - 9
conformance/failure_list_ruby_mac.txt

@@ -5,6 +5,7 @@ Recommended.Proto3.JsonInput.BytesFieldBase64Url.JsonOutput
 Recommended.Proto3.JsonInput.BytesFieldBase64Url.ProtobufOutput
 Recommended.Proto3.JsonInput.DurationHas3FractionalDigits.Validator
 Recommended.Proto3.JsonInput.DurationHas6FractionalDigits.Validator
+Recommended.Proto3.JsonInput.FieldMaskInvalidCharacter
 Recommended.Proto3.JsonInput.MapFieldValueIsNull
 Recommended.Proto3.JsonInput.RepeatedFieldMessageElementIsNull
 Recommended.Proto3.JsonInput.RepeatedFieldPrimitiveElementIsNull
@@ -14,6 +15,34 @@ Recommended.Proto3.JsonInput.StringFieldUnpairedHighSurrogate
 Recommended.Proto3.JsonInput.StringFieldUnpairedLowSurrogate
 Recommended.Proto3.JsonInput.TimestampHas3FractionalDigits.Validator
 Recommended.Proto3.JsonInput.TimestampHas6FractionalDigits.Validator
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.BOOL.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.BOOL.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.DOUBLE.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.DOUBLE.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.ENUM.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.ENUM.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED32.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED32.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED64.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED64.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT32.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT32.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT64.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.INT64.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED32.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED32.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED64.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SFIXED64.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT32.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT32.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT64.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.SINT64.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT32.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT32.UnpackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.PackedInput.DefaultOutput.ProtobufOutput
+Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.UnpackedInput.DefaultOutput.ProtobufOutput
 Required.DurationProtoInputTooLarge.JsonOutput
 Required.DurationProtoInputTooSmall.JsonOutput
 Required.Proto3.JsonInput.DoubleFieldMaxNegativeValue.JsonOutput
@@ -26,6 +55,12 @@ Required.Proto3.JsonInput.DurationRepeatedValue.JsonOutput
 Required.Proto3.JsonInput.FloatFieldInfinity.JsonOutput
 Required.Proto3.JsonInput.FloatFieldNan.JsonOutput
 Required.Proto3.JsonInput.FloatFieldNegativeInfinity.JsonOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonFalse.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonNull.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonNumber.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonObject.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonString.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonTrue.ProtobufOutput
 Required.Proto3.JsonInput.OneofFieldDuplicate
 Required.Proto3.JsonInput.OptionalBoolWrapper.JsonOutput
 Required.Proto3.JsonInput.OptionalBytesWrapper.JsonOutput
@@ -38,6 +73,7 @@ Required.Proto3.JsonInput.OptionalUint32Wrapper.JsonOutput
 Required.Proto3.JsonInput.OptionalUint64Wrapper.JsonOutput
 Required.Proto3.JsonInput.OptionalWrapperTypesWithNonDefaultValue.JsonOutput
 Required.Proto3.JsonInput.OptionalWrapperTypesWithNonDefaultValue.ProtobufOutput
+Required.Proto3.JsonInput.RejectTopLevelNull
 Required.Proto3.JsonInput.RepeatedBoolWrapper.JsonOutput
 Required.Proto3.JsonInput.RepeatedBytesWrapper.JsonOutput
 Required.Proto3.JsonInput.RepeatedDoubleWrapper.JsonOutput
@@ -53,14 +89,8 @@ Required.Proto3.ProtobufInput.DoubleFieldNormalizeQuietNan.JsonOutput
 Required.Proto3.ProtobufInput.DoubleFieldNormalizeSignalingNan.JsonOutput
 Required.Proto3.ProtobufInput.FloatFieldNormalizeQuietNan.JsonOutput
 Required.Proto3.ProtobufInput.FloatFieldNormalizeSignalingNan.JsonOutput
-Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.JsonOutput
+Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.PackedInput.JsonOutput
+Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.UnpackedInput.JsonOutput
+Required.Proto3.ProtobufInput.ValidDataScalar.FLOAT[1].JsonOutput
 Required.TimestampProtoInputTooLarge.JsonOutput
 Required.TimestampProtoInputTooSmall.JsonOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonFalse.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonNull.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonNumber.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonObject.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonString.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonTrue.ProtobufOutput
-Recommended.Proto3.JsonInput.FieldMaskInvalidCharacter
-Required.Proto3.JsonInput.RejectTopLevelNull

+ 6 - 0
csharp/compatibility_tests/v3.0.0/test.sh

@@ -34,6 +34,8 @@ cd $(dirname $0)
 # these tests).
 TEST_VERSION=3.0.0
 
+LAST_RELEASED=3.9.0
+
 # The old version of protobuf that we are testing compatibility against. This
 # is usually the same as TEST_VERSION (i.e., we use the tests extracted from
 # that version to test compatibility of the newest runtime against it), but it
@@ -52,6 +54,10 @@ case "$1" in
     OLD_VERSION=3.1.0
     OLD_VERSION_PROTOC=http://repo1.maven.org/maven2/com/google/protobuf/protoc/3.1.0/protoc-3.1.0-linux-x86_64.exe
     ;;
+  $LAST_RELEASED)
+    OLD_VERSION=$LAST_RELEASED
+    OLD_VERSION_PROTOC=http://repo1.maven.org/maven2/com/google/protobuf/protoc/$OLD_VERSION/protoc-$OLD_VERSION-linux-x86_64.exe
+    ;;
   *)
     echo "[ERROR]: Unknown version number: $1"
     exit 1

BIN
csharp/src/Google.Protobuf.Test/testprotos.pb


+ 181 - 16
csharp/src/Google.Protobuf/FieldCodec.cs

@@ -45,13 +45,178 @@ namespace Google.Protobuf
     {
         // TODO: Avoid the "dual hit" of lambda expressions: create open delegates instead. (At least test...)
 
+        /// <summary>
+        /// Retrieves a codec suitable for a string field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<string> ForString(uint tag)
+        {
+            return FieldCodec.ForString(tag, "");
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a bytes field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<ByteString> ForBytes(uint tag)
+        {
+            return FieldCodec.ForBytes(tag, ByteString.Empty);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a bool field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<bool> ForBool(uint tag)
+        {
+            return FieldCodec.ForBool(tag, false);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an int32 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<int> ForInt32(uint tag)
+        {
+            return FieldCodec.ForInt32(tag, 0);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an sint32 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<int> ForSInt32(uint tag)
+        {
+            return FieldCodec.ForSInt32(tag, 0);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a fixed32 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<uint> ForFixed32(uint tag)
+        {
+            return FieldCodec.ForFixed32(tag, 0);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an sfixed32 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<int> ForSFixed32(uint tag)
+        {
+            return FieldCodec.ForSFixed32(tag, 0);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a uint32 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<uint> ForUInt32(uint tag)
+        {
+            return FieldCodec.ForUInt32(tag, 0);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an int64 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<long> ForInt64(uint tag)
+        {
+            return FieldCodec.ForInt64(tag, 0);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an sint64 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<long> ForSInt64(uint tag)
+        {
+            return FieldCodec.ForSInt64(tag, 0);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a fixed64 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<ulong> ForFixed64(uint tag)
+        {
+            return FieldCodec.ForFixed64(tag, 0);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for an sfixed64 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<long> ForSFixed64(uint tag)
+        {
+            return FieldCodec.ForSFixed64(tag, 0);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a uint64 field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<ulong> ForUInt64(uint tag)
+        {
+            return FieldCodec.ForUInt64(tag, 0);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a float field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<float> ForFloat(uint tag)
+        {
+            return FieldCodec.ForFloat(tag, 0);
+        }
+
+        /// <summary>
+        /// Retrieves a codec suitable for a double field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<double> ForDouble(uint tag)
+        {
+            return FieldCodec.ForDouble(tag, 0);
+        }
+
+        // Enums are tricky. We can probably use expression trees to build these delegates automatically,
+        // but it's easy to generate the code for it.
+
+        /// <summary>
+        /// Retrieves a codec suitable for an enum field with the given tag.
+        /// </summary>
+        /// <param name="tag">The tag.</param>
+        /// <param name="toInt32">A conversion function from <see cref="Int32"/> to the enum type.</param>
+        /// <param name="fromInt32">A conversion function from the enum type to <see cref="Int32"/>.</param>
+        /// <returns>A codec for the given tag.</returns>
+        public static FieldCodec<T> ForEnum<T>(uint tag, Func<T, int> toInt32, Func<int, T> fromInt32)
+        {
+            return FieldCodec.ForEnum(tag, toInt32, fromInt32, default(T));
+        }
+
         /// <summary>
         /// Retrieves a codec suitable for a string field with the given tag.
         /// </summary>
         /// <param name="tag">The tag.</param>
         /// <param name="defaultValue">The default value.</param>
         /// <returns>A codec for the given tag.</returns>
-        public static FieldCodec<string> ForString(uint tag, string defaultValue = "")
+        public static FieldCodec<string> ForString(uint tag, string defaultValue)
         {
             return new FieldCodec<string>(input => input.ReadString(), (output, value) => output.WriteString(value), CodedOutputStream.ComputeStringSize, tag);
         }
@@ -62,7 +227,7 @@ namespace Google.Protobuf
         /// <param name="tag">The tag.</param>
         /// <param name="defaultValue">The default value.</param>
         /// <returns>A codec for the given tag.</returns>
-        public static FieldCodec<ByteString> ForBytes(uint tag, ByteString defaultValue = null)
+        public static FieldCodec<ByteString> ForBytes(uint tag, ByteString defaultValue)
         {
             return new FieldCodec<ByteString>(input => input.ReadBytes(), (output, value) => output.WriteBytes(value), CodedOutputStream.ComputeBytesSize, tag);
         }
@@ -73,7 +238,7 @@ namespace Google.Protobuf
         /// <param name="tag">The tag.</param>
         /// <param name="defaultValue">The default value.</param>
         /// <returns>A codec for the given tag.</returns>
-        public static FieldCodec<bool> ForBool(uint tag, bool defaultValue = false)
+        public static FieldCodec<bool> ForBool(uint tag, bool defaultValue)
         {
             return new FieldCodec<bool>(input => input.ReadBool(), (output, value) => output.WriteBool(value), CodedOutputStream.BoolSize, tag);
         }
@@ -84,7 +249,7 @@ namespace Google.Protobuf
         /// <param name="tag">The tag.</param>
         /// <param name="defaultValue">The default value.</param>
         /// <returns>A codec for the given tag.</returns>
-        public static FieldCodec<int> ForInt32(uint tag, int defaultValue = 0)
+        public static FieldCodec<int> ForInt32(uint tag, int defaultValue)
         {
             return new FieldCodec<int>(input => input.ReadInt32(), (output, value) => output.WriteInt32(value), CodedOutputStream.ComputeInt32Size, tag);
         }
@@ -95,7 +260,7 @@ namespace Google.Protobuf
         /// <param name="tag">The tag.</param>
         /// <param name="defaultValue">The default value.</param>
         /// <returns>A codec for the given tag.</returns>
-        public static FieldCodec<int> ForSInt32(uint tag, int defaultValue = 0)
+        public static FieldCodec<int> ForSInt32(uint tag, int defaultValue)
         {
             return new FieldCodec<int>(input => input.ReadSInt32(), (output, value) => output.WriteSInt32(value), CodedOutputStream.ComputeSInt32Size, tag);
         }
@@ -106,7 +271,7 @@ namespace Google.Protobuf
         /// <param name="tag">The tag.</param>
         /// <param name="defaultValue">The default value.</param>
         /// <returns>A codec for the given tag.</returns>
-        public static FieldCodec<uint> ForFixed32(uint tag, uint defaultValue = 0)
+        public static FieldCodec<uint> ForFixed32(uint tag, uint defaultValue)
         {
             return new FieldCodec<uint>(input => input.ReadFixed32(), (output, value) => output.WriteFixed32(value), 4, tag);
         }
@@ -117,7 +282,7 @@ namespace Google.Protobuf
         /// <param name="tag">The tag.</param>
         /// <param name="defaultValue">The default value.</param>
         /// <returns>A codec for the given tag.</returns>
-        public static FieldCodec<int> ForSFixed32(uint tag, int defaultValue = 0)
+        public static FieldCodec<int> ForSFixed32(uint tag, int defaultValue)
         {
             return new FieldCodec<int>(input => input.ReadSFixed32(), (output, value) => output.WriteSFixed32(value), 4, tag);
         }
@@ -128,7 +293,7 @@ namespace Google.Protobuf
         /// <param name="tag">The tag.</param>
         /// <param name="defaultValue">The default value.</param>
         /// <returns>A codec for the given tag.</returns>
-        public static FieldCodec<uint> ForUInt32(uint tag, uint defaultValue = 0)
+        public static FieldCodec<uint> ForUInt32(uint tag, uint defaultValue)
         {
             return new FieldCodec<uint>(input => input.ReadUInt32(), (output, value) => output.WriteUInt32(value), CodedOutputStream.ComputeUInt32Size, tag);
         }
@@ -139,7 +304,7 @@ namespace Google.Protobuf
         /// <param name="tag">The tag.</param>
         /// <param name="defaultValue">The default value.</param>
         /// <returns>A codec for the given tag.</returns>
-        public static FieldCodec<long> ForInt64(uint tag, long defaultValue = 0)
+        public static FieldCodec<long> ForInt64(uint tag, long defaultValue)
         {
             return new FieldCodec<long>(input => input.ReadInt64(), (output, value) => output.WriteInt64(value), CodedOutputStream.ComputeInt64Size, tag);
         }
@@ -150,7 +315,7 @@ namespace Google.Protobuf
         /// <param name="tag">The tag.</param>
         /// <param name="defaultValue">The default value.</param>
         /// <returns>A codec for the given tag.</returns>
-        public static FieldCodec<long> ForSInt64(uint tag, long defaultValue = 0)
+        public static FieldCodec<long> ForSInt64(uint tag, long defaultValue)
         {
             return new FieldCodec<long>(input => input.ReadSInt64(), (output, value) => output.WriteSInt64(value), CodedOutputStream.ComputeSInt64Size, tag);
         }
@@ -161,7 +326,7 @@ namespace Google.Protobuf
         /// <param name="tag">The tag.</param>
         /// <param name="defaultValue">The default value.</param>
         /// <returns>A codec for the given tag.</returns>
-        public static FieldCodec<ulong> ForFixed64(uint tag, ulong defaultValue = 0)
+        public static FieldCodec<ulong> ForFixed64(uint tag, ulong defaultValue)
         {
             return new FieldCodec<ulong>(input => input.ReadFixed64(), (output, value) => output.WriteFixed64(value), 8, tag);
         }
@@ -172,7 +337,7 @@ namespace Google.Protobuf
         /// <param name="tag">The tag.</param>
         /// <param name="defaultValue">The default value.</param>
         /// <returns>A codec for the given tag.</returns>
-        public static FieldCodec<long> ForSFixed64(uint tag, long defaultValue = 0)
+        public static FieldCodec<long> ForSFixed64(uint tag, long defaultValue)
         {
             return new FieldCodec<long>(input => input.ReadSFixed64(), (output, value) => output.WriteSFixed64(value), 8, tag);
         }
@@ -183,7 +348,7 @@ namespace Google.Protobuf
         /// <param name="tag">The tag.</param>
         /// <param name="defaultValue">The default value.</param>
         /// <returns>A codec for the given tag.</returns>
-        public static FieldCodec<ulong> ForUInt64(uint tag, ulong defaultValue = 0)
+        public static FieldCodec<ulong> ForUInt64(uint tag, ulong defaultValue)
         {
             return new FieldCodec<ulong>(input => input.ReadUInt64(), (output, value) => output.WriteUInt64(value), CodedOutputStream.ComputeUInt64Size, tag);
         }
@@ -194,7 +359,7 @@ namespace Google.Protobuf
         /// <param name="tag">The tag.</param>
         /// <param name="defaultValue">The default value.</param>
         /// <returns>A codec for the given tag.</returns>
-        public static FieldCodec<float> ForFloat(uint tag, float defaultValue = 0)
+        public static FieldCodec<float> ForFloat(uint tag, float defaultValue)
         {
             return new FieldCodec<float>(input => input.ReadFloat(), (output, value) => output.WriteFloat(value), CodedOutputStream.FloatSize, tag);
         }
@@ -205,7 +370,7 @@ namespace Google.Protobuf
         /// <param name="tag">The tag.</param>
         /// <param name="defaultValue">The default value.</param>
         /// <returns>A codec for the given tag.</returns>
-        public static FieldCodec<double> ForDouble(uint tag, double defaultValue = 0)
+        public static FieldCodec<double> ForDouble(uint tag, double defaultValue)
         {
             return new FieldCodec<double>(input => input.ReadDouble(), (output, value) => output.WriteDouble(value), CodedOutputStream.DoubleSize, tag);
         }
@@ -221,7 +386,7 @@ namespace Google.Protobuf
         /// <param name="fromInt32">A conversion function from the enum type to <see cref="Int32"/>.</param>
         /// <param name="defaultValue">The default value.</param>
         /// <returns>A codec for the given tag.</returns>
-        public static FieldCodec<T> ForEnum<T>(uint tag, Func<T, int> toInt32, Func<int, T> fromInt32, T defaultValue = default(T))
+        public static FieldCodec<T> ForEnum<T>(uint tag, Func<T, int> toInt32, Func<int, T> fromInt32, T defaultValue)
         {
             return new FieldCodec<T>(input => fromInt32(
                 input.ReadEnum()),

+ 1 - 1
csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs

@@ -62,7 +62,7 @@ namespace Google.Protobuf.WellKnownTypes {
   ///     if (duration.seconds &lt; 0 &amp;&amp; duration.nanos > 0) {
   ///       duration.seconds += 1;
   ///       duration.nanos -= 1000000000;
-  ///     } else if (durations.seconds > 0 &amp;&amp; duration.nanos &lt; 0) {
+  ///     } else if (duration.seconds > 0 &amp;&amp; duration.nanos &lt; 0) {
   ///       duration.seconds -= 1;
   ///       duration.nanos += 1000000000;
   ///     }

+ 480 - 91
java/core/src/main/java/com/google/protobuf/FieldSet.java

@@ -48,8 +48,7 @@ import java.util.Map;
  *
  * @author kenton@google.com Kenton Varda
  */
-final class FieldSet<
-    FieldDescriptorType extends FieldSet.FieldDescriptorLite<FieldDescriptorType>> {
+final class FieldSet<T extends FieldSet.FieldDescriptorLite<T>> {
   /**
    * Interface for a FieldDescriptor or lite extension descriptor. This prevents FieldSet from
    * depending on {@link Descriptors.FieldDescriptor}.
@@ -72,18 +71,26 @@ final class FieldSet<
     MessageLite.Builder internalMergeFrom(MessageLite.Builder to, MessageLite from);
   }
 
-  private final SmallSortedMap<FieldDescriptorType, Object> fields;
+  private static final int DEFAULT_FIELD_MAP_ARRAY_SIZE = 16;
+
+  private final SmallSortedMap<T, Object> fields;
   private boolean isImmutable;
-  private boolean hasLazyField = false;
+  private boolean hasLazyField;
 
   /** Construct a new FieldSet. */
   private FieldSet() {
-    this.fields = SmallSortedMap.newFieldMap(16);
+    this.fields = SmallSortedMap.newFieldMap(DEFAULT_FIELD_MAP_ARRAY_SIZE);
   }
 
   /** Construct an empty FieldSet. This is only used to initialize DEFAULT_INSTANCE. */
+  @SuppressWarnings("unused")
   private FieldSet(final boolean dummy) {
-    this.fields = SmallSortedMap.newFieldMap(0);
+    this(SmallSortedMap.<T>newFieldMap(0));
+    makeImmutable();
+  }
+
+  private FieldSet(SmallSortedMap<T, Object> fields) {
+    this.fields = fields;
     makeImmutable();
   }
 
@@ -98,6 +105,11 @@ final class FieldSet<
     return DEFAULT_INSTANCE;
   }
 
+  /** Construct a new Builder. */
+  public static <T extends FieldDescriptorLite<T>> Builder<T> newBuilder() {
+    return new Builder<T>();
+  }
+
   @SuppressWarnings("rawtypes")
   private static final FieldSet DEFAULT_INSTANCE = new FieldSet(true);
 
@@ -152,18 +164,16 @@ final class FieldSet<
    * @return the newly cloned FieldSet
    */
   @Override
-  public FieldSet<FieldDescriptorType> clone() {
+  public FieldSet<T> clone() {
     // We can't just call fields.clone because List objects in the map
     // should not be shared.
-    FieldSet<FieldDescriptorType> clone = FieldSet.newFieldSet();
+    FieldSet<T> clone = FieldSet.newFieldSet();
     for (int i = 0; i < fields.getNumArrayEntries(); i++) {
-      Map.Entry<FieldDescriptorType, Object> entry = fields.getArrayEntryAt(i);
-      FieldDescriptorType descriptor = entry.getKey();
-      clone.setField(descriptor, entry.getValue());
+      Map.Entry<T, Object> entry = fields.getArrayEntryAt(i);
+      clone.setField(entry.getKey(), entry.getValue());
     }
-    for (Map.Entry<FieldDescriptorType, Object> entry : fields.getOverflowEntries()) {
-      FieldDescriptorType descriptor = entry.getKey();
-      clone.setField(descriptor, entry.getValue());
+    for (Map.Entry<T, Object> entry : fields.getOverflowEntries()) {
+      clone.setField(entry.getKey(), entry.getValue());
     }
     clone.hasLazyField = hasLazyField;
     return clone;
@@ -179,15 +189,9 @@ final class FieldSet<
   }
 
   /** Get a simple map containing all the fields. */
-  public Map<FieldDescriptorType, Object> getAllFields() {
+  public Map<T, Object> getAllFields() {
     if (hasLazyField) {
-      SmallSortedMap<FieldDescriptorType, Object> result = SmallSortedMap.newFieldMap(16);
-      for (int i = 0; i < fields.getNumArrayEntries(); i++) {
-        cloneFieldEntry(result, fields.getArrayEntryAt(i));
-      }
-      for (Map.Entry<FieldDescriptorType, Object> entry : fields.getOverflowEntries()) {
-        cloneFieldEntry(result, entry);
-      }
+      SmallSortedMap<T, Object> result = cloneAllFieldsMap(fields, /* copyList */ false);
       if (fields.isImmutable()) {
         result.makeImmutable();
       }
@@ -196,12 +200,26 @@ final class FieldSet<
     return fields.isImmutable() ? fields : Collections.unmodifiableMap(fields);
   }
 
-  private void cloneFieldEntry(
-      Map<FieldDescriptorType, Object> map, Map.Entry<FieldDescriptorType, Object> entry) {
-    FieldDescriptorType key = entry.getKey();
+  private static <T extends FieldDescriptorLite<T>> SmallSortedMap<T, Object> cloneAllFieldsMap(
+      SmallSortedMap<T, Object> fields, boolean copyList) {
+    SmallSortedMap<T, Object> result = SmallSortedMap.newFieldMap(DEFAULT_FIELD_MAP_ARRAY_SIZE);
+    for (int i = 0; i < fields.getNumArrayEntries(); i++) {
+      cloneFieldEntry(result, fields.getArrayEntryAt(i), copyList);
+    }
+    for (Map.Entry<T, Object> entry : fields.getOverflowEntries()) {
+      cloneFieldEntry(result, entry, copyList);
+    }
+    return result;
+  }
+
+  private static <T extends FieldDescriptorLite<T>> void cloneFieldEntry(
+      Map<T, Object> map, Map.Entry<T, Object> entry, boolean copyList) {
+    T key = entry.getKey();
     Object value = entry.getValue();
     if (value instanceof LazyField) {
       map.put(key, ((LazyField) value).getValue());
+    } else if (copyList && value instanceof List) {
+      map.put(key, new ArrayList<>((List<?>) value));
     } else {
       map.put(key, value);
     }
@@ -211,9 +229,9 @@ final class FieldSet<
    * Get an iterator to the field map. This iterator should not be leaked out of the protobuf
    * library as it is not protected from mutation when fields is not immutable.
    */
-  public Iterator<Map.Entry<FieldDescriptorType, Object>> iterator() {
+  public Iterator<Map.Entry<T, Object>> iterator() {
     if (hasLazyField) {
-      return new LazyIterator<FieldDescriptorType>(fields.entrySet().iterator());
+      return new LazyIterator<T>(fields.entrySet().iterator());
     }
     return fields.entrySet().iterator();
   }
@@ -223,15 +241,15 @@ final class FieldSet<
    * should not be leaked out of the protobuf library as it is not protected from mutation when
    * fields is not immutable.
    */
-  Iterator<Map.Entry<FieldDescriptorType, Object>> descendingIterator() {
+  Iterator<Map.Entry<T, Object>> descendingIterator() {
     if (hasLazyField) {
-      return new LazyIterator<FieldDescriptorType>(fields.descendingEntrySet().iterator());
+      return new LazyIterator<T>(fields.descendingEntrySet().iterator());
     }
     return fields.descendingEntrySet().iterator();
   }
 
   /** Useful for implementing {@link Message#hasField(Descriptors.FieldDescriptor)}. */
-  public boolean hasField(final FieldDescriptorType descriptor) {
+  public boolean hasField(final T descriptor) {
     if (descriptor.isRepeated()) {
       throw new IllegalArgumentException("hasField() can only be called on non-repeated fields.");
     }
@@ -244,7 +262,7 @@ final class FieldSet<
    * returns {@code null} if the field is not set; in this case it is up to the caller to fetch the
    * field's default value.
    */
-  public Object getField(final FieldDescriptorType descriptor) {
+  public Object getField(final T descriptor) {
     Object o = fields.get(descriptor);
     if (o instanceof LazyField) {
       return ((LazyField) o).getValue();
@@ -256,7 +274,7 @@ final class FieldSet<
    * Useful for implementing {@link Message.Builder#setField(Descriptors.FieldDescriptor,Object)}.
    */
   @SuppressWarnings({"unchecked", "rawtypes"})
-  public void setField(final FieldDescriptorType descriptor, Object value) {
+  public void setField(final T descriptor, Object value) {
     if (descriptor.isRepeated()) {
       if (!(value instanceof List)) {
         throw new IllegalArgumentException(
@@ -282,7 +300,7 @@ final class FieldSet<
   }
 
   /** Useful for implementing {@link Message.Builder#clearField(Descriptors.FieldDescriptor)}. */
-  public void clearField(final FieldDescriptorType descriptor) {
+  public void clearField(final T descriptor) {
     fields.remove(descriptor);
     if (fields.isEmpty()) {
       hasLazyField = false;
@@ -290,7 +308,7 @@ final class FieldSet<
   }
 
   /** Useful for implementing {@link Message#getRepeatedFieldCount(Descriptors.FieldDescriptor)}. */
-  public int getRepeatedFieldCount(final FieldDescriptorType descriptor) {
+  public int getRepeatedFieldCount(final T descriptor) {
     if (!descriptor.isRepeated()) {
       throw new IllegalArgumentException(
           "getRepeatedField() can only be called on repeated fields.");
@@ -305,7 +323,7 @@ final class FieldSet<
   }
 
   /** Useful for implementing {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)}. */
-  public Object getRepeatedField(final FieldDescriptorType descriptor, final int index) {
+  public Object getRepeatedField(final T descriptor, final int index) {
     if (!descriptor.isRepeated()) {
       throw new IllegalArgumentException(
           "getRepeatedField() can only be called on repeated fields.");
@@ -325,8 +343,7 @@ final class FieldSet<
    * Message.Builder#setRepeatedField(Descriptors.FieldDescriptor,int,Object)}.
    */
   @SuppressWarnings("unchecked")
-  public void setRepeatedField(
-      final FieldDescriptorType descriptor, final int index, final Object value) {
+  public void setRepeatedField(final T descriptor, final int index, final Object value) {
     if (!descriptor.isRepeated()) {
       throw new IllegalArgumentException(
           "getRepeatedField() can only be called on repeated fields.");
@@ -346,7 +363,7 @@ final class FieldSet<
    * Message.Builder#addRepeatedField(Descriptors.FieldDescriptor,Object)}.
    */
   @SuppressWarnings("unchecked")
-  public void addRepeatedField(final FieldDescriptorType descriptor, final Object value) {
+  public void addRepeatedField(final T descriptor, final Object value) {
     if (!descriptor.isRepeated()) {
       throw new IllegalArgumentException(
           "addRepeatedField() can only be called on repeated fields.");
@@ -373,53 +390,45 @@ final class FieldSet<
    *
    * @throws IllegalArgumentException The value is not of the right type.
    */
-  private static void verifyType(final WireFormat.FieldType type, final Object value) {
-    checkNotNull(value);
+  private void verifyType(final WireFormat.FieldType type, final Object value) {
+    if (!isValidType(type, value)) {
+      // TODO(kenton):  When chaining calls to setField(), it can be hard to
+      //   tell from the stack trace which exact call failed, since the whole
+      //   chain is considered one line of code.  It would be nice to print
+      //   more information here, e.g. naming the field.  We used to do that.
+      //   But we can't now that FieldSet doesn't use descriptors.  Maybe this
+      //   isn't a big deal, though, since it would only really apply when using
+      //   reflection and generally people don't chain reflection setters.
+      throw new IllegalArgumentException(
+          "Wrong object type used with protocol message reflection.");
+    }
+  }
 
-    boolean isValid = false;
+  private static boolean isValidType(final WireFormat.FieldType type, final Object value) {
+    checkNotNull(value);
     switch (type.getJavaType()) {
       case INT:
-        isValid = value instanceof Integer;
-        break;
+        return value instanceof Integer;
       case LONG:
-        isValid = value instanceof Long;
-        break;
+        return value instanceof Long;
       case FLOAT:
-        isValid = value instanceof Float;
-        break;
+        return value instanceof Float;
       case DOUBLE:
-        isValid = value instanceof Double;
-        break;
+        return value instanceof Double;
       case BOOLEAN:
-        isValid = value instanceof Boolean;
-        break;
+        return value instanceof Boolean;
       case STRING:
-        isValid = value instanceof String;
-        break;
+        return value instanceof String;
       case BYTE_STRING:
-        isValid = value instanceof ByteString || value instanceof byte[];
-        break;
+        return value instanceof ByteString || value instanceof byte[];
       case ENUM:
         // TODO(kenton):  Caller must do type checking here, I guess.
-        isValid = (value instanceof Integer || value instanceof Internal.EnumLite);
-        break;
+        return (value instanceof Integer || value instanceof Internal.EnumLite);
       case MESSAGE:
         // TODO(kenton):  Caller must do type checking here, I guess.
-        isValid = (value instanceof MessageLite) || (value instanceof LazyField);
-        break;
-    }
-
-    if (!isValid) {
-      // TODO(kenton):  When chaining calls to setField(), it can be hard to
-      //   tell from the stack trace which exact call failed, since the whole
-      //   chain is considered one line of code.  It would be nice to print
-      //   more information here, e.g. naming the field.  We used to do that.
-      //   But we can't now that FieldSet doesn't use descriptors.  Maybe this
-      //   isn't a big deal, though, since it would only really apply when using
-      //   reflection and generally people don't chain reflection setters.
-      throw new IllegalArgumentException(
-          "Wrong object type used with protocol message reflection.");
+        return (value instanceof MessageLite) || (value instanceof LazyField);
     }
+    return false;
   }
 
   // =================================================================
@@ -436,7 +445,7 @@ final class FieldSet<
         return false;
       }
     }
-    for (final Map.Entry<FieldDescriptorType, Object> entry : fields.getOverflowEntries()) {
+    for (final Map.Entry<T, Object> entry : fields.getOverflowEntries()) {
       if (!isInitialized(entry)) {
         return false;
       }
@@ -445,8 +454,9 @@ final class FieldSet<
   }
 
   @SuppressWarnings("unchecked")
-  private boolean isInitialized(final Map.Entry<FieldDescriptorType, Object> entry) {
-    final FieldDescriptorType descriptor = entry.getKey();
+  private static <T extends FieldDescriptorLite<T>> boolean isInitialized(
+      final Map.Entry<T, Object> entry) {
+    final T descriptor = entry.getKey();
     if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
       if (descriptor.isRepeated()) {
         for (final MessageLite element : (List<MessageLite>) entry.getValue()) {
@@ -485,16 +495,16 @@ final class FieldSet<
   }
 
   /** Like {@link Message.Builder#mergeFrom(Message)}, but merges from another {@link FieldSet}. */
-  public void mergeFrom(final FieldSet<FieldDescriptorType> other) {
+  public void mergeFrom(final FieldSet<T> other) {
     for (int i = 0; i < other.fields.getNumArrayEntries(); i++) {
       mergeFromField(other.fields.getArrayEntryAt(i));
     }
-    for (final Map.Entry<FieldDescriptorType, Object> entry : other.fields.getOverflowEntries()) {
+    for (final Map.Entry<T, Object> entry : other.fields.getOverflowEntries()) {
       mergeFromField(entry);
     }
   }
 
-  private Object cloneIfMutable(Object value) {
+  private static Object cloneIfMutable(Object value) {
     if (value instanceof byte[]) {
       byte[] bytes = (byte[]) value;
       byte[] copy = new byte[bytes.length];
@@ -506,8 +516,8 @@ final class FieldSet<
   }
 
   @SuppressWarnings({"unchecked", "rawtypes"})
-  private void mergeFromField(final Map.Entry<FieldDescriptorType, Object> entry) {
-    final FieldDescriptorType descriptor = entry.getKey();
+  private void mergeFromField(final Map.Entry<T, Object> entry) {
+    final T descriptor = entry.getKey();
     Object otherValue = entry.getValue();
     if (otherValue instanceof LazyField) {
       otherValue = ((LazyField) otherValue).getValue();
@@ -532,7 +542,6 @@ final class FieldSet<
               descriptor
                   .internalMergeFrom(((MessageLite) value).toBuilder(), (MessageLite) otherValue)
                   .build();
-
         fields.put(descriptor, value);
       }
     } else {
@@ -567,10 +576,10 @@ final class FieldSet<
   /** See {@link Message#writeTo(CodedOutputStream)}. */
   public void writeTo(final CodedOutputStream output) throws IOException {
     for (int i = 0; i < fields.getNumArrayEntries(); i++) {
-      final Map.Entry<FieldDescriptorType, Object> entry = fields.getArrayEntryAt(i);
+      final Map.Entry<T, Object> entry = fields.getArrayEntryAt(i);
       writeField(entry.getKey(), entry.getValue(), output);
     }
-    for (final Map.Entry<FieldDescriptorType, Object> entry : fields.getOverflowEntries()) {
+    for (final Map.Entry<T, Object> entry : fields.getOverflowEntries()) {
       writeField(entry.getKey(), entry.getValue(), output);
     }
   }
@@ -580,15 +589,14 @@ final class FieldSet<
     for (int i = 0; i < fields.getNumArrayEntries(); i++) {
       writeMessageSetTo(fields.getArrayEntryAt(i), output);
     }
-    for (final Map.Entry<FieldDescriptorType, Object> entry : fields.getOverflowEntries()) {
+    for (final Map.Entry<T, Object> entry : fields.getOverflowEntries()) {
       writeMessageSetTo(entry, output);
     }
   }
 
-  private void writeMessageSetTo(
-      final Map.Entry<FieldDescriptorType, Object> entry, final CodedOutputStream output)
+  private void writeMessageSetTo(final Map.Entry<T, Object> entry, final CodedOutputStream output)
       throws IOException {
-    final FieldDescriptorType descriptor = entry.getKey();
+    final T descriptor = entry.getKey();
     if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE
         && !descriptor.isRepeated()
         && !descriptor.isPacked()) {
@@ -750,10 +758,10 @@ final class FieldSet<
   public int getSerializedSize() {
     int size = 0;
     for (int i = 0; i < fields.getNumArrayEntries(); i++) {
-      final Map.Entry<FieldDescriptorType, Object> entry = fields.getArrayEntryAt(i);
+      final Map.Entry<T, Object> entry = fields.getArrayEntryAt(i);
       size += computeFieldSize(entry.getKey(), entry.getValue());
     }
-    for (final Map.Entry<FieldDescriptorType, Object> entry : fields.getOverflowEntries()) {
+    for (final Map.Entry<T, Object> entry : fields.getOverflowEntries()) {
       size += computeFieldSize(entry.getKey(), entry.getValue());
     }
     return size;
@@ -765,14 +773,14 @@ final class FieldSet<
     for (int i = 0; i < fields.getNumArrayEntries(); i++) {
       size += getMessageSetSerializedSize(fields.getArrayEntryAt(i));
     }
-    for (final Map.Entry<FieldDescriptorType, Object> entry : fields.getOverflowEntries()) {
+    for (final Map.Entry<T, Object> entry : fields.getOverflowEntries()) {
       size += getMessageSetSerializedSize(entry);
     }
     return size;
   }
 
-  private int getMessageSetSerializedSize(final Map.Entry<FieldDescriptorType, Object> entry) {
-    final FieldDescriptorType descriptor = entry.getKey();
+  private int getMessageSetSerializedSize(final Map.Entry<T, Object> entry) {
+    final T descriptor = entry.getKey();
     Object value = entry.getValue();
     if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE
         && !descriptor.isRepeated()
@@ -904,4 +912,385 @@ final class FieldSet<
       return computeElementSize(type, number, value);
     }
   }
+
+  /**
+   * A FieldSet Builder that accept a {@link MessageLite.Builder} as a field value. This is useful
+   * for implementing methods in {@link MessageLite.Builder}.
+   */
+  static final class Builder<T extends FieldDescriptorLite<T>> {
+
+    private SmallSortedMap<T, Object> fields;
+    private boolean hasLazyField;
+    private boolean isMutable;
+    private boolean hasNestedBuilders;
+
+    private Builder() {
+      this(SmallSortedMap.<T>newFieldMap(DEFAULT_FIELD_MAP_ARRAY_SIZE));
+    }
+
+    private Builder(SmallSortedMap<T, Object> fields) {
+      this.fields = fields;
+      this.isMutable = true;
+    }
+
+    /** Creates the FieldSet */
+    public FieldSet<T> build() {
+      if (fields.isEmpty()) {
+        return FieldSet.emptySet();
+      }
+      isMutable = false;
+      SmallSortedMap<T, Object> fieldsForBuild = fields;
+      if (hasNestedBuilders) {
+        // Make a copy of the fields map with all Builders replaced by Message.
+        fieldsForBuild = cloneAllFieldsMap(fields, /* copyList */ false);
+        replaceBuilders(fieldsForBuild);
+      }
+      FieldSet<T> fieldSet = new FieldSet<>(fieldsForBuild);
+      fieldSet.hasLazyField = hasLazyField;
+      return fieldSet;
+    }
+
+    private static <T extends FieldDescriptorLite<T>> void replaceBuilders(
+        SmallSortedMap<T, Object> fieldMap) {
+      for (int i = 0; i < fieldMap.getNumArrayEntries(); i++) {
+        replaceBuilders(fieldMap.getArrayEntryAt(i));
+      }
+      for (Map.Entry<T, Object> entry : fieldMap.getOverflowEntries()) {
+        replaceBuilders(entry);
+      }
+    }
+
+    private static <T extends FieldDescriptorLite<T>> void replaceBuilders(
+        Map.Entry<T, Object> entry) {
+      entry.setValue(replaceBuilders(entry.getKey(), entry.getValue()));
+    }
+
+    private static <T extends FieldDescriptorLite<T>> Object replaceBuilders(
+        T descriptor, Object value) {
+      if (value == null) {
+        return value;
+      }
+      if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
+        if (descriptor.isRepeated()) {
+          if (!(value instanceof List)) {
+            throw new IllegalStateException(
+                "Repeated field should contains a List but actually contains type: "
+                    + value.getClass());
+          }
+          @SuppressWarnings("unchecked")  // We just check that value is an instance of List above.
+          List<Object> list = (List<Object>) value;
+          for (int i = 0; i < list.size(); i++) {
+            Object oldElement = list.get(i);
+            Object newElement = replaceBuilder(oldElement);
+            if (newElement != oldElement) {
+              // If the list contains a Message.Builder, then make a copy of that list and then
+              // modify the Message.Builder into a Message and return the new list. This way, the
+              // existing Message.Builder will still be able to modify the inner fields of the
+              // original FieldSet.Builder.
+              if (list == value) {
+                list = new ArrayList<>(list);
+              }
+              list.set(i, newElement);
+            }
+          }
+          return list;
+        } else {
+          return replaceBuilder(value);
+        }
+      }
+      return value;
+    }
+
+    private static Object replaceBuilder(Object value) {
+      return (value instanceof MessageLite.Builder) ? ((MessageLite.Builder) value).build() : value;
+    }
+
+    /** Returns a new Builder using the fields from {@code fieldSet}. */
+    public static <T extends FieldDescriptorLite<T>> Builder<T> fromFieldSet(FieldSet<T> fieldSet) {
+      Builder<T> builder = new Builder<T>(cloneAllFieldsMap(fieldSet.fields, /* copyList */ true));
+      builder.hasLazyField = fieldSet.hasLazyField;
+      return builder;
+    }
+
+    // =================================================================
+
+    /** Get a simple map containing all the fields. */
+    public Map<T, Object> getAllFields() {
+      if (hasLazyField) {
+        SmallSortedMap<T, Object> result = cloneAllFieldsMap(fields, /* copyList */ false);
+        if (fields.isImmutable()) {
+          result.makeImmutable();
+        } else {
+          replaceBuilders(result);
+        }
+        return result;
+      }
+      return fields.isImmutable() ? fields : Collections.unmodifiableMap(fields);
+    }
+
+    /** Useful for implementing {@link Message#hasField(Descriptors.FieldDescriptor)}. */
+    public boolean hasField(final T descriptor) {
+      if (descriptor.isRepeated()) {
+        throw new IllegalArgumentException("hasField() can only be called on non-repeated fields.");
+      }
+
+      return fields.get(descriptor) != null;
+    }
+
+    /**
+     * Useful for implementing {@link Message#getField(Descriptors.FieldDescriptor)}. This method
+     * returns {@code null} if the field is not set; in this case it is up to the caller to fetch
+     * the field's default value.
+     */
+    public Object getField(final T descriptor) {
+      Object value = getFieldAllowBuilders(descriptor);
+      return replaceBuilders(descriptor, value);
+    }
+
+    /** Same as {@link #getField(F)}, but allow a {@link MessageLite.Builder} to be returned. */
+    Object getFieldAllowBuilders(final T descriptor) {
+      Object o = fields.get(descriptor);
+      if (o instanceof LazyField) {
+        return ((LazyField) o).getValue();
+      }
+      return o;
+    }
+
+    private void ensureIsMutable() {
+      if (!isMutable) {
+        fields = cloneAllFieldsMap(fields, /* copyList */ true);
+        isMutable = true;
+      }
+    }
+
+    /**
+     * Useful for implementing {@link Message.Builder#setField(Descriptors.FieldDescriptor,
+     * Object)}.
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public void setField(final T descriptor, Object value) {
+      ensureIsMutable();
+      if (descriptor.isRepeated()) {
+        if (!(value instanceof List)) {
+          throw new IllegalArgumentException(
+              "Wrong object type used with protocol message reflection.");
+        }
+
+        // Wrap the contents in a new list so that the caller cannot change
+        // the list's contents after setting it.
+        final List newList = new ArrayList();
+        newList.addAll((List) value);
+        for (final Object element : newList) {
+          verifyType(descriptor.getLiteType(), element);
+          hasNestedBuilders = hasNestedBuilders || element instanceof MessageLite.Builder;
+        }
+        value = newList;
+      } else {
+        verifyType(descriptor.getLiteType(), value);
+      }
+
+      if (value instanceof LazyField) {
+        hasLazyField = true;
+      }
+      hasNestedBuilders = hasNestedBuilders || value instanceof MessageLite.Builder;
+
+      fields.put(descriptor, value);
+    }
+
+    /** Useful for implementing {@link Message.Builder#clearField(Descriptors.FieldDescriptor)}. */
+    public void clearField(final T descriptor) {
+      ensureIsMutable();
+      fields.remove(descriptor);
+      if (fields.isEmpty()) {
+        hasLazyField = false;
+      }
+    }
+
+    /**
+     * Useful for implementing {@link Message#getRepeatedFieldCount(Descriptors.FieldDescriptor)}.
+     */
+    public int getRepeatedFieldCount(final T descriptor) {
+      if (!descriptor.isRepeated()) {
+        throw new IllegalArgumentException(
+            "getRepeatedField() can only be called on repeated fields.");
+      }
+
+      final Object value = getField(descriptor);
+      if (value == null) {
+        return 0;
+      } else {
+        return ((List<?>) value).size();
+      }
+    }
+
+    /**
+     * Useful for implementing {@link Message#getRepeatedField(Descriptors.FieldDescriptor, int)}.
+     */
+    public Object getRepeatedField(final T descriptor, final int index) {
+      if (hasNestedBuilders) {
+        ensureIsMutable();
+      }
+      Object value = getRepeatedFieldAllowBuilders(descriptor, index);
+      return replaceBuilder(value);
+    }
+
+    /**
+     * Same as {@link #getRepeatedField(F, int)}, but allow a {@link MessageLite.Builder} to be
+     * returned.
+     */
+    Object getRepeatedFieldAllowBuilders(final T descriptor, final int index) {
+      if (!descriptor.isRepeated()) {
+        throw new IllegalArgumentException(
+            "getRepeatedField() can only be called on repeated fields.");
+      }
+
+      final Object value = getFieldAllowBuilders(descriptor);
+
+      if (value == null) {
+        throw new IndexOutOfBoundsException();
+      } else {
+        return ((List<?>) value).get(index);
+      }
+    }
+
+    /**
+     * Useful for implementing {@link Message.Builder#setRepeatedField(Descriptors.FieldDescriptor,
+     * int, Object)}.
+     */
+    @SuppressWarnings("unchecked")
+    public void setRepeatedField(final T descriptor, final int index, final Object value) {
+      ensureIsMutable();
+      if (!descriptor.isRepeated()) {
+        throw new IllegalArgumentException(
+            "getRepeatedField() can only be called on repeated fields.");
+      }
+
+      hasNestedBuilders = hasNestedBuilders || value instanceof MessageLite.Builder;
+
+      final Object list = getField(descriptor);
+      if (list == null) {
+        throw new IndexOutOfBoundsException();
+      }
+
+      verifyType(descriptor.getLiteType(), value);
+      ((List<Object>) list).set(index, value);
+    }
+
+    /**
+     * Useful for implementing {@link Message.Builder#addRepeatedField(Descriptors.FieldDescriptor,
+     * Object)}.
+     */
+    @SuppressWarnings("unchecked")
+    public void addRepeatedField(final T descriptor, final Object value) {
+      ensureIsMutable();
+      if (!descriptor.isRepeated()) {
+        throw new IllegalArgumentException(
+            "addRepeatedField() can only be called on repeated fields.");
+      }
+
+      hasNestedBuilders = hasNestedBuilders || value instanceof MessageLite.Builder;
+
+      verifyType(descriptor.getLiteType(), value);
+
+      final Object existingValue = getField(descriptor);
+      List<Object> list;
+      if (existingValue == null) {
+        list = new ArrayList<>();
+        fields.put(descriptor, list);
+      } else {
+        list = (List<Object>) existingValue;
+      }
+
+      list.add(value);
+    }
+
+    /**
+     * Verifies that the given object is of the correct type to be a valid value for the given
+     * field. (For repeated fields, this checks if the object is the right type to be one element of
+     * the field.)
+     *
+     * @throws IllegalArgumentException The value is not of the right type.
+     */
+    private static void verifyType(final WireFormat.FieldType type, final Object value) {
+      if (!FieldSet.isValidType(type, value)) {
+        // Builder can accept Message.Builder values even though FieldSet will reject.
+        if (type.getJavaType() == WireFormat.JavaType.MESSAGE
+            && value instanceof MessageLite.Builder) {
+          return;
+        }
+        throw new IllegalArgumentException(
+            "Wrong object type used with protocol message reflection.");
+      }
+    }
+
+    /**
+     * See {@link Message#isInitialized()}. Note: Since {@code FieldSet} itself does not have any
+     * way of knowing about required fields that aren't actually present in the set, it is up to the
+     * caller to check that all required fields are present.
+     */
+    public boolean isInitialized() {
+      for (int i = 0; i < fields.getNumArrayEntries(); i++) {
+        if (!FieldSet.isInitialized(fields.getArrayEntryAt(i))) {
+          return false;
+        }
+      }
+      for (final Map.Entry<T, Object> entry : fields.getOverflowEntries()) {
+        if (!FieldSet.isInitialized(entry)) {
+          return false;
+        }
+      }
+      return true;
+    }
+
+    /**
+     * Like {@link Message.Builder#mergeFrom(Message)}, but merges from another {@link FieldSet}.
+     */
+    public void mergeFrom(final FieldSet<T> other) {
+      ensureIsMutable();
+      for (int i = 0; i < other.fields.getNumArrayEntries(); i++) {
+        mergeFromField(other.fields.getArrayEntryAt(i));
+      }
+      for (final Map.Entry<T, Object> entry : other.fields.getOverflowEntries()) {
+        mergeFromField(entry);
+      }
+    }
+
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    private void mergeFromField(final Map.Entry<T, Object> entry) {
+      final T descriptor = entry.getKey();
+      Object otherValue = entry.getValue();
+      if (otherValue instanceof LazyField) {
+        otherValue = ((LazyField) otherValue).getValue();
+      }
+
+      if (descriptor.isRepeated()) {
+        Object value = getField(descriptor);
+        if (value == null) {
+          value = new ArrayList();
+        }
+        for (Object element : (List) otherValue) {
+          ((List) value).add(FieldSet.cloneIfMutable(element));
+        }
+        fields.put(descriptor, value);
+      } else if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
+        Object value = getField(descriptor);
+        if (value == null) {
+          fields.put(descriptor, FieldSet.cloneIfMutable(otherValue));
+        } else {
+          // Merge the messages.
+          if (value instanceof MessageLite.Builder) {
+            descriptor.internalMergeFrom((MessageLite.Builder) value, (MessageLite) otherValue);
+          } else {
+            value =
+                descriptor
+                    .internalMergeFrom(((MessageLite) value).toBuilder(), (MessageLite) otherValue)
+                    .build();
+            fields.put(descriptor, value);
+          }
+        }
+      } else {
+        fields.put(descriptor, cloneIfMutable(otherValue));
+      }
+    }
+  }
 }

+ 90 - 20
java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java

@@ -1363,7 +1363,7 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
       extends Builder<BuilderType>
       implements ExtendableMessageOrBuilder<MessageType> {
 
-    private FieldSet<FieldDescriptor> extensions = FieldSet.emptySet();
+    private FieldSet.Builder<FieldDescriptor> extensions;
 
     protected ExtendableBuilder() {}
 
@@ -1374,18 +1374,18 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
 
     // For immutable message conversion.
     void internalSetExtensionSet(FieldSet<FieldDescriptor> extensions) {
-      this.extensions = extensions;
+      this.extensions = FieldSet.Builder.fromFieldSet(extensions);
     }
 
     @Override
     public BuilderType clear() {
-      extensions = FieldSet.emptySet();
+      extensions = null;
       return super.clear();
     }
 
     private void ensureExtensionsIsMutable() {
-      if (extensions.isImmutable()) {
-        extensions = extensions.clone();
+      if (extensions == null) {
+        extensions = FieldSet.newBuilder();
       }
     }
 
@@ -1408,7 +1408,7 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
       Extension<MessageType, Type> extension = checkNotLite(extensionLite);
 
       verifyExtensionContainingType(extension);
-      return extensions.hasField(extension.getDescriptor());
+      return extensions == null ? false : extensions.hasField(extension.getDescriptor());
     }
 
     /** Get the number of elements in a repeated extension. */
@@ -1419,7 +1419,7 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
 
       verifyExtensionContainingType(extension);
       final FieldDescriptor descriptor = extension.getDescriptor();
-      return extensions.getRepeatedFieldCount(descriptor);
+      return extensions == null ? 0 : extensions.getRepeatedFieldCount(descriptor);
     }
 
     /** Get the value of an extension. */
@@ -1429,7 +1429,7 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
 
       verifyExtensionContainingType(extension);
       FieldDescriptor descriptor = extension.getDescriptor();
-      final Object value = extensions.getField(descriptor);
+      final Object value = extensions == null ? null : extensions.getField(descriptor);
       if (value == null) {
         if (descriptor.isRepeated()) {
           return (Type) Collections.emptyList();
@@ -1453,8 +1453,11 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
 
       verifyExtensionContainingType(extension);
       FieldDescriptor descriptor = extension.getDescriptor();
-      return (Type) extension.singularFromReflectionType(
-          extensions.getRepeatedField(descriptor, index));
+      if (extensions == null) {
+        throw new IndexOutOfBoundsException();
+      }
+      return (Type)
+          extension.singularFromReflectionType(extensions.getRepeatedField(descriptor, index));
     }
 
     /** Set the value of an extension. */
@@ -1605,7 +1608,7 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
 
     /** Called by subclasses to check if all extensions are initialized. */
     protected boolean extensionsAreInitialized() {
-      return extensions.isInitialized();
+      return extensions == null ? true : extensions.isInitialized();
     }
 
     /**
@@ -1613,8 +1616,9 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
      * building the message.
      */
     private FieldSet<FieldDescriptor> buildExtensions() {
-      extensions.makeImmutable();
-      return extensions;
+      return extensions == null
+          ? (FieldSet<FieldDescriptor>) FieldSet.emptySet()
+          : extensions.build();
     }
 
     @Override
@@ -1628,7 +1632,9 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
     @Override
     public Map<FieldDescriptor, Object> getAllFields() {
       final Map<FieldDescriptor, Object> result = super.getAllFieldsMutable();
-      result.putAll(extensions.getAllFields());
+      if (extensions != null) {
+        result.putAll(extensions.getAllFields());
+      }
       return Collections.unmodifiableMap(result);
     }
 
@@ -1636,7 +1642,7 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
     public Object getField(final FieldDescriptor field) {
       if (field.isExtension()) {
         verifyContainingType(field);
-        final Object value = extensions.getField(field);
+        final Object value = extensions == null ? null : extensions.getField(field);
         if (value == null) {
           if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
             // Lacking an ExtensionRegistry, we have no way to determine the
@@ -1653,11 +1659,44 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
       }
     }
 
+    @Override
+    public Message.Builder getFieldBuilder(final FieldDescriptor field) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        if (field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
+          throw new UnsupportedOperationException(
+              "getFieldBuilder() called on a non-Message type.");
+        }
+        ensureExtensionsIsMutable();
+        final Object value = extensions.getFieldAllowBuilders(field);
+        if (value == null) {
+          Message.Builder builder = DynamicMessage.newBuilder(field.getMessageType());
+          extensions.setField(field, builder);
+          onChanged();
+          return builder;
+        } else {
+          if (value instanceof Message.Builder) {
+            return (Message.Builder) value;
+          } else if (value instanceof Message) {
+            Message.Builder builder = ((Message) value).toBuilder();
+            extensions.setField(field, builder);
+            onChanged();
+            return builder;
+          } else {
+            throw new UnsupportedOperationException(
+                "getRepeatedFieldBuilder() called on a non-Message type.");
+          }
+        }
+      } else {
+        return super.getFieldBuilder(field);
+      }
+    }
+
     @Override
     public int getRepeatedFieldCount(final FieldDescriptor field) {
       if (field.isExtension()) {
         verifyContainingType(field);
-        return extensions.getRepeatedFieldCount(field);
+        return extensions == null ? 0 : extensions.getRepeatedFieldCount(field);
       } else {
         return super.getRepeatedFieldCount(field);
       }
@@ -1668,17 +1707,46 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
                                    final int index) {
       if (field.isExtension()) {
         verifyContainingType(field);
+        if (extensions == null) {
+          throw new IndexOutOfBoundsException();
+        }
         return extensions.getRepeatedField(field, index);
       } else {
         return super.getRepeatedField(field, index);
       }
     }
 
+    @Override
+    public Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field, final int index) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        ensureExtensionsIsMutable();
+        if (field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
+          throw new UnsupportedOperationException(
+              "getRepeatedFieldBuilder() called on a non-Message type.");
+        }
+        final Object value = extensions.getRepeatedFieldAllowBuilders(field, index);
+        if (value instanceof Message.Builder) {
+          return (Message.Builder) value;
+        } else if (value instanceof Message) {
+          Message.Builder builder = ((Message) value).toBuilder();
+          extensions.setRepeatedField(field, index, builder);
+          onChanged();
+          return builder;
+        } else {
+          throw new UnsupportedOperationException(
+              "getRepeatedFieldBuilder() called on a non-Message type.");
+        }
+      } else {
+        return super.getRepeatedFieldBuilder(field, index);
+      }
+    }
+
     @Override
     public boolean hasField(final FieldDescriptor field) {
       if (field.isExtension()) {
         verifyContainingType(field);
-        return extensions.hasField(field);
+        return extensions == null ? false : extensions.hasField(field);
       } else {
         return super.hasField(field);
       }
@@ -1749,9 +1817,11 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
     }
 
     protected final void mergeExtensionFields(final ExtendableMessage other) {
-      ensureExtensionsIsMutable();
-      extensions.mergeFrom(other.extensions);
-      onChanged();
+      if (other.extensions != null) {
+        ensureExtensionsIsMutable();
+        extensions.mergeFrom(other.extensions);
+        onChanged();
+      }
     }
 
     private void verifyContainingType(final FieldDescriptor field) {

+ 2 - 1
java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java

@@ -32,9 +32,10 @@ package com.google.protobuf;
 
 import com.google.protobuf.Internal.ProtobufList;
 import java.util.Arrays;
+import java.util.RandomAccess;
 
 /** Implements {@link ProtobufList} for non-primitive and {@link String} types. */
-final class ProtobufArrayList<E> extends AbstractProtobufList<E> {
+final class ProtobufArrayList<E> extends AbstractProtobufList<E> implements RandomAccess {
 
   private static final ProtobufArrayList<Object> EMPTY_LIST =
       new ProtobufArrayList<Object>(new Object[0], 0);

+ 181 - 15
java/core/src/main/java/com/google/protobuf/TextFormat.java

@@ -113,8 +113,8 @@ public final class TextFormat {
   }
 
   /**
-   * Generates a human readable form of the field, useful for debugging and other purposes, with no
-   * newline characters.
+   * Generates a human readable form of the field, useful for debugging and other purposes, with
+   * no newline characters.
    *
    * @deprecated Use {@code printer().shortDebugString(FieldDescriptor, Object)}
    */
@@ -122,10 +122,10 @@ public final class TextFormat {
   public static String shortDebugString(final FieldDescriptor field, final Object value) {
     return printer().shortDebugString(field, value);
   }
-
+  //
   /**
-   * Generates a human readable form of the unknown fields, useful for debugging and other purposes,
-   * with no newline characters.
+   * Generates a human readable form of the unknown fields, useful for debugging and other
+   * purposes, with no newline characters.
    *
    * @deprecated Use {@code printer().shortDebugString(UnknownFieldSet)}
    */
@@ -166,8 +166,8 @@ public final class TextFormat {
   }
 
   /**
-   * Same as {@code printToString()}, except that non-ASCII characters in string type fields are not
-   * escaped in backslash+octals.
+   * Same as {@code printToString()}, except that non-ASCII characters in string type fields are
+   * not escaped in backslash+octals.
    *
    * @deprecated Use {@code printer().escapingNonAscii(false).printToString(UnknownFieldSet)}
    */
@@ -175,20 +175,21 @@ public final class TextFormat {
   public static String printToUnicodeString(final UnknownFieldSet fields) {
     return printer().escapingNonAscii(false).printToString(fields);
   }
-
+  //
   /** @deprecated Use {@code printer().printField(FieldDescriptor, Object, Appendable)} */
   @Deprecated
   public static void printField(
-      final FieldDescriptor field, final Object value, final Appendable output) throws IOException {
+      final FieldDescriptor field, final Object value, final Appendable output)
+      throws IOException {
     printer().printField(field, value, output);
   }
-
+  //
   /** @deprecated Use {@code printer().printFieldToString(FieldDescriptor, Object)} */
   @Deprecated
   public static String printFieldToString(final FieldDescriptor field, final Object value) {
     return printer().printFieldToString(field, value);
   }
-
+  //
   /**
    * Outputs a unicode textual representation of the value of given field value.
    *
@@ -205,7 +206,8 @@ public final class TextFormat {
    */
   @Deprecated
   public static void printUnicodeFieldValue(
-      final FieldDescriptor field, final Object value, final Appendable output) throws IOException {
+      final FieldDescriptor field, final Object value, final Appendable output)
+      throws IOException {
     printer().escapingNonAscii(false).printFieldValue(field, value, output);
   }
 
@@ -285,13 +287,16 @@ public final class TextFormat {
   public static final class Printer {
 
     // Printer instance which escapes non-ASCII characters.
-    private static final Printer DEFAULT = new Printer(true);
+    private static final Printer DEFAULT = new Printer(true, TypeRegistry.getEmptyTypeRegistry());
 
     /** Whether to escape non ASCII characters with backslash and octal. */
     private final boolean escapeNonAscii;
 
-    private Printer(boolean escapeNonAscii) {
+    private final TypeRegistry typeRegistry;
+
+    private Printer(boolean escapeNonAscii, TypeRegistry typeRegistry) {
       this.escapeNonAscii = escapeNonAscii;
+      this.typeRegistry = typeRegistry;
     }
 
     /**
@@ -304,7 +309,20 @@ public final class TextFormat {
      *     with the escape mode set to the given parameter.
      */
     public Printer escapingNonAscii(boolean escapeNonAscii) {
-      return new Printer(escapeNonAscii);
+      return new Printer(escapeNonAscii, typeRegistry);
+    }
+
+    /**
+     * Creates a new {@link Printer} using the given typeRegistry. The new Printer clones all other
+     * configurations from the current {@link Printer}.
+     *
+     * @throws IllegalArgumentException if a registry is already set.
+     */
+    public Printer usingTypeRegistry(TypeRegistry typeRegistry) {
+      if (this.typeRegistry != TypeRegistry.getEmptyTypeRegistry()) {
+        throw new IllegalArgumentException("Only one typeRegistry is allowed.");
+      }
+      return new Printer(escapeNonAscii, typeRegistry);
     }
 
     /**
@@ -323,9 +341,66 @@ public final class TextFormat {
 
     private void print(final MessageOrBuilder message, final TextGenerator generator)
         throws IOException {
+      if (message.getDescriptorForType().getFullName().equals("google.protobuf.Any")
+          && printAny(message, generator)) {
+        return;
+      }
       printMessage(message, generator);
     }
 
+    /**
+     * Attempt to print the 'google.protobuf.Any' message in a human-friendly format. Returns false
+     * if the message isn't a valid 'google.protobuf.Any' message (in which case the message should
+     * be rendered just like a regular message to help debugging).
+     */
+    private boolean printAny(final MessageOrBuilder message, final TextGenerator generator)
+        throws IOException {
+      Descriptor messageType = message.getDescriptorForType();
+      FieldDescriptor typeUrlField = messageType.findFieldByNumber(1);
+      FieldDescriptor valueField = messageType.findFieldByNumber(2);
+      if (typeUrlField == null
+          || typeUrlField.getType() != FieldDescriptor.Type.STRING
+          || valueField == null
+          || valueField.getType() != FieldDescriptor.Type.BYTES) {
+        // The message may look like an Any but isn't actually an Any message (might happen if the
+        // user tries to use DynamicMessage to construct an Any from incomplete Descriptor).
+        return false;
+      }
+      String typeUrl = (String) message.getField(typeUrlField);
+      // If type_url is not set, we will not be able to decode the content of the value, so just
+      // print out the Any like a regular message.
+      if (typeUrl.isEmpty()) {
+        return false;
+      }
+      Object value = message.getField(valueField);
+
+      Message.Builder contentBuilder = null;
+      try {
+        Descriptor contentType = typeRegistry.getDescriptorForTypeUrl(typeUrl);
+        if (contentType == null) {
+          return false;
+        }
+        contentBuilder = DynamicMessage.getDefaultInstance(contentType).newBuilderForType();
+        contentBuilder.mergeFrom((ByteString) value);
+      } catch (InvalidProtocolBufferException e) {
+        // The value of Any is malformed. We cannot print it out nicely, so fallback to printing out
+        // the type_url and value as bytes. Note that we fail open here to be consistent with
+        // text_format.cc, and also to allow a way for users to inspect the content of the broken
+        // message.
+        return false;
+      }
+      generator.print("[");
+      generator.print(typeUrl);
+      generator.print("] {");
+      generator.eol();
+      generator.indent();
+      print(contentBuilder, generator);
+      generator.outdent();
+      generator.print("}");
+      generator.eol();
+      return true;
+    }
+
     public String printFieldToString(final FieldDescriptor field, final Object value) {
       try {
         final StringBuilder text = new StringBuilder();
@@ -1382,6 +1457,7 @@ public final class TextFormat {
       FORBID_SINGULAR_OVERWRITES
     }
 
+    private final TypeRegistry typeRegistry;
     private final boolean allowUnknownFields;
     private final boolean allowUnknownEnumValues;
     private final boolean allowUnknownExtensions;
@@ -1389,11 +1465,13 @@ public final class TextFormat {
     private TextFormatParseInfoTree.Builder parseInfoTreeBuilder;
 
     private Parser(
+        TypeRegistry typeRegistry,
         boolean allowUnknownFields,
         boolean allowUnknownEnumValues,
         boolean allowUnknownExtensions,
         SingularOverwritePolicy singularOverwritePolicy,
         TextFormatParseInfoTree.Builder parseInfoTreeBuilder) {
+      this.typeRegistry = typeRegistry;
       this.allowUnknownFields = allowUnknownFields;
       this.allowUnknownEnumValues = allowUnknownEnumValues;
       this.allowUnknownExtensions = allowUnknownExtensions;
@@ -1414,6 +1492,18 @@ public final class TextFormat {
       private SingularOverwritePolicy singularOverwritePolicy =
           SingularOverwritePolicy.ALLOW_SINGULAR_OVERWRITES;
       private TextFormatParseInfoTree.Builder parseInfoTreeBuilder = null;
+      private TypeRegistry typeRegistry = TypeRegistry.getEmptyTypeRegistry();
+
+      /**
+       * Sets the TypeRegistry for resolving Any. If this is not set, TextFormat will not be able to
+       * parse Any unless Any is write as bytes.
+       *
+       * @throws IllegalArgumentException if a registry is already set.
+       */
+      public Builder setTypeRegistry(TypeRegistry typeRegistry) {
+        this.typeRegistry = typeRegistry;
+        return this;
+      }
 
       /**
        * Set whether this parser will allow unknown fields. By default, an exception is thrown if an
@@ -1452,6 +1542,7 @@ public final class TextFormat {
 
       public Parser build() {
         return new Parser(
+            typeRegistry,
             allowUnknownFields,
             allowUnknownEnumValues,
             allowUnknownExtensions,
@@ -1834,6 +1925,14 @@ public final class TextFormat {
           endToken = "}";
         }
 
+        // Try to parse human readable format of Any in the form: [type_url]: { ... }
+        if (field.getMessageType().getFullName().equals("google.protobuf.Any")
+            && tokenizer.tryConsume("[")) {
+          value =
+              consumeAnyFieldValue(
+                  tokenizer, extensionRegistry, field, parseTreeBuilder, unknownFields);
+          tokenizer.consume(endToken);
+        } else {
           Message defaultInstance = (extension == null) ? null : extension.defaultInstance;
           MessageReflection.MergeTarget subField =
               target.newMergeTargetForField(field, defaultInstance);
@@ -1846,6 +1945,8 @@ public final class TextFormat {
           }
 
           value = subField.finish();
+        }
+
       } else {
         switch (field.getType()) {
           case INT32:
@@ -1951,6 +2052,71 @@ public final class TextFormat {
       }
     }
 
+    private Object consumeAnyFieldValue(
+        final Tokenizer tokenizer,
+        final ExtensionRegistry extensionRegistry,
+        final FieldDescriptor field,
+        final TextFormatParseInfoTree.Builder parseTreeBuilder,
+        List<UnknownField> unknownFields)
+        throws ParseException {
+      // Try to parse human readable format of Any in the form: [type_url]: { ... }
+      StringBuilder typeUrlBuilder = new StringBuilder();
+      // Parse the type_url inside [].
+      while (true) {
+        typeUrlBuilder.append(tokenizer.consumeIdentifier());
+        if (tokenizer.tryConsume("]")) {
+          break;
+        }
+        if (tokenizer.tryConsume("/")) {
+          typeUrlBuilder.append("/");
+        } else if (tokenizer.tryConsume(".")) {
+          typeUrlBuilder.append(".");
+        } else {
+          throw tokenizer.parseExceptionPreviousToken("Expected a valid type URL.");
+        }
+      }
+      tokenizer.tryConsume(":");
+      final String anyEndToken;
+      if (tokenizer.tryConsume("<")) {
+        anyEndToken = ">";
+      } else {
+        tokenizer.consume("{");
+        anyEndToken = "}";
+      }
+      String typeUrl = typeUrlBuilder.toString();
+      Descriptor contentType = null;
+      try {
+        contentType = typeRegistry.getDescriptorForTypeUrl(typeUrl);
+      } catch (InvalidProtocolBufferException e) {
+        throw tokenizer.parseException("Invalid valid type URL. Found: " + typeUrl);
+      }
+      if (contentType == null) {
+        throw tokenizer.parseException(
+            "Unable to parse Any of type: "
+                + typeUrl
+                + ". Please make sure that the TypeRegistry contains the descriptors for the given"
+                + " types.");
+      }
+      Message.Builder contentBuilder =
+          DynamicMessage.getDefaultInstance(contentType).newBuilderForType();
+      MessageReflection.BuilderAdapter contentTarget =
+          new MessageReflection.BuilderAdapter(contentBuilder);
+      while (!tokenizer.tryConsume(anyEndToken)) {
+        mergeField(tokenizer, extensionRegistry, contentTarget, parseTreeBuilder, unknownFields);
+      }
+
+      // Serialize the content and put it back into an Any. Note that we can't depend on Any here
+      // because of a cyclic dependency (java_proto_library for any_java_proto depends on the
+      // protobuf_impl), so we need to construct the Any using proto reflection.
+      Descriptor anyDescriptor = field.getMessageType();
+      Message.Builder anyBuilder =
+          DynamicMessage.getDefaultInstance(anyDescriptor).newBuilderForType();
+      anyBuilder.setField(anyDescriptor.findFieldByName("type_url"), typeUrlBuilder.toString());
+      anyBuilder.setField(
+          anyDescriptor.findFieldByName("value"), contentBuilder.build().toByteString());
+
+      return anyBuilder.build();
+    }
 
     /** Skips the next field including the field's name and value. */
     private void skipField(Tokenizer tokenizer) throws ParseException {

+ 160 - 0
java/core/src/main/java/com/google/protobuf/TypeRegistry.java

@@ -0,0 +1,160 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.FileDescriptor;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Logger;
+
+/**
+ * A TypeRegistry is used to resolve Any messages. You must provide a TypeRegistry containing all
+ * message types used in Any message fields.
+ */
+public class TypeRegistry {
+  private static final Logger logger = Logger.getLogger(TypeRegistry.class.getName());
+
+  private static class EmptyTypeRegistryHolder {
+    private static final TypeRegistry EMPTY =
+        new TypeRegistry(Collections.<String, Descriptor>emptyMap());
+  }
+
+  public static TypeRegistry getEmptyTypeRegistry() {
+    return EmptyTypeRegistryHolder.EMPTY;
+  }
+
+
+  public static Builder newBuilder() {
+    return new Builder();
+  }
+
+  /**
+   * Find a type by its full name. Returns null if it cannot be found in this {@link TypeRegistry}.
+   */
+  public Descriptor find(String name) {
+    return types.get(name);
+  }
+
+  /**
+   * Find a type by its typeUrl. Returns null if it cannot be found in this {@link TypeRegistry}.
+   */
+  /* @Nullable */
+  public final Descriptor getDescriptorForTypeUrl(String typeUrl)
+      throws InvalidProtocolBufferException {
+    return find(getTypeName(typeUrl));
+  }
+
+  private final Map<String, Descriptor> types;
+
+  TypeRegistry(Map<String, Descriptor> types) {
+    this.types = types;
+  }
+
+  private static String getTypeName(String typeUrl) throws InvalidProtocolBufferException {
+    String[] parts = typeUrl.split("/");
+    if (parts.length == 1) {
+      throw new InvalidProtocolBufferException("Invalid type url found: " + typeUrl);
+    }
+    return parts[parts.length - 1];
+  }
+
+  /** A Builder is used to build {@link TypeRegistry}. */
+  public static final class Builder {
+    private Builder() {}
+
+    /**
+     * Adds a message type and all types defined in the same .proto file as well as all transitively
+     * imported .proto files to this {@link Builder}.
+     */
+    public Builder add(Descriptor messageType) {
+      if (types == null) {
+        throw new IllegalStateException("A TypeRegistry.Builder can only be used once.");
+      }
+      addFile(messageType.getFile());
+      return this;
+    }
+
+    /**
+     * Adds message types and all types defined in the same .proto file as well as all transitively
+     * imported .proto files to this {@link Builder}.
+     */
+    public Builder add(Iterable<Descriptor> messageTypes) {
+      if (types == null) {
+        throw new IllegalStateException("A TypeRegistry.Builder can only be used once.");
+      }
+      for (Descriptor type : messageTypes) {
+        addFile(type.getFile());
+      }
+      return this;
+    }
+
+    /** Builds a {@link TypeRegistry}. This method can only be called once for one Builder. */
+    public TypeRegistry build() {
+      TypeRegistry result = new TypeRegistry(types);
+      // Make sure the built {@link TypeRegistry} is immutable.
+      types = null;
+      return result;
+    }
+
+    private void addFile(FileDescriptor file) {
+      // Skip the file if it's already added.
+      if (!files.add(file.getFullName())) {
+        return;
+      }
+      for (FileDescriptor dependency : file.getDependencies()) {
+        addFile(dependency);
+      }
+      for (Descriptor message : file.getMessageTypes()) {
+        addMessage(message);
+      }
+    }
+
+    private void addMessage(Descriptor message) {
+      for (Descriptor nestedType : message.getNestedTypes()) {
+        addMessage(nestedType);
+      }
+
+      if (types.containsKey(message.getFullName())) {
+        logger.warning("Type " + message.getFullName() + " is added multiple times.");
+        return;
+      }
+
+      types.put(message.getFullName(), message);
+    }
+
+    private final Set<String> files = new HashSet<>();
+    private Map<String, Descriptor> types = new HashMap<>();
+  }
+}

+ 154 - 0
java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java

@@ -115,6 +115,160 @@ public class GeneratedMessageTest extends TestCase {
     GeneratedMessageV3.setAlwaysUseFieldBuildersForTesting(false);
   }
 
+  public void testGetFieldBuilderForExtensionField() {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    Message.Builder fieldBuilder =
+        builder.getFieldBuilder(UnittestProto.optionalNestedMessageExtension.getDescriptor());
+    int expected = 7432;
+    FieldDescriptor field =
+        NestedMessage.getDescriptor().findFieldByNumber(NestedMessage.BB_FIELD_NUMBER);
+    fieldBuilder.setField(field, expected);
+    assertEquals(
+        expected,
+        builder.build().getExtension(UnittestProto.optionalNestedMessageExtension).getBb());
+
+    // fieldBuilder still updates the builder after builder build() has been called.
+    expected += 100;
+    fieldBuilder.setField(field, expected);
+    assertEquals(
+        expected,
+        builder.build().getExtension(UnittestProto.optionalNestedMessageExtension).getBb());
+  }
+
+  public void testGetFieldBuilderWithExistingMessage() {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    builder.setExtension(
+        UnittestProto.optionalNestedMessageExtension,
+        NestedMessage.newBuilder().setBb(123).build());
+    Message.Builder fieldBuilder =
+        builder.getFieldBuilder(UnittestProto.optionalNestedMessageExtension.getDescriptor());
+    int expected = 7432;
+    FieldDescriptor field =
+        NestedMessage.getDescriptor().findFieldByNumber(NestedMessage.BB_FIELD_NUMBER);
+    fieldBuilder.setField(field, expected);
+    assertEquals(
+        expected,
+        builder.build().getExtension(UnittestProto.optionalNestedMessageExtension).getBb());
+
+    // fieldBuilder still updates the builder after builder build() has been called.
+    expected += 100;
+    fieldBuilder.setField(field, expected);
+    assertEquals(
+        expected,
+        builder.build().getExtension(UnittestProto.optionalNestedMessageExtension).getBb());
+  }
+
+  public void testGetFieldBuilderWithExistingBuilder() {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    NestedMessage.Builder nestedMessageBuilder = NestedMessage.newBuilder().setBb(123);
+    builder.setField(
+        UnittestProto.optionalNestedMessageExtension.getDescriptor(), nestedMessageBuilder);
+    Message.Builder fieldBuilder =
+        builder.getFieldBuilder(UnittestProto.optionalNestedMessageExtension.getDescriptor());
+    int expected = 7432;
+    FieldDescriptor field =
+        NestedMessage.getDescriptor().findFieldByNumber(NestedMessage.BB_FIELD_NUMBER);
+    fieldBuilder.setField(field, expected);
+    assertEquals(
+        expected,
+        builder.build().getExtension(UnittestProto.optionalNestedMessageExtension).getBb());
+
+    // Existing nestedMessageBuilder will also update builder.
+    expected += 100;
+    nestedMessageBuilder.setBb(expected);
+    assertEquals(
+        expected,
+        builder.build().getExtension(UnittestProto.optionalNestedMessageExtension).getBb());
+
+    // fieldBuilder still updates the builder.
+    expected += 100;
+    fieldBuilder.setField(field, expected);
+    assertEquals(
+        expected,
+        builder.build().getExtension(UnittestProto.optionalNestedMessageExtension).getBb());
+  }
+
+  public void testGetRepeatedFieldBuilderForExtensionField() {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    builder.addExtension(
+        UnittestProto.repeatedNestedMessageExtension,
+        NestedMessage.newBuilder().setBb(123).build());
+    Message.Builder fieldBuilder =
+        builder.getRepeatedFieldBuilder(
+            UnittestProto.repeatedNestedMessageExtension.getDescriptor(), 0);
+    int expected = 7432;
+    FieldDescriptor field =
+        NestedMessage.getDescriptor().findFieldByNumber(NestedMessage.BB_FIELD_NUMBER);
+    fieldBuilder.setField(field, expected);
+    assertEquals(
+        expected,
+        builder.build().getExtension(UnittestProto.repeatedNestedMessageExtension, 0).getBb());
+
+    // fieldBuilder still updates the builder after builder build() has been called.
+    expected += 100;
+    fieldBuilder.setField(field, expected);
+    assertEquals(
+        expected,
+        builder.build().getExtension(UnittestProto.repeatedNestedMessageExtension, 0).getBb());
+  }
+
+  public void testGetRepeatedFieldBuilderForExistingBuilder() {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    NestedMessage.Builder nestedMessageBuilder = NestedMessage.newBuilder().setBb(123);
+    builder.addRepeatedField(
+        UnittestProto.repeatedNestedMessageExtension.getDescriptor(), nestedMessageBuilder);
+    Message.Builder fieldBuilder =
+        builder.getRepeatedFieldBuilder(
+            UnittestProto.repeatedNestedMessageExtension.getDescriptor(), 0);
+    int expected = 7432;
+    FieldDescriptor field =
+        NestedMessage.getDescriptor().findFieldByNumber(NestedMessage.BB_FIELD_NUMBER);
+    fieldBuilder.setField(field, expected);
+    assertEquals(
+        expected,
+        builder.build().getExtension(UnittestProto.repeatedNestedMessageExtension, 0).getBb());
+
+    // Existing nestedMessageBuilder will also update builder.
+    expected += 100;
+    nestedMessageBuilder.setBb(expected);
+    assertEquals(
+        expected,
+        builder.build().getExtension(UnittestProto.repeatedNestedMessageExtension, 0).getBb());
+
+    // fieldBuilder still updates the builder.
+    expected += 100;
+    fieldBuilder.setField(field, expected);
+    assertEquals(
+        expected,
+        builder.build().getExtension(UnittestProto.repeatedNestedMessageExtension, 0).getBb());
+  }
+
+  public void testGetExtensionFieldOutOfBound() {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    try {
+      builder.getRepeatedField(UnittestProto.repeatedNestedMessageExtension.getDescriptor(), 0);
+      fail("Expected IndexOutOfBoundsException to be thrown");
+    } catch (IndexOutOfBoundsException expected) {
+    }
+    try {
+      builder.getExtension(UnittestProto.repeatedNestedMessageExtension, 0);
+      fail("Expected IndexOutOfBoundsException to be thrown");
+    } catch (IndexOutOfBoundsException expected) {
+    }
+    TestAllExtensions extensionsMessage = builder.build();
+    try {
+      extensionsMessage.getRepeatedField(
+          UnittestProto.repeatedNestedMessageExtension.getDescriptor(), 0);
+      fail("Expected IndexOutOfBoundsException to be thrown");
+    } catch (IndexOutOfBoundsException expected) {
+    }
+    try {
+      extensionsMessage.getExtension(UnittestProto.repeatedNestedMessageExtension, 0);
+      fail("Expected IndexOutOfBoundsException to be thrown");
+    } catch (IndexOutOfBoundsException expected) {
+    }
+  }
+
   public void testDefaultInstance() throws Exception {
     assertSame(
         TestAllTypes.getDefaultInstance(),

+ 5 - 1
java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java

@@ -30,6 +30,7 @@
 
 package com.google.protobuf;
 
+import protobuf_unittest.Engine;
 import protobuf_unittest.Vehicle;
 import protobuf_unittest.Wheel;
 import java.util.ArrayList;
@@ -64,7 +65,7 @@ public class NestedBuildersTest extends TestCase {
     for (int i = 0; i < 4; i++) {
       vehicleBuilder.getWheelBuilder(i).setRadius(5).setWidth(i + 10);
     }
-    vehicleBuilder.getEngineBuilder().setLiters(20);
+    Engine.Builder engineBuilder = vehicleBuilder.getEngineBuilder().setLiters(20);
 
     vehicle = vehicleBuilder.build();
     for (int i = 0; i < 4; i++) {
@@ -74,6 +75,9 @@ public class NestedBuildersTest extends TestCase {
     }
     assertEquals(20, vehicle.getEngine().getLiters());
     assertTrue(vehicle.hasEngine());
+
+    engineBuilder.setLiters(50);
+    assertEquals(50, vehicleBuilder.getEngine().getLiters());
   }
 
   public void testMessagesAreCached() {

+ 191 - 0
java/core/src/test/java/com/google/protobuf/TextFormatTest.java

@@ -33,9 +33,14 @@ package com.google.protobuf;
 import static com.google.protobuf.TestUtil.TEST_REQUIRED_INITIALIZED;
 import static com.google.protobuf.TestUtil.TEST_REQUIRED_UNINITIALIZED;
 
+import com.google.protobuf.DescriptorProtos.DescriptorProto;
+import com.google.protobuf.DescriptorProtos.FieldDescriptorProto;
+import com.google.protobuf.DescriptorProtos.FileDescriptorProto;
 import com.google.protobuf.Descriptors.Descriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.Descriptors.FileDescriptor;
 import com.google.protobuf.TextFormat.Parser.SingularOverwritePolicy;
+import any_test.AnyTestProto.TestAny;
 import map_test.MapTestProto.TestMap;
 import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
 import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
@@ -48,6 +53,7 @@ import protobuf_unittest.UnittestProto.TestOneof2;
 import protobuf_unittest.UnittestProto.TestRequired;
 import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet;
 import java.io.StringReader;
+import java.util.Arrays;
 import java.util.List;
 import java.util.logging.Logger;
 import junit.framework.TestCase;
@@ -506,6 +512,191 @@ public class TextFormatTest extends TestCase {
     assertEquals(2, builder.getOptionalInt64());
   }
 
+  public void testPrintAny_customBuiltTypeRegistry() throws Exception {
+    TestAny testAny =
+        TestAny.newBuilder()
+            .setValue(
+                Any.newBuilder()
+                    .setTypeUrl("type.googleapis.com/" + TestAllTypes.getDescriptor().getFullName())
+                    .setValue(
+                        TestAllTypes.newBuilder().setOptionalInt32(12345).build().toByteString())
+                    .build())
+            .build();
+    String actual =
+        TextFormat.printer()
+            .usingTypeRegistry(TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build())
+            .printToString(testAny);
+    String expected =
+        "value {\n"
+            + "  [type.googleapis.com/protobuf_unittest.TestAllTypes] {\n"
+            + "    optional_int32: 12345\n"
+            + "  }\n"
+            + "}\n";
+    assertEquals(expected, actual);
+  }
+
+  private static Descriptor createDescriptorForAny(FieldDescriptorProto... fields)
+      throws Exception {
+    FileDescriptor fileDescriptor =
+        FileDescriptor.buildFrom(
+            FileDescriptorProto.newBuilder()
+                .setName("any.proto")
+                .setPackage("google.protobuf")
+                .setSyntax("proto3")
+                .addMessageType(
+                    DescriptorProto.newBuilder()
+                        .setName("Any")
+                        .addAllField(Arrays.asList(fields)))
+                .build(),
+            new FileDescriptor[0]);
+    return fileDescriptor.getMessageTypes().get(0);
+  }
+
+  public void testPrintAny_anyWithDynamicMessage() throws Exception {
+    Descriptor descriptor =
+        createDescriptorForAny(
+            FieldDescriptorProto.newBuilder()
+                .setName("type_url")
+                .setNumber(1)
+                .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+                .setType(FieldDescriptorProto.Type.TYPE_STRING)
+                .build(),
+            FieldDescriptorProto.newBuilder()
+                .setName("value")
+                .setNumber(2)
+                .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+                .setType(FieldDescriptorProto.Type.TYPE_BYTES)
+                .build());
+    DynamicMessage testAny =
+        DynamicMessage.newBuilder(descriptor)
+            .setField(
+                descriptor.findFieldByNumber(1),
+                "type.googleapis.com/" + TestAllTypes.getDescriptor().getFullName())
+            .setField(
+                descriptor.findFieldByNumber(2),
+                TestAllTypes.newBuilder().setOptionalInt32(12345).build().toByteString())
+            .build();
+    String actual =
+        TextFormat.printer()
+            .usingTypeRegistry(TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build())
+            .printToString(testAny);
+    String expected =
+        "[type.googleapis.com/protobuf_unittest.TestAllTypes] {\n"
+            + "  optional_int32: 12345\n"
+            + "}\n";
+    assertEquals(expected, actual);
+  }
+
+  public void testPrintAny_anyFromWithNoValueField() throws Exception {
+    Descriptor descriptor =
+        createDescriptorForAny(
+            FieldDescriptorProto.newBuilder()
+                .setName("type_url")
+                .setNumber(1)
+                .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+                .setType(FieldDescriptorProto.Type.TYPE_STRING)
+                .build());
+    DynamicMessage testAny =
+        DynamicMessage.newBuilder(descriptor)
+            .setField(
+                descriptor.findFieldByNumber(1),
+                "type.googleapis.com/" + TestAllTypes.getDescriptor().getFullName())
+            .build();
+    String actual =
+        TextFormat.printer()
+            .usingTypeRegistry(TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build())
+            .printToString(testAny);
+    String expected = "type_url: \"type.googleapis.com/protobuf_unittest.TestAllTypes\"\n";
+    assertEquals(expected, actual);
+  }
+
+  public void testPrintAny_anyFromWithNoTypeUrlField() throws Exception {
+    Descriptor descriptor =
+        createDescriptorForAny(
+            FieldDescriptorProto.newBuilder()
+                .setName("value")
+                .setNumber(2)
+                .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+                .setType(FieldDescriptorProto.Type.TYPE_BYTES)
+                .build());
+    DynamicMessage testAny =
+        DynamicMessage.newBuilder(descriptor)
+            .setField(
+                descriptor.findFieldByNumber(2),
+                TestAllTypes.newBuilder().setOptionalInt32(12345).build().toByteString())
+            .build();
+    String actual =
+        TextFormat.printer()
+            .usingTypeRegistry(TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build())
+            .printToString(testAny);
+    String expected = "value: \"\\b\\271`\"\n";
+    assertEquals(expected, actual);
+  }
+
+  public void testPrintAny_anyWithInvalidFieldType() throws Exception {
+    Descriptor descriptor =
+        createDescriptorForAny(
+            FieldDescriptorProto.newBuilder()
+                .setName("type_url")
+                .setNumber(1)
+                .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+                .setType(FieldDescriptorProto.Type.TYPE_STRING)
+                .build(),
+            FieldDescriptorProto.newBuilder()
+                .setName("value")
+                .setNumber(2)
+                .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+                .setType(FieldDescriptorProto.Type.TYPE_STRING)
+                .build());
+    DynamicMessage testAny =
+        DynamicMessage.newBuilder(descriptor)
+            .setField(
+                descriptor.findFieldByNumber(1),
+                "type.googleapis.com/" + TestAllTypes.getDescriptor().getFullName())
+            .setField(descriptor.findFieldByNumber(2), "test")
+            .build();
+    String actual =
+        TextFormat.printer()
+            .usingTypeRegistry(TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build())
+            .printToString(testAny);
+    String expected =
+        "type_url: \"type.googleapis.com/protobuf_unittest.TestAllTypes\"\n" + "value: \"test\"\n";
+    assertEquals(expected, actual);
+  }
+
+
+  public void testMergeAny_customBuiltTypeRegistry() throws Exception {
+    TestAny.Builder builder = TestAny.newBuilder();
+    TextFormat.Parser.newBuilder()
+        .setTypeRegistry(TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build())
+        .build()
+        .merge(
+            "value: {\n"
+                + "[type.googleapis.com/protobuf_unittest.TestAllTypes] {\n"
+                + "optional_int32: 12345\n"
+                + "optional_nested_message {\n"
+                + "  bb: 123\n"
+                + "}\n"
+                + "}\n"
+                + "}",
+            builder);
+    assertEquals(
+        TestAny.newBuilder()
+            .setValue(
+                Any.newBuilder()
+                    .setTypeUrl("type.googleapis.com/" + TestAllTypes.getDescriptor().getFullName())
+                    .setValue(
+                        TestAllTypes.newBuilder()
+                            .setOptionalInt32(12345)
+                            .setOptionalNestedMessage(
+                                TestAllTypes.NestedMessage.newBuilder().setBb(123))
+                            .build()
+                            .toByteString())
+                    .build())
+            .build(),
+        builder.build());
+  }
+
 
   private void assertParseError(String error, String text) {
     // Test merge().

+ 70 - 0
java/core/src/test/java/com/google/protobuf/TypeRegistryTest.java

@@ -0,0 +1,70 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+
+import com.google.protobuf.Descriptors.Descriptor;
+import protobuf_unittest.UnittestProto;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class TypeRegistryTest {
+
+  @Test
+  public void findDescriptorByFullName() throws Exception {
+    Descriptor descriptor = UnittestProto.TestAllTypes.getDescriptor();
+    assertNull(TypeRegistry.getEmptyTypeRegistry().find(descriptor.getFullName()));
+
+    assertSame(
+        descriptor,
+        TypeRegistry.newBuilder().add(descriptor).build().find(descriptor.getFullName()));
+  }
+
+  @Test
+  public void findDescriptorByTypeUrl() throws Exception {
+    Descriptor descriptor = UnittestProto.TestAllTypes.getDescriptor();
+    assertNull(
+        TypeRegistry.getEmptyTypeRegistry()
+            .getDescriptorForTypeUrl("type.googleapis.com/" + descriptor.getFullName()));
+
+    assertSame(
+        descriptor,
+        TypeRegistry.newBuilder()
+            .add(descriptor)
+            .build()
+            .getDescriptorForTypeUrl("type.googleapis.com/" + descriptor.getFullName()));
+  }
+
+}

+ 0 - 2
java/core/src/test/proto/com/google/protobuf/test_extra_interfaces.proto

@@ -36,8 +36,6 @@ package protobuf_unittest;
 message Proto1 {
   option experimental_java_message_interface =
       "com.google.protobuf.ExtraInterfaces.HasBoolValue";
-  option experimental_java_interface_extends =
-      "com.google.protobuf.ExtraInterfaces.HasByteValue";
   option experimental_java_message_interface =
       "com.google.protobuf.ExtraInterfaces.HasStringValue<Proto1>";
   option experimental_java_builder_interface =

+ 1 - 0
java/lite/pom.xml

@@ -224,6 +224,7 @@
                     <exclude>TextFormatParseLocationTest.java</exclude>
                     <exclude>TextFormatTest.java</exclude>
                     <exclude>TestUtil.java</exclude>
+                    <exclude>TypeRegistryTest.java</exclude>
                     <exclude>UnknownEnumValueTest.java</exclude>
                     <exclude>UnknownFieldSetLiteTest.java</exclude>
                     <exclude>UnknownFieldSetTest.java</exclude>

+ 113 - 27
java/util/src/main/java/com/google/protobuf/util/JsonFormat.java

@@ -108,15 +108,22 @@ public class JsonFormat {
    */
   public static Printer printer() {
     return new Printer(
-        TypeRegistry.getEmptyTypeRegistry(), false, Collections.<FieldDescriptor>emptySet(),
-        false, false, false, false);
+        com.google.protobuf.TypeRegistry.getEmptyTypeRegistry(),
+        TypeRegistry.getEmptyTypeRegistry(),
+        /* alwaysOutputDefaultValueFields */ false,
+        /* includingDefaultValueFields */ Collections.<FieldDescriptor>emptySet(),
+        /* preservingProtoFieldNames */ false,
+        /* omittingInsignificantWhitespace */ false,
+        /* printingEnumsAsInts */ false,
+        /* sortingMapKeys */ false);
   }
 
   /**
    * A Printer converts protobuf message to JSON format.
    */
   public static class Printer {
-    private final TypeRegistry registry;
+    private final com.google.protobuf.TypeRegistry registry;
+    private final TypeRegistry oldRegistry;
     // NOTE: There are 3 states for these *defaultValueFields variables:
     // 1) Default - alwaysOutput is false & including is empty set. Fields only output if they are
     //    set to non-default values.
@@ -133,7 +140,8 @@ public class JsonFormat {
     private final boolean sortingMapKeys;
 
     private Printer(
-        TypeRegistry registry,
+        com.google.protobuf.TypeRegistry registry,
+        TypeRegistry oldRegistry,
         boolean alwaysOutputDefaultValueFields,
         Set<FieldDescriptor> includingDefaultValueFields,
         boolean preservingProtoFieldNames,
@@ -141,6 +149,7 @@ public class JsonFormat {
         boolean printingEnumsAsInts,
         boolean sortingMapKeys) {
       this.registry = registry;
+      this.oldRegistry = oldRegistry;
       this.alwaysOutputDefaultValueFields = alwaysOutputDefaultValueFields;
       this.includingDefaultValueFields = includingDefaultValueFields;
       this.preservingProtoFieldNames = preservingProtoFieldNames;
@@ -150,17 +159,41 @@ public class JsonFormat {
     }
 
     /**
-     * Creates a new {@link Printer} using the given registry. The new Printer
-     * clones all other configurations from the current {@link Printer}.
+     * Creates a new {@link Printer} using the given registry. The new Printer clones all other
+     * configurations from the current {@link Printer}.
      *
      * @throws IllegalArgumentException if a registry is already set.
      */
-    public Printer usingTypeRegistry(TypeRegistry registry) {
-      if (this.registry != TypeRegistry.getEmptyTypeRegistry()) {
+    public Printer usingTypeRegistry(TypeRegistry oldRegistry) {
+      if (this.oldRegistry != TypeRegistry.getEmptyTypeRegistry()
+          || this.registry != com.google.protobuf.TypeRegistry.getEmptyTypeRegistry()) {
+        throw new IllegalArgumentException("Only one registry is allowed.");
+      }
+      return new Printer(
+          com.google.protobuf.TypeRegistry.getEmptyTypeRegistry(),
+          oldRegistry,
+          alwaysOutputDefaultValueFields,
+          includingDefaultValueFields,
+          preservingProtoFieldNames,
+          omittingInsignificantWhitespace,
+          printingEnumsAsInts,
+          sortingMapKeys);
+    }
+
+    /**
+     * Creates a new {@link Printer} using the given registry. The new Printer clones all other
+     * configurations from the current {@link Printer}.
+     *
+     * @throws IllegalArgumentException if a registry is already set.
+     */
+    public Printer usingTypeRegistry(com.google.protobuf.TypeRegistry registry) {
+      if (this.oldRegistry != TypeRegistry.getEmptyTypeRegistry()
+          || this.registry != com.google.protobuf.TypeRegistry.getEmptyTypeRegistry()) {
         throw new IllegalArgumentException("Only one registry is allowed.");
       }
       return new Printer(
           registry,
+          oldRegistry,
           alwaysOutputDefaultValueFields,
           includingDefaultValueFields,
           preservingProtoFieldNames,
@@ -179,6 +212,7 @@ public class JsonFormat {
       checkUnsetIncludingDefaultValueFields();
       return new Printer(
           registry,
+          oldRegistry,
           true,
           Collections.<FieldDescriptor>emptySet(),
           preservingProtoFieldNames,
@@ -197,6 +231,7 @@ public class JsonFormat {
       checkUnsetPrintingEnumsAsInts();
       return new Printer(
           registry,
+          oldRegistry,
           alwaysOutputDefaultValueFields,
           Collections.<FieldDescriptor>emptySet(),
           preservingProtoFieldNames,
@@ -226,6 +261,7 @@ public class JsonFormat {
       checkUnsetIncludingDefaultValueFields();
       return new Printer(
           registry,
+          oldRegistry,
           false,
           Collections.unmodifiableSet(new HashSet<>(fieldsToAlwaysOutput)),
           preservingProtoFieldNames,
@@ -250,6 +286,7 @@ public class JsonFormat {
     public Printer preservingProtoFieldNames() {
       return new Printer(
           registry,
+          oldRegistry,
           alwaysOutputDefaultValueFields,
           includingDefaultValueFields,
           true,
@@ -279,6 +316,7 @@ public class JsonFormat {
     public Printer omittingInsignificantWhitespace() {
       return new Printer(
           registry,
+          oldRegistry,
           alwaysOutputDefaultValueFields,
           includingDefaultValueFields,
           preservingProtoFieldNames,
@@ -302,6 +340,7 @@ public class JsonFormat {
     public Printer sortingMapKeys() {
       return new Printer(
           registry,
+          oldRegistry,
           alwaysOutputDefaultValueFields,
           includingDefaultValueFields,
           preservingProtoFieldNames,
@@ -322,6 +361,7 @@ public class JsonFormat {
       // mobile.
       new PrinterImpl(
               registry,
+              oldRegistry,
               alwaysOutputDefaultValueFields,
               includingDefaultValueFields,
               preservingProtoFieldNames,
@@ -354,37 +394,66 @@ public class JsonFormat {
    * Creates a {@link Parser} with default configuration.
    */
   public static Parser parser() {
-    return new Parser(TypeRegistry.getEmptyTypeRegistry(), false, Parser.DEFAULT_RECURSION_LIMIT);
+    return new Parser(
+        com.google.protobuf.TypeRegistry.getEmptyTypeRegistry(),
+        TypeRegistry.getEmptyTypeRegistry(),
+        false,
+        Parser.DEFAULT_RECURSION_LIMIT);
   }
 
   /**
    * A Parser parses JSON to protobuf message.
    */
   public static class Parser {
-    private final TypeRegistry registry;
+    private final com.google.protobuf.TypeRegistry registry;
+    private final TypeRegistry oldRegistry;
     private final boolean ignoringUnknownFields;
     private final int recursionLimit;
 
     // The default parsing recursion limit is aligned with the proto binary parser.
     private static final int DEFAULT_RECURSION_LIMIT = 100;
 
-    private Parser(TypeRegistry registry, boolean ignoreUnknownFields, int recursionLimit) {
+    private Parser(
+        com.google.protobuf.TypeRegistry registry,
+        TypeRegistry oldRegistry,
+        boolean ignoreUnknownFields,
+        int recursionLimit) {
       this.registry = registry;
+      this.oldRegistry = oldRegistry;
       this.ignoringUnknownFields = ignoreUnknownFields;
       this.recursionLimit = recursionLimit;
     }
 
     /**
-     * Creates a new {@link Parser} using the given registry. The new Parser
-     * clones all other configurations from this Parser.
+     * Creates a new {@link Parser} using the given registry. The new Parser clones all other
+     * configurations from this Parser.
      *
      * @throws IllegalArgumentException if a registry is already set.
      */
-    public Parser usingTypeRegistry(TypeRegistry registry) {
-      if (this.registry != TypeRegistry.getEmptyTypeRegistry()) {
+    public Parser usingTypeRegistry(TypeRegistry oldRegistry) {
+      if (this.oldRegistry != TypeRegistry.getEmptyTypeRegistry()
+          || this.registry != com.google.protobuf.TypeRegistry.getEmptyTypeRegistry()) {
         throw new IllegalArgumentException("Only one registry is allowed.");
       }
-      return new Parser(registry, ignoringUnknownFields, recursionLimit);
+      return new Parser(
+          com.google.protobuf.TypeRegistry.getEmptyTypeRegistry(),
+          oldRegistry,
+          ignoringUnknownFields,
+          recursionLimit);
+    }
+
+    /**
+     * Creates a new {@link Parser} using the given registry. The new Parser clones all other
+     * configurations from this Parser.
+     *
+     * @throws IllegalArgumentException if a registry is already set.
+     */
+    public Parser usingTypeRegistry(com.google.protobuf.TypeRegistry registry) {
+      if (this.oldRegistry != TypeRegistry.getEmptyTypeRegistry()
+          || this.registry != com.google.protobuf.TypeRegistry.getEmptyTypeRegistry()) {
+        throw new IllegalArgumentException("Only one registry is allowed.");
+      }
+      return new Parser(registry, oldRegistry, ignoringUnknownFields, recursionLimit);
     }
 
     /**
@@ -392,7 +461,7 @@ public class JsonFormat {
      * encountered. The new Parser clones all other configurations from this Parser.
      */
     public Parser ignoringUnknownFields() {
-      return new Parser(this.registry, true, recursionLimit);
+      return new Parser(this.registry, oldRegistry, true, recursionLimit);
     }
 
     /**
@@ -404,7 +473,8 @@ public class JsonFormat {
     public void merge(String json, Message.Builder builder) throws InvalidProtocolBufferException {
       // TODO(xiaofeng): Investigate the allocation overhead and optimize for
       // mobile.
-      new ParserImpl(registry, ignoringUnknownFields, recursionLimit).merge(json, builder);
+      new ParserImpl(registry, oldRegistry, ignoringUnknownFields, recursionLimit)
+          .merge(json, builder);
     }
 
     /**
@@ -417,12 +487,13 @@ public class JsonFormat {
     public void merge(Reader json, Message.Builder builder) throws IOException {
       // TODO(xiaofeng): Investigate the allocation overhead and optimize for
       // mobile.
-      new ParserImpl(registry, ignoringUnknownFields, recursionLimit).merge(json, builder);
+      new ParserImpl(registry, oldRegistry, ignoringUnknownFields, recursionLimit)
+          .merge(json, builder);
     }
 
     // For testing only.
     Parser usingRecursionLimit(int recursionLimit) {
-      return new Parser(registry, ignoringUnknownFields, recursionLimit);
+      return new Parser(registry, oldRegistry, ignoringUnknownFields, recursionLimit);
     }
   }
 
@@ -478,7 +549,7 @@ public class JsonFormat {
       @CanIgnoreReturnValue
       public Builder add(Descriptor messageType) {
         if (types == null) {
-          throw new IllegalStateException("A TypeRegistry.Builer can only be used once.");
+          throw new IllegalStateException("A TypeRegistry.Builder can only be used once.");
         }
         addFile(messageType.getFile());
         return this;
@@ -641,7 +712,8 @@ public class JsonFormat {
    * A Printer converts protobuf messages to JSON format.
    */
   private static final class PrinterImpl {
-    private final TypeRegistry registry;
+    private final com.google.protobuf.TypeRegistry registry;
+    private final TypeRegistry oldRegistry;
     private final boolean alwaysOutputDefaultValueFields;
     private final Set<FieldDescriptor> includingDefaultValueFields;
     private final boolean preservingProtoFieldNames;
@@ -658,7 +730,8 @@ public class JsonFormat {
     }
 
     PrinterImpl(
-        TypeRegistry registry,
+        com.google.protobuf.TypeRegistry registry,
+        TypeRegistry oldRegistry,
         boolean alwaysOutputDefaultValueFields,
         Set<FieldDescriptor> includingDefaultValueFields,
         boolean preservingProtoFieldNames,
@@ -667,6 +740,7 @@ public class JsonFormat {
         boolean printingEnumsAsInts,
         boolean sortingMapKeys) {
       this.registry = registry;
+      this.oldRegistry = oldRegistry;
       this.alwaysOutputDefaultValueFields = alwaysOutputDefaultValueFields;
       this.includingDefaultValueFields = includingDefaultValueFields;
       this.preservingProtoFieldNames = preservingProtoFieldNames;
@@ -807,7 +881,10 @@ public class JsonFormat {
       String typeUrl = (String) message.getField(typeUrlField);
       Descriptor type = registry.getDescriptorForTypeUrl(typeUrl);
       if (type == null) {
-        throw new InvalidProtocolBufferException("Cannot find type for url: " + typeUrl);
+        type = oldRegistry.getDescriptorForTypeUrl(typeUrl);
+        if (type == null) {
+          throw new InvalidProtocolBufferException("Cannot find type for url: " + typeUrl);
+        }
       }
       ByteString content = (ByteString) message.getField(valueField);
       Message contentMessage =
@@ -1218,14 +1295,20 @@ public class JsonFormat {
   }
 
   private static class ParserImpl {
-    private final TypeRegistry registry;
+    private final com.google.protobuf.TypeRegistry registry;
+    private final TypeRegistry oldRegistry;
     private final JsonParser jsonParser;
     private final boolean ignoringUnknownFields;
     private final int recursionLimit;
     private int currentDepth;
 
-    ParserImpl(TypeRegistry registry, boolean ignoreUnknownFields, int recursionLimit) {
+    ParserImpl(
+        com.google.protobuf.TypeRegistry registry,
+        TypeRegistry oldRegistry,
+        boolean ignoreUnknownFields,
+        int recursionLimit) {
       this.registry = registry;
+      this.oldRegistry = oldRegistry;
       this.ignoringUnknownFields = ignoreUnknownFields;
       this.jsonParser = new JsonParser();
       this.recursionLimit = recursionLimit;
@@ -1448,7 +1531,10 @@ public class JsonFormat {
       String typeUrl = typeUrlElement.getAsString();
       Descriptor contentType = registry.getDescriptorForTypeUrl(typeUrl);
       if (contentType == null) {
-        throw new InvalidProtocolBufferException("Cannot resolve type: " + typeUrl);
+        contentType = oldRegistry.getDescriptorForTypeUrl(typeUrl);
+        if (contentType == null) {
+          throw new InvalidProtocolBufferException("Cannot resolve type: " + typeUrl);
+        }
       }
       builder.setField(typeUrlField, typeUrl);
       Message.Builder contentBuilder =

+ 50 - 1
java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java

@@ -152,6 +152,16 @@ public class JsonFormatTest extends TestCase {
     assertEquals(message.toString(), parsedMessage.toString());
   }
 
+  private void assertRoundTripEquals(Message message, com.google.protobuf.TypeRegistry registry)
+      throws Exception {
+    JsonFormat.Printer printer = JsonFormat.printer().usingTypeRegistry(registry);
+    JsonFormat.Parser parser = JsonFormat.parser().usingTypeRegistry(registry);
+    Message.Builder builder = message.newBuilderForType();
+    parser.merge(printer.print(message), builder);
+    Message parsedMessage = builder.build();
+    assertEquals(message.toString(), parsedMessage.toString());
+  }
+
   private String toJsonString(Message message) throws IOException {
     return JsonFormat.printer().print(message);
   }
@@ -850,6 +860,45 @@ public class JsonFormatTest extends TestCase {
   }
 
 
+  public void testAnyFieldsWithCustomAddedTypeRegistry() throws Exception {
+    TestAllTypes content = TestAllTypes.newBuilder().setOptionalInt32(1234).build();
+    TestAny message = TestAny.newBuilder().setAnyValue(Any.pack(content)).build();
+
+    com.google.protobuf.TypeRegistry registry =
+        com.google.protobuf.TypeRegistry.newBuilder().add(content.getDescriptorForType()).build();
+    JsonFormat.Printer printer = JsonFormat.printer().usingTypeRegistry(registry);
+
+    assertEquals(
+        "{\n"
+            + "  \"anyValue\": {\n"
+            + "    \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n"
+            + "    \"optionalInt32\": 1234\n"
+            + "  }\n"
+            + "}",
+        printer.print(message));
+    assertRoundTripEquals(message, registry);
+
+    TestAny messageWithDefaultAnyValue =
+        TestAny.newBuilder().setAnyValue(Any.getDefaultInstance()).build();
+    assertEquals("{\n" + "  \"anyValue\": {}\n" + "}", printer.print(messageWithDefaultAnyValue));
+    assertRoundTripEquals(messageWithDefaultAnyValue, registry);
+
+    // Well-known types have a special formatting when embedded in Any.
+    //
+    // 1. Any in Any.
+    Any anyMessage = Any.pack(Any.pack(content));
+    assertEquals(
+        "{\n"
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.Any\",\n"
+            + "  \"value\": {\n"
+            + "    \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n"
+            + "    \"optionalInt32\": 1234\n"
+            + "  }\n"
+            + "}",
+        printer.print(anyMessage));
+    assertRoundTripEquals(anyMessage, registry);
+  }
+
   public void testAnyFields() throws Exception {
     TestAllTypes content = TestAllTypes.newBuilder().setOptionalInt32(1234).build();
     TestAny message = TestAny.newBuilder().setAnyValue(Any.pack(content)).build();
@@ -1136,7 +1185,7 @@ public class JsonFormatTest extends TestCase {
       Any.Builder builder = Any.newBuilder();
       mergeFromJson(
           "{\n"
-              + "  \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n"
+              + "  \"@type\": \"type.googleapis.com/json_test.UnexpectedTypes\",\n"
               + "  \"optionalInt32\": 12345\n"
               + "}",
           builder);

+ 54 - 54
js/binary/decoder.js

@@ -246,20 +246,6 @@ jspb.BinaryDecoder = function(opt_bytes, opt_start, opt_length) {
    */
   this.cursor_ = 0;
 
-  /**
-   * Temporary storage for the low 32 bits of 64-bit data types that we're
-   * decoding.
-   * @private {number}
-   */
-  this.tempLow_ = 0;
-
-  /**
-   * Temporary storage for the high 32 bits of 64-bit data types that we're
-   * decoding.
-   * @private {number}
-   */
-  this.tempHigh_ = 0;
-
   /**
    * Set to true if this decoder encountered an error due to corrupt data.
    * @private {boolean}
@@ -442,9 +428,9 @@ jspb.BinaryDecoder.prototype.getError = function() {
 
 
 /**
- * Reads an unsigned varint from the binary stream and stores it as a split
- * 64-bit integer. Since this does not convert the value to a number, no
- * precision is lost.
+ * Reads an unsigned varint from the binary stream and invokes the conversion
+ * function with the value in two signed 32 bit integers to produce the result.
+ * Since this does not convert the value to a number, no precision is lost.
  *
  * It's possible for an unsigned varint to be incorrectly encoded - more than
  * 64 bits' worth of data could be present. If this happens, this method will
@@ -454,52 +440,72 @@ jspb.BinaryDecoder.prototype.getError = function() {
  * details on the format, see
  * https://developers.google.com/protocol-buffers/docs/encoding
  *
- * @private
+ * @param {function(number, number): T} convert Conversion function to produce
+ *     the result value, takes parameters (lowBits, highBits).
+ * @return {T}
+ * @template T
  */
-jspb.BinaryDecoder.prototype.readSplitVarint64_ = function() {
-  var temp;
+jspb.BinaryDecoder.prototype.readSplitVarint64 = function(convert) {
+  var temp = 128;
   var lowBits = 0;
   var highBits = 0;
 
   // Read the first four bytes of the varint, stopping at the terminator if we
   // see it.
-  for (var i = 0; i < 4; i++) {
+  for (var i = 0; i < 4 && temp >= 128; i++) {
     temp = this.bytes_[this.cursor_++];
     lowBits |= (temp & 0x7F) << (i * 7);
-    if (temp < 128) {
-      this.tempLow_ = lowBits >>> 0;
-      this.tempHigh_ = 0;
-      return;
-    }
   }
 
-  // Read the fifth byte, which straddles the low and high dwords.
-  temp = this.bytes_[this.cursor_++];
-  lowBits |= (temp & 0x7F) << 28;
-  highBits |= (temp & 0x7F) >> 4;
-  if (temp < 128) {
-    this.tempLow_ = lowBits >>> 0;
-    this.tempHigh_ = highBits >>> 0;
-    return;
+  if (temp >= 128) {
+    // Read the fifth byte, which straddles the low and high dwords.
+    temp = this.bytes_[this.cursor_++];
+    lowBits |= (temp & 0x7F) << 28;
+    highBits |= (temp & 0x7F) >> 4;
   }
 
-  // Read the sixth through tenth byte.
-  for (var i = 0; i < 5; i++) {
-    temp = this.bytes_[this.cursor_++];
-    highBits |= (temp & 0x7F) << (i * 7 + 3);
-    if (temp < 128) {
-      this.tempLow_ = lowBits >>> 0;
-      this.tempHigh_ = highBits >>> 0;
-      return;
+  if (temp >= 128) {
+    // Read the sixth through tenth byte.
+    for (var i = 0; i < 5 && temp >= 128; i++) {
+      temp = this.bytes_[this.cursor_++];
+      highBits |= (temp & 0x7F) << (i * 7 + 3);
     }
   }
 
+  if (temp < 128) {
+    return convert(lowBits >>> 0, highBits >>> 0);
+  }
+
   // If we did not see the terminator, the encoding was invalid.
   goog.asserts.fail('Failed to read varint, encoding is invalid.');
   this.error_ = true;
 };
 
 
+/**
+ * Reads a 64-bit fixed-width value from the stream and invokes the conversion
+ * function with the value in two signed 32 bit integers to produce the result.
+ * Since this does not convert the value to a number, no precision is lost.
+ *
+ * @param {function(number, number): T} convert Conversion function to produce
+ *     the result value, takes parameters (lowBits, highBits).
+ * @return {T}
+ * @template T
+ */
+jspb.BinaryDecoder.prototype.readSplitFixed64 = function(convert) {
+  var bytes = this.bytes_;
+  var cursor = this.cursor_;
+  this.cursor_ += 8;
+  var lowBits = 0;
+  var highBits = 0;
+  for (var i = cursor + 7; i >= cursor; i--) {
+    lowBits = (lowBits << 8) | bytes[i];
+    highBits = (highBits << 8) | bytes[i + 4];
+  }
+  return convert(lowBits, highBits);
+};
+
+
 /**
  * Skips over a varint in the block without decoding it.
  */
@@ -668,8 +674,7 @@ jspb.BinaryDecoder.prototype.readZigzagVarint32 = function() {
  *     integer exceeds 2^53.
  */
 jspb.BinaryDecoder.prototype.readUnsignedVarint64 = function() {
-  this.readSplitVarint64_();
-  return jspb.utils.joinUint64(this.tempLow_, this.tempHigh_);
+  return this.readSplitVarint64(jspb.utils.joinUint64);
 };
 
 
@@ -680,8 +685,7 @@ jspb.BinaryDecoder.prototype.readUnsignedVarint64 = function() {
  * @return {string} The decoded unsigned varint as a decimal string.
  */
 jspb.BinaryDecoder.prototype.readUnsignedVarint64String = function() {
-  this.readSplitVarint64_();
-  return jspb.utils.joinUnsignedDecimalString(this.tempLow_, this.tempHigh_);
+  return this.readSplitVarint64(jspb.utils.joinUnsignedDecimalString);
 };
 
 
@@ -694,8 +698,7 @@ jspb.BinaryDecoder.prototype.readUnsignedVarint64String = function() {
  *     integer exceeds 2^53.
  */
 jspb.BinaryDecoder.prototype.readSignedVarint64 = function() {
-  this.readSplitVarint64_();
-  return jspb.utils.joinInt64(this.tempLow_, this.tempHigh_);
+  return this.readSplitVarint64(jspb.utils.joinInt64);
 };
 
 
@@ -706,8 +709,7 @@ jspb.BinaryDecoder.prototype.readSignedVarint64 = function() {
  * @return {string} The decoded signed varint as a decimal string.
  */
 jspb.BinaryDecoder.prototype.readSignedVarint64String = function() {
-  this.readSplitVarint64_();
-  return jspb.utils.joinSignedDecimalString(this.tempLow_, this.tempHigh_);
+  return this.readSplitVarint64(jspb.utils.joinSignedDecimalString);
 };
 
 
@@ -725,8 +727,7 @@ jspb.BinaryDecoder.prototype.readSignedVarint64String = function() {
  *     integer exceeds 2^53.
  */
 jspb.BinaryDecoder.prototype.readZigzagVarint64 = function() {
-  this.readSplitVarint64_();
-  return jspb.utils.joinZigzag64(this.tempLow_, this.tempHigh_);
+  return this.readSplitVarint64(jspb.utils.joinZigzag64);
 };
 
 
@@ -1039,8 +1040,7 @@ jspb.BinaryDecoder.prototype.readBytes = function(length) {
  * @return {string} The hash value.
  */
 jspb.BinaryDecoder.prototype.readVarintHash64 = function() {
-  this.readSplitVarint64_();
-  return jspb.utils.joinHash64(this.tempLow_, this.tempHigh_);
+  return this.readSplitVarint64(jspb.utils.joinHash64);
 };
 
 

+ 52 - 27
js/binary/decoder_test.js

@@ -45,6 +45,7 @@ goog.require('goog.testing.asserts');
 goog.require('jspb.BinaryConstants');
 goog.require('jspb.BinaryDecoder');
 goog.require('jspb.BinaryEncoder');
+goog.require('jspb.utils');
 
 
 /**
@@ -172,11 +173,9 @@ describe('binaryDecoderTest', function() {
   });
 
 
-  /**
-   * Tests reading 64-bit integers as hash strings.
-   */
-  it('testHashStrings', function() {
-    var encoder = new jspb.BinaryEncoder();
+  describe('varint64', function() {
+    var /** !jspb.BinaryEncoder */ encoder;
+    var /** !jspb.BinaryDecoder */ decoder;
 
     var hashA = String.fromCharCode(0x00, 0x00, 0x00, 0x00,
                                     0x00, 0x00, 0x00, 0x00);
@@ -186,28 +185,54 @@ describe('binaryDecoderTest', function() {
                                     0x87, 0x65, 0x43, 0x21);
     var hashD = String.fromCharCode(0xFF, 0xFF, 0xFF, 0xFF,
                                     0xFF, 0xFF, 0xFF, 0xFF);
-
-    encoder.writeVarintHash64(hashA);
-    encoder.writeVarintHash64(hashB);
-    encoder.writeVarintHash64(hashC);
-    encoder.writeVarintHash64(hashD);
-
-    encoder.writeFixedHash64(hashA);
-    encoder.writeFixedHash64(hashB);
-    encoder.writeFixedHash64(hashC);
-    encoder.writeFixedHash64(hashD);
-
-    var decoder = jspb.BinaryDecoder.alloc(encoder.end());
-
-    assertEquals(hashA, decoder.readVarintHash64());
-    assertEquals(hashB, decoder.readVarintHash64());
-    assertEquals(hashC, decoder.readVarintHash64());
-    assertEquals(hashD, decoder.readVarintHash64());
-
-    assertEquals(hashA, decoder.readFixedHash64());
-    assertEquals(hashB, decoder.readFixedHash64());
-    assertEquals(hashC, decoder.readFixedHash64());
-    assertEquals(hashD, decoder.readFixedHash64());
+    beforeEach(function() {
+      encoder = new jspb.BinaryEncoder();
+
+      encoder.writeVarintHash64(hashA);
+      encoder.writeVarintHash64(hashB);
+      encoder.writeVarintHash64(hashC);
+      encoder.writeVarintHash64(hashD);
+
+      encoder.writeFixedHash64(hashA);
+      encoder.writeFixedHash64(hashB);
+      encoder.writeFixedHash64(hashC);
+      encoder.writeFixedHash64(hashD);
+
+      decoder = jspb.BinaryDecoder.alloc(encoder.end());
+    });
+
+    it('reads 64-bit integers as hash strings', function() {
+      assertEquals(hashA, decoder.readVarintHash64());
+      assertEquals(hashB, decoder.readVarintHash64());
+      assertEquals(hashC, decoder.readVarintHash64());
+      assertEquals(hashD, decoder.readVarintHash64());
+
+      assertEquals(hashA, decoder.readFixedHash64());
+      assertEquals(hashB, decoder.readFixedHash64());
+      assertEquals(hashC, decoder.readFixedHash64());
+      assertEquals(hashD, decoder.readFixedHash64());
+    });
+
+    it('reads split 64 bit integers', function() {
+      function hexJoin(bitsLow, bitsHigh) {
+        return `0x${(bitsHigh >>> 0).toString(16)}:0x${
+            (bitsLow >>> 0).toString(16)}`;
+      }
+      function hexJoinHash(hash64) {
+        jspb.utils.splitHash64(hash64);
+        return hexJoin(jspb.utils.split64Low, jspb.utils.split64High);
+      }
+
+      expect(decoder.readSplitVarint64(hexJoin)).toEqual(hexJoinHash(hashA));
+      expect(decoder.readSplitVarint64(hexJoin)).toEqual(hexJoinHash(hashB));
+      expect(decoder.readSplitVarint64(hexJoin)).toEqual(hexJoinHash(hashC));
+      expect(decoder.readSplitVarint64(hexJoin)).toEqual(hexJoinHash(hashD));
+
+      expect(decoder.readSplitFixed64(hexJoin)).toEqual(hexJoinHash(hashA));
+      expect(decoder.readSplitFixed64(hexJoin)).toEqual(hexJoinHash(hashB));
+      expect(decoder.readSplitFixed64(hexJoin)).toEqual(hexJoinHash(hashC));
+      expect(decoder.readSplitFixed64(hexJoin)).toEqual(hexJoinHash(hashD));
+    });
   });
 
   /**

+ 34 - 0
js/binary/reader.js

@@ -954,6 +954,23 @@ jspb.BinaryReader.prototype.readVarintHash64 = function() {
 };
 
 
+/**
+ * Reads a 64-bit varint field from the stream and invokes `convert` to produce
+ * the return value, or throws an error if the next field in the stream is not
+ * of the correct wire type.
+ *
+ * @param {function(number, number): T} convert Conversion function to produce
+ *     the result value, takes parameters (lowBits, highBits).
+ * @return {T}
+ * @template T
+ */
+jspb.BinaryReader.prototype.readSplitVarint64 = function(convert) {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
+  return this.decoder_.readSplitVarint64(convert);
+};
+
+
 /**
  * Reads a 64-bit varint or fixed64 field from the stream and returns it as a
  * 8-character Unicode string for use as a hash table key, or throws an error
@@ -968,6 +985,23 @@ jspb.BinaryReader.prototype.readFixedHash64 = function() {
 };
 
 
+/**
+ * Reads a 64-bit fixed64 field from the stream and invokes `convert`
+ * to produce the return value, or throws an error if the next field in the
+ * stream is not of the correct wire type.
+ *
+ * @param {function(number, number): T} convert Conversion function to produce
+ *     the result value, takes parameters (lowBits, highBits).
+ * @return {T}
+ * @template T
+ */
+jspb.BinaryReader.prototype.readSplitFixed64 = function(convert) {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED64);
+  return this.decoder_.readSplitFixed64(convert);
+};
+
+
 /**
  * Reads a packed scalar field using the supplied raw reader function.
  * @param {function(this:jspb.BinaryDecoder)} decodeMethod

+ 20 - 0
js/binary/reader_test.js

@@ -407,6 +407,26 @@ describe('binaryReaderTest', function() {
       -6, '08 8B 80 80 80 80 80 80 80 80 00');
   });
 
+  /**
+   * Tests reading 64-bit integers as split values.
+   */
+  it('handles split 64 fields', function() {
+    var writer = new jspb.BinaryWriter();
+    writer.writeInt64String(1, '4294967296');
+    writer.writeSfixed64String(2, '4294967298');
+    var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
+
+    function rejoin(lowBits, highBits) {
+      return highBits * 2 ** 32 + (lowBits >>> 0);
+    }
+    reader.nextField();
+    expect(reader.getFieldNumber()).toEqual(1);
+    expect(reader.readSplitVarint64(rejoin)).toEqual(0x100000000);
+
+    reader.nextField();
+    expect(reader.getFieldNumber()).toEqual(2);
+    expect(reader.readSplitFixed64(rejoin)).toEqual(0x100000002);
+  });
 
   /**
    * Tests 64-bit fields that are handled as strings.

+ 43 - 24
js/binary/utils.js

@@ -428,7 +428,6 @@ jspb.utils.joinHash64 = function(bitsLow, bitsHigh) {
   return String.fromCharCode(a, b, c, d, e, f, g, h);
 };
 
-
 /**
  * Individual digits for number->string conversion.
  * @const {!Array<string>}
@@ -438,6 +437,11 @@ jspb.utils.DIGITS = [
   '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
 ];
 
+/** @const @private {number} '0' */
+jspb.utils.ZERO_CHAR_CODE_ = 48;
+
+/** @const @private {number} 'a' */
+jspb.utils.A_CHAR_CODE_ = 97;
 
 /**
  * Losslessly converts a 64-bit unsigned integer in 32:32 split representation
@@ -487,27 +491,20 @@ jspb.utils.joinUnsignedDecimalString = function(bitsLow, bitsHigh) {
     digitB %= base;
   }
 
-  // Convert base-1e7 digits to base-10, omitting leading zeroes.
-  var table = jspb.utils.DIGITS;
-  var start = false;
-  var result = '';
-
-  function emit(digit) {
-    var temp = base;
-    for (var i = 0; i < 7; i++) {
-      temp /= 10;
-      var decimalDigit = ((digit / temp) % 10) >>> 0;
-      if ((decimalDigit == 0) && !start) continue;
-      start = true;
-      result += table[decimalDigit];
+  // Convert base-1e7 digits to base-10, with optional leading zeroes.
+  function decimalFrom1e7(digit1e7, needLeadingZeros) {
+    var partial = digit1e7 ? String(digit1e7) : '';
+    if (needLeadingZeros) {
+      return '0000000'.slice(partial.length) + partial;
     }
+    return partial;
   }
 
-  if (digitC || start) emit(digitC);
-  if (digitB || start) emit(digitB);
-  if (digitA || start) emit(digitA);
-
-  return result;
+  return decimalFrom1e7(digitC, /*needLeadingZeros=*/ 0) +
+      decimalFrom1e7(digitB, /*needLeadingZeros=*/ digitC) +
+      // If the final 1e7 digit didn't need leading zeros, we would have
+      // returned via the trivial code path at the top.
+      decimalFrom1e7(digitA, /*needLeadingZeros=*/ 1);
 };
 
 
@@ -605,7 +602,7 @@ jspb.utils.decimalStringToHash64 = function(dec) {
 
   // For each decimal digit, set result to 10*result + digit.
   for (var i = 0; i < dec.length; i++) {
-    muladd(10, jspb.utils.DIGITS.indexOf(dec[i]));
+    muladd(10, dec.charCodeAt(i) - jspb.utils.ZERO_CHAR_CODE_);
   }
 
   // If there's a minus sign, convert into two's complement.
@@ -627,6 +624,28 @@ jspb.utils.splitDecimalString = function(value) {
   jspb.utils.splitHash64(jspb.utils.decimalStringToHash64(value));
 };
 
+/**
+ * @param {number} nibble A 4-bit integer.
+ * @return {string}
+ * @private
+ */
+jspb.utils.toHexDigit_ = function(nibble) {
+  return String.fromCharCode(
+      nibble < 10 ? jspb.utils.ZERO_CHAR_CODE_ + nibble :
+                    jspb.utils.A_CHAR_CODE_ - 10 + nibble);
+};
+
+/**
+ * @param {number} hexCharCode
+ * @return {number}
+ * @private
+ */
+jspb.utils.fromHexCharCode_ = function(hexCharCode) {
+  if (hexCharCode >= jspb.utils.A_CHAR_CODE_) {
+    return hexCharCode - jspb.utils.A_CHAR_CODE_ + 10;
+  }
+  return hexCharCode - jspb.utils.ZERO_CHAR_CODE_;
+};
 
 /**
  * Converts an 8-character hash string into its hexadecimal representation.
@@ -640,8 +659,8 @@ jspb.utils.hash64ToHexString = function(hash) {
 
   for (var i = 0; i < 8; i++) {
     var c = hash.charCodeAt(7 - i);
-    temp[i * 2 + 2] = jspb.utils.DIGITS[c >> 4];
-    temp[i * 2 + 3] = jspb.utils.DIGITS[c & 0xF];
+    temp[i * 2 + 2] = jspb.utils.toHexDigit_(c >> 4);
+    temp[i * 2 + 3] = jspb.utils.toHexDigit_(c & 0xF);
   }
 
   var result = temp.join('');
@@ -662,8 +681,8 @@ jspb.utils.hexStringToHash64 = function(hex) {
 
   var result = '';
   for (var i = 0; i < 8; i++) {
-    var hi = jspb.utils.DIGITS.indexOf(hex[i * 2 + 2]);
-    var lo = jspb.utils.DIGITS.indexOf(hex[i * 2 + 3]);
+    var hi = jspb.utils.fromHexCharCode_(hex.charCodeAt(i * 2 + 2));
+    var lo = jspb.utils.fromHexCharCode_(hex.charCodeAt(i * 2 + 3));
     result = String.fromCharCode(hi * 16 + lo) + result;
   }
 

+ 106 - 110
js/binary/utils_test.js

@@ -38,7 +38,6 @@
 
 goog.require('goog.crypt');
 goog.require('goog.crypt.base64');
-goog.require('goog.testing.asserts');
 goog.require('jspb.BinaryConstants');
 goog.require('jspb.BinaryWriter');
 goog.require('jspb.utils');
@@ -82,36 +81,36 @@ describe('binaryUtilsTest', function() {
     // Check some magic numbers.
     var result =
         jspb.utils.joinUnsignedDecimalString(0x89e80001, 0x8ac72304);
-    assertEquals('10000000000000000001', result);
+    expect(result).toEqual('10000000000000000001');
 
     result = jspb.utils.joinUnsignedDecimalString(0xacd05f15, 0x1b69b4b);
-    assertEquals('123456789123456789', result);
+    expect(result).toEqual('123456789123456789');
 
     result = jspb.utils.joinUnsignedDecimalString(0xeb1f0ad2, 0xab54a98c);
-    assertEquals('12345678901234567890', result);
+    expect(result).toEqual('12345678901234567890');
 
     result = jspb.utils.joinUnsignedDecimalString(0xe3b70cb1, 0x891087b8);
-    assertEquals('9876543210987654321', result);
+    expect(result).toEqual('9876543210987654321');
 
     // Check limits.
     result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x00000000);
-    assertEquals('0', result);
+    expect(result).toEqual('0');
 
     result = jspb.utils.joinUnsignedDecimalString(0xFFFFFFFF, 0xFFFFFFFF);
-    assertEquals('18446744073709551615', result);
+    expect(result).toEqual('18446744073709551615');
 
     // Check each bit of the low dword.
     for (var i = 0; i < 32; i++) {
       var low = (1 << i) >>> 0;
       result = jspb.utils.joinUnsignedDecimalString(low, 0);
-      assertEquals('' + Math.pow(2, i), result);
+      expect(result).toEqual('' + Math.pow(2, i));
     }
 
     // Check the first 20 bits of the high dword.
     for (var i = 0; i < 20; i++) {
       var high = (1 << i) >>> 0;
       result = jspb.utils.joinUnsignedDecimalString(0, high);
-      assertEquals('' + Math.pow(2, 32 + i), result);
+      expect(result).toEqual('' + Math.pow(2, 32 + i));
     }
 
     // V8's internal double-to-string conversion is inaccurate for values above
@@ -119,40 +118,40 @@ describe('binaryUtilsTest', function() {
     // manually against the correct string representations of 2^N.
 
     result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x00100000);
-    assertEquals('4503599627370496', result);
+    expect(result).toEqual('4503599627370496');
 
     result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x00200000);
-    assertEquals('9007199254740992', result);
+    expect(result).toEqual('9007199254740992');
 
     result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x00400000);
-    assertEquals('18014398509481984', result);
+    expect(result).toEqual('18014398509481984');
 
     result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x00800000);
-    assertEquals('36028797018963968', result);
+    expect(result).toEqual('36028797018963968');
 
     result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x01000000);
-    assertEquals('72057594037927936', result);
+    expect(result).toEqual('72057594037927936');
 
     result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x02000000);
-    assertEquals('144115188075855872', result);
+    expect(result).toEqual('144115188075855872');
 
     result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x04000000);
-    assertEquals('288230376151711744', result);
+    expect(result).toEqual('288230376151711744');
 
     result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x08000000);
-    assertEquals('576460752303423488', result);
+    expect(result).toEqual('576460752303423488');
 
     result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x10000000);
-    assertEquals('1152921504606846976', result);
+    expect(result).toEqual('1152921504606846976');
 
     result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x20000000);
-    assertEquals('2305843009213693952', result);
+    expect(result).toEqual('2305843009213693952');
 
     result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x40000000);
-    assertEquals('4611686018427387904', result);
+    expect(result).toEqual('4611686018427387904');
 
     result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x80000000);
-    assertEquals('9223372036854775808', result);
+    expect(result).toEqual('9223372036854775808');
   });
 
 
@@ -164,38 +163,38 @@ describe('binaryUtilsTest', function() {
     var convert = jspb.utils.hash64ToDecimalString;
 
     result = convert(toHashString(0x00000000, 0x00000000), false);
-    assertEquals('0', result);
+    expect(result).toEqual('0');
 
     result = convert(toHashString(0x00000000, 0x00000000), true);
-    assertEquals('0', result);
+    expect(result).toEqual('0');
 
     result = convert(toHashString(0xFFFFFFFF, 0xFFFFFFFF), false);
-    assertEquals('18446744073709551615', result);
+    expect(result).toEqual('18446744073709551615');
 
     result = convert(toHashString(0xFFFFFFFF, 0xFFFFFFFF), true);
-    assertEquals('-1', result);
+    expect(result).toEqual('-1');
 
     result = convert(toHashString(0x00000000, 0x80000000), false);
-    assertEquals('9223372036854775808', result);
+    expect(result).toEqual('9223372036854775808');
 
     result = convert(toHashString(0x00000000, 0x80000000), true);
-    assertEquals('-9223372036854775808', result);
+    expect(result).toEqual('-9223372036854775808');
 
     result = convert(toHashString(0xacd05f15, 0x01b69b4b), false);
-    assertEquals('123456789123456789', result);
+    expect(result).toEqual('123456789123456789');
 
     result = convert(toHashString(~0xacd05f15 + 1, ~0x01b69b4b), true);
-    assertEquals('-123456789123456789', result);
+    expect(result).toEqual('-123456789123456789');
 
     // And converting arrays of hashes should work the same way.
     result = jspb.utils.hash64ArrayToDecimalStrings([
       toHashString(0xFFFFFFFF, 0xFFFFFFFF),
       toHashString(0x00000000, 0x80000000),
       toHashString(0xacd05f15, 0x01b69b4b)], false);
-    assertEquals(3, result.length);
-    assertEquals('18446744073709551615', result[0]);
-    assertEquals('9223372036854775808', result[1]);
-    assertEquals('123456789123456789', result[2]);
+    expect(result.length).toEqual(3);
+    expect(result[0]).toEqual('18446744073709551615');
+    expect(result[1]).toEqual('9223372036854775808');
+    expect(result[2]).toEqual('123456789123456789');
   });
 
   /*
@@ -206,32 +205,32 @@ describe('binaryUtilsTest', function() {
     var convert = jspb.utils.decimalStringToHash64;
 
     result = convert('0');
-    assertEquals(goog.crypt.byteArrayToString(
-      [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), result);
+    expect(result).toEqual(goog.crypt.byteArrayToString(
+        [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]));
 
     result = convert('-1');
-    assertEquals(goog.crypt.byteArrayToString(
-      [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]), result);
+    expect(result).toEqual(goog.crypt.byteArrayToString(
+        [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]));
 
     result = convert('18446744073709551615');
-    assertEquals(goog.crypt.byteArrayToString(
-      [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]), result);
+    expect(result).toEqual(goog.crypt.byteArrayToString(
+        [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]));
 
     result = convert('9223372036854775808');
-    assertEquals(goog.crypt.byteArrayToString(
-      [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80]), result);
+    expect(result).toEqual(goog.crypt.byteArrayToString(
+        [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80]));
 
     result = convert('-9223372036854775808');
-    assertEquals(goog.crypt.byteArrayToString(
-      [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80]), result);
+    expect(result).toEqual(goog.crypt.byteArrayToString(
+        [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80]));
 
     result = convert('123456789123456789');
-    assertEquals(goog.crypt.byteArrayToString(
-      [0x15, 0x5F, 0xD0, 0xAC, 0x4B, 0x9B, 0xB6, 0x01]), result);
+    expect(result).toEqual(goog.crypt.byteArrayToString(
+        [0x15, 0x5F, 0xD0, 0xAC, 0x4B, 0x9B, 0xB6, 0x01]));
 
     result = convert('-123456789123456789');
-    assertEquals(goog.crypt.byteArrayToString(
-      [0xEB, 0xA0, 0x2F, 0x53, 0xB4, 0x64, 0x49, 0xFE]), result);
+    expect(result).toEqual(goog.crypt.byteArrayToString(
+        [0xEB, 0xA0, 0x2F, 0x53, 0xB4, 0x64, 0x49, 0xFE]));
   });
 
   /**
@@ -242,13 +241,13 @@ describe('binaryUtilsTest', function() {
     var convert = jspb.utils.hash64ToHexString;
 
     result = convert(toHashString(0x00000000, 0x00000000));
-    assertEquals('0x0000000000000000', result);
+    expect(result).toEqual('0x0000000000000000');
 
     result = convert(toHashString(0xFFFFFFFF, 0xFFFFFFFF));
-    assertEquals('0xffffffffffffffff', result);
+    expect(result).toEqual('0xffffffffffffffff');
 
     result = convert(toHashString(0x12345678, 0x9ABCDEF0));
-    assertEquals('0x9abcdef012345678', result);
+    expect(result).toEqual('0x9abcdef012345678');
   });
 
 
@@ -260,22 +259,22 @@ describe('binaryUtilsTest', function() {
     var convert = jspb.utils.hexStringToHash64;
 
     result = convert('0x0000000000000000');
-    assertEquals(goog.crypt.byteArrayToString(
-        [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), result);
+    expect(result).toEqual(goog.crypt.byteArrayToString(
+        [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]));
 
     result = convert('0xffffffffffffffff');
-    assertEquals(goog.crypt.byteArrayToString(
-        [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]), result);
+    expect(result).toEqual(goog.crypt.byteArrayToString(
+        [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]));
 
     // Hex string is big-endian, hash string is little-endian.
     result = convert('0x123456789ABCDEF0');
-    assertEquals(goog.crypt.byteArrayToString(
-        [0xF0, 0xDE, 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12]), result);
+    expect(result).toEqual(goog.crypt.byteArrayToString(
+        [0xF0, 0xDE, 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12]));
 
     // Capitalization should not matter.
     result = convert('0x0000abcdefABCDEF');
-    assertEquals(goog.crypt.byteArrayToString(
-        [0xEF, 0xCD, 0xAB, 0xEF, 0xCD, 0xAB, 0x00, 0x00]), result);
+    expect(result).toEqual(goog.crypt.byteArrayToString(
+        [0xEF, 0xCD, 0xAB, 0xEF, 0xCD, 0xAB, 0x00, 0x00]));
   });
 
 
@@ -288,25 +287,25 @@ describe('binaryUtilsTest', function() {
     var convert = jspb.utils.numberToHash64;
 
     result = convert(0x0000000000000);
-    assertEquals('0x0000000000000000', jspb.utils.hash64ToHexString(result));
+    expect(jspb.utils.hash64ToHexString(result)).toEqual('0x0000000000000000');
 
     result = convert(0xFFFFFFFFFFFFF);
-    assertEquals('0x000fffffffffffff', jspb.utils.hash64ToHexString(result));
+    expect(jspb.utils.hash64ToHexString(result)).toEqual('0x000fffffffffffff');
 
     result = convert(0x123456789ABCD);
-    assertEquals('0x000123456789abcd', jspb.utils.hash64ToHexString(result));
+    expect(jspb.utils.hash64ToHexString(result)).toEqual('0x000123456789abcd');
 
     result = convert(0xDCBA987654321);
-    assertEquals('0x000dcba987654321', jspb.utils.hash64ToHexString(result));
+    expect(jspb.utils.hash64ToHexString(result)).toEqual('0x000dcba987654321');
 
     // 53 bits of precision should not be truncated.
     result = convert(0x10000000000001);
-    assertEquals('0x0010000000000001', jspb.utils.hash64ToHexString(result));
+    expect(jspb.utils.hash64ToHexString(result)).toEqual('0x0010000000000001');
 
     // 54 bits of precision should be truncated.
     result = convert(0x20000000000001);
-    assertNotEquals(
-        '0x0020000000000001', jspb.utils.hash64ToHexString(result));
+    expect(jspb.utils.hash64ToHexString(result))
+        .not.toEqual('0x0020000000000001');
   });
 
 
@@ -322,15 +321,15 @@ describe('binaryUtilsTest', function() {
     // come back out of the string unchanged.
     for (var i = 0; i < 65536; i++) {
       strings[i] = 'a' + String.fromCharCode(i) + 'a';
-      if (3 != strings[i].length) throw 'fail!';
-      if (i != strings[i].charCodeAt(1)) throw 'fail!';
+      expect(strings[i].length).toEqual(3);
+      expect(strings[i].charCodeAt(1)).toEqual(i);
     }
 
     // Each unicode character should compare equal to itself and not equal to a
     // different unicode character.
     for (var i = 0; i < 65536; i++) {
-      if (strings[i] != strings[i]) throw 'fail!';
-      if (strings[i] == strings[(i + 1) % 65536]) throw 'fail!';
+      expect(strings[i] == strings[i]).toEqual(true);
+      expect(strings[i] == strings[(i + 1) % 65536]).toEqual(false);
     }
   });
 
@@ -345,10 +344,9 @@ describe('binaryUtilsTest', function() {
 
     // NaN.
     jspb.utils.splitFloat32(NaN);
-    if (!isNaN(jspb.utils.joinFloat32(jspb.utils.split64Low,
-                                      jspb.utils.split64High))) {
-      throw 'fail!';
-    }
+    expect(isNaN(jspb.utils.joinFloat32(
+               jspb.utils.split64Low, jspb.utils.split64High)))
+        .toEqual(true);
 
     /**
      * @param {number} x
@@ -359,10 +357,9 @@ describe('binaryUtilsTest', function() {
       if (goog.isDef(opt_bits)) {
         if (opt_bits != jspb.utils.split64Low) throw 'fail!';
       }
-      if (truncate(x) != jspb.utils.joinFloat32(jspb.utils.split64Low,
-          jspb.utils.split64High)) {
-        throw 'fail!';
-      }
+      expect(truncate(x))
+          .toEqual(jspb.utils.joinFloat32(
+              jspb.utils.split64Low, jspb.utils.split64High));
     }
 
     // Positive and negative infinity.
@@ -411,10 +408,9 @@ describe('binaryUtilsTest', function() {
 
     // NaN.
     jspb.utils.splitFloat64(NaN);
-    if (!isNaN(jspb.utils.joinFloat64(jspb.utils.split64Low,
-        jspb.utils.split64High))) {
-      throw 'fail!';
-    }
+    expect(isNaN(jspb.utils.joinFloat64(
+               jspb.utils.split64Low, jspb.utils.split64High)))
+        .toEqual(true);
 
     /**
      * @param {number} x
@@ -429,10 +425,9 @@ describe('binaryUtilsTest', function() {
       if (goog.isDef(opt_lowBits)) {
         if (opt_lowBits != jspb.utils.split64Low) throw 'fail!';
       }
-      if (x != jspb.utils.joinFloat64(jspb.utils.split64Low,
-          jspb.utils.split64High)) {
-        throw 'fail!';
-      }
+      expect(
+          jspb.utils.joinFloat64(jspb.utils.split64Low, jspb.utils.split64High))
+          .toEqual(x);
     }
 
     // Positive and negative infinity.
@@ -487,8 +482,8 @@ describe('binaryUtilsTest', function() {
 
     // We should have two more varints than we started with - one for the field
     // tag, one for the packed length.
-    assertEquals(values.length + 2,
-                 jspb.utils.countVarints(buffer, 0, buffer.length));
+    expect(jspb.utils.countVarints(buffer, 0, buffer.length))
+        .toEqual(values.length + 2);
   });
 
 
@@ -506,8 +501,8 @@ describe('binaryUtilsTest', function() {
     writer.writeString(2, 'terminator');
 
     var buffer = new Uint8Array(writer.getResultBuffer());
-    assertEquals(count,
-        jspb.utils.countVarintFields(buffer, 0, buffer.length, 1));
+    expect(jspb.utils.countVarintFields(buffer, 0, buffer.length, 1))
+        .toEqual(count);
 
     writer = new jspb.BinaryWriter();
 
@@ -519,8 +514,8 @@ describe('binaryUtilsTest', function() {
     writer.writeString(2, 'terminator');
 
     buffer = new Uint8Array(writer.getResultBuffer());
-    assertEquals(count,
-        jspb.utils.countVarintFields(buffer, 0, buffer.length, 123456789));
+    expect(jspb.utils.countVarintFields(buffer, 0, buffer.length, 123456789))
+        .toEqual(count);
   });
 
 
@@ -538,8 +533,8 @@ describe('binaryUtilsTest', function() {
     writer.writeString(2, 'terminator');
 
     var buffer = new Uint8Array(writer.getResultBuffer());
-    assertEquals(count,
-        jspb.utils.countFixed32Fields(buffer, 0, buffer.length, 1));
+    expect(jspb.utils.countFixed32Fields(buffer, 0, buffer.length, 1))
+        .toEqual(count);
 
     writer = new jspb.BinaryWriter();
 
@@ -551,8 +546,8 @@ describe('binaryUtilsTest', function() {
     writer.writeString(2, 'terminator');
 
     buffer = new Uint8Array(writer.getResultBuffer());
-    assertEquals(count,
-        jspb.utils.countFixed32Fields(buffer, 0, buffer.length, 123456789));
+    expect(jspb.utils.countFixed32Fields(buffer, 0, buffer.length, 123456789))
+        .toEqual(count);
   });
 
 
@@ -570,8 +565,8 @@ describe('binaryUtilsTest', function() {
     writer.writeString(2, 'terminator');
 
     var buffer = new Uint8Array(writer.getResultBuffer());
-    assertEquals(count,
-        jspb.utils.countFixed64Fields(buffer, 0, buffer.length, 1));
+    expect(jspb.utils.countFixed64Fields(buffer, 0, buffer.length, 1))
+        .toEqual(count);
 
     writer = new jspb.BinaryWriter();
 
@@ -583,8 +578,8 @@ describe('binaryUtilsTest', function() {
     writer.writeString(2, 'terminator');
 
     buffer = new Uint8Array(writer.getResultBuffer());
-    assertEquals(count,
-        jspb.utils.countFixed64Fields(buffer, 0, buffer.length, 123456789));
+    expect(jspb.utils.countFixed64Fields(buffer, 0, buffer.length, 123456789))
+        .toEqual(count);
   });
 
 
@@ -602,8 +597,8 @@ describe('binaryUtilsTest', function() {
     writer.writeString(2, 'terminator');
 
     var buffer = new Uint8Array(writer.getResultBuffer());
-    assertEquals(count,
-        jspb.utils.countDelimitedFields(buffer, 0, buffer.length, 1));
+    expect(jspb.utils.countDelimitedFields(buffer, 0, buffer.length, 1))
+        .toEqual(count);
 
     writer = new jspb.BinaryWriter();
 
@@ -615,8 +610,8 @@ describe('binaryUtilsTest', function() {
     writer.writeString(2, 'terminator');
 
     buffer = new Uint8Array(writer.getResultBuffer());
-    assertEquals(count,
-        jspb.utils.countDelimitedFields(buffer, 0, buffer.length, 123456789));
+    expect(jspb.utils.countDelimitedFields(buffer, 0, buffer.length, 123456789))
+        .toEqual(count);
   });
 
 
@@ -624,9 +619,10 @@ describe('binaryUtilsTest', function() {
    * Tests byte format for debug strings.
    */
   it('testDebugBytesToTextFormat', function() {
-    assertEquals('""', jspb.utils.debugBytesToTextFormat(null));
-    assertEquals('"\\x00\\x10\\xff"',
-        jspb.utils.debugBytesToTextFormat([0, 16, 255]));
+    expect(jspb.utils.debugBytesToTextFormat(null)).toEqual('""');
+    expect(jspb.utils.debugBytesToTextFormat([
+      0, 16, 255
+    ])).toEqual('"\\x00\\x10\\xff"');
   });
 
 
@@ -647,15 +643,15 @@ describe('binaryUtilsTest', function() {
     var sourceString = goog.crypt.byteArrayToString(sourceData);
 
     function check(result) {
-      assertEquals(Uint8Array, result.constructor);
-      assertEquals(sourceData.length, result.length);
+      expect(result.constructor).toEqual(Uint8Array);
+      expect(result.length).toEqual(sourceData.length);
       for (var i = 0; i < result.length; i++) {
-        assertEquals(sourceData[i], result[i]);
+        expect(result[i]).toEqual(sourceData[i]);
       }
     }
 
     // Converting Uint8Arrays into Uint8Arrays should be a no-op.
-    assertEquals(sourceBytes, convert(sourceBytes));
+    expect(convert(sourceBytes)).toEqual(sourceBytes);
 
     // Converting Array<numbers> into Uint8Arrays should work.
     check(convert(sourceData));

+ 98 - 0
js/binary/writer.js

@@ -886,6 +886,32 @@ jspb.BinaryWriter.prototype.writeVarintHash64 = function(field, value) {
 };
 
 
+/**
+ * Writes a 64-bit field to the buffer as a fixed64.
+ * @param {number} field The field number.
+ * @param {number} lowBits The low 32 bits.
+ * @param {number} highBits The high 32 bits.
+ */
+jspb.BinaryWriter.prototype.writeSplitFixed64 = function(
+    field, lowBits, highBits) {
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
+  this.encoder_.writeSplitFixed64(lowBits, highBits);
+};
+
+
+/**
+ * Writes a 64-bit field to the buffer as a varint.
+ * @param {number} field The field number.
+ * @param {number} lowBits The low 32 bits.
+ * @param {number} highBits The high 32 bits.
+ */
+jspb.BinaryWriter.prototype.writeSplitVarint64 = function(
+    field, lowBits, highBits) {
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.encoder_.writeSplitVarint64(lowBits, highBits);
+};
+
+
 /**
  * Writes an array of numbers to the buffer as a repeated 32-bit int field.
  * @param {number} field The field number.
@@ -926,6 +952,40 @@ jspb.BinaryWriter.prototype.writeRepeatedInt64 = function(field, value) {
 };
 
 
+/**
+ * Writes an array of 64-bit values to the buffer as a fixed64.
+ * @param {number} field The field number.
+ * @param {?Array<T>} value The value.
+ * @param {function(T): number} lo Function to get low bits.
+ * @param {function(T): number} hi Function to get high bits.
+ * @template T
+ */
+jspb.BinaryWriter.prototype.writeRepeatedSplitFixed64 = function(
+    field, value, lo, hi) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeSplitFixed64(field, lo(value[i]), hi(value[i]));
+  }
+};
+
+
+/**
+ * Writes an array of 64-bit values to the buffer as a varint.
+ * @param {number} field The field number.
+ * @param {?Array<T>} value The value.
+ * @param {function(T): number} lo Function to get low bits.
+ * @param {function(T): number} hi Function to get high bits.
+ * @template T
+ */
+jspb.BinaryWriter.prototype.writeRepeatedSplitVarint64 = function(
+    field, value, lo, hi) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeSplitVarint64(field, lo(value[i]), hi(value[i]));
+  }
+};
+
+
 /**
  * Writes an array of numbers formatted as strings to the buffer as a repeated
  * 64-bit int field.
@@ -1313,6 +1373,44 @@ jspb.BinaryWriter.prototype.writePackedInt64 = function(field, value) {
 };
 
 
+/**
+ * Writes an array of 64-bit values to the buffer as a fixed64.
+ * @param {number} field The field number.
+ * @param {?Array<T>} value The value.
+ * @param {function(T): number} lo Function to get low bits.
+ * @param {function(T): number} hi Function to get high bits.
+ * @template T
+ */
+jspb.BinaryWriter.prototype.writePackedSplitFixed64 = function(
+    field, value, lo, hi) {
+  if (value == null) return;
+  var bookmark = this.beginDelimited_(field);
+  for (var i = 0; i < value.length; i++) {
+    this.encoder_.writeSplitFixed64(lo(value[i]), hi(value[i]));
+  }
+  this.endDelimited_(bookmark);
+};
+
+
+/**
+ * Writes an array of 64-bit values to the buffer as a varint.
+ * @param {number} field The field number.
+ * @param {?Array<T>} value The value.
+ * @param {function(T): number} lo Function to get low bits.
+ * @param {function(T): number} hi Function to get high bits.
+ * @template T
+ */
+jspb.BinaryWriter.prototype.writePackedSplitVarint64 = function(
+    field, value, lo, hi) {
+  if (value == null) return;
+  var bookmark = this.beginDelimited_(field);
+  for (var i = 0; i < value.length; i++) {
+    this.encoder_.writeSplitVarint64(lo(value[i]), hi(value[i]));
+  }
+  this.endDelimited_(bookmark);
+};
+
+
 /**
  * Writes an array of numbers represented as strings to the buffer as a packed
  * 64-bit int field.

+ 71 - 0
js/binary/writer_test.js

@@ -40,6 +40,7 @@
 
 goog.require('goog.crypt');
 goog.require('goog.testing.asserts');
+goog.require('jspb.BinaryReader');
 goog.require('jspb.BinaryWriter');
 
 
@@ -130,4 +131,74 @@ describe('binaryWriterTest', function() {
     assertEquals('CgF/', writer.getResultBase64String(false));
     assertEquals('CgF_', writer.getResultBase64String(true));
   });
+
+  it('writes split 64 fields', function() {
+    var writer = new jspb.BinaryWriter();
+    writer.writeSplitVarint64(1, 0x1, 0x2);
+    writer.writeSplitVarint64(1, 0xFFFFFFFF, 0xFFFFFFFF);
+    writer.writeSplitFixed64(2, 0x1, 0x2);
+    writer.writeSplitFixed64(2, 0xFFFFFFF0, 0xFFFFFFFF);
+    function lo(i) {
+      return i + 1;
+    }
+    function hi(i) {
+      return i + 2;
+    }
+    writer.writeRepeatedSplitVarint64(3, [0, 1, 2], lo, hi);
+    writer.writeRepeatedSplitFixed64(4, [0, 1, 2], lo, hi);
+    writer.writePackedSplitVarint64(5, [0, 1, 2], lo, hi);
+    writer.writePackedSplitFixed64(6, [0, 1, 2], lo, hi);
+
+    function bitsAsArray(lowBits, highBits) {
+      return [lowBits >>> 0, highBits >>> 0];
+    }
+    var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
+    reader.nextField();
+    expect(reader.getFieldNumber()).toEqual(1);
+    expect(reader.readSplitVarint64(bitsAsArray)).toEqual([0x1, 0x2]);
+
+    reader.nextField();
+    expect(reader.getFieldNumber()).toEqual(1);
+    expect(reader.readSplitVarint64(bitsAsArray)).toEqual([
+      0xFFFFFFFF, 0xFFFFFFFF
+    ]);
+
+    reader.nextField();
+    expect(reader.getFieldNumber()).toEqual(2);
+    expect(reader.readSplitFixed64(bitsAsArray)).toEqual([0x1, 0x2]);
+
+    reader.nextField();
+    expect(reader.getFieldNumber()).toEqual(2);
+    expect(reader.readSplitFixed64(bitsAsArray)).toEqual([
+      0xFFFFFFF0, 0xFFFFFFFF
+    ]);
+
+    for (let i = 0; i < 3; i++) {
+      reader.nextField();
+      expect(reader.getFieldNumber()).toEqual(3);
+      expect(reader.readSplitVarint64(bitsAsArray)).toEqual([i + 1, i + 2]);
+    }
+
+    for (let i = 0; i < 3; i++) {
+      reader.nextField();
+      expect(reader.getFieldNumber()).toEqual(4);
+      expect(reader.readSplitFixed64(bitsAsArray)).toEqual([i + 1, i + 2]);
+    }
+
+    reader.nextField();
+    expect(reader.getFieldNumber()).toEqual(5);
+    expect(reader.readPackedInt64String()).toEqual([
+      String(2 * 2 ** 32 + 1),
+      String(3 * 2 ** 32 + 2),
+      String(4 * 2 ** 32 + 3),
+    ]);
+
+    reader.nextField();
+    expect(reader.getFieldNumber()).toEqual(6);
+    expect(reader.readPackedFixed64String()).toEqual([
+      String(2 * 2 ** 32 + 1),
+      String(3 * 2 ** 32 + 2),
+      String(4 * 2 ** 32 + 3),
+    ]);
+  });
 });

+ 6 - 2
js/map.js

@@ -465,11 +465,15 @@ jspb.Map.prototype.serializeBinary = function(
  *    entries with unset keys is required for maps to be backwards compatible
  *    with the repeated message representation described here: goo.gl/zuoLAC
  *
+ * @param {V=} opt_defaultValue
+ *    The default value for the type of map values.
+ *
  */
 jspb.Map.deserializeBinary = function(map, reader, keyReaderFn, valueReaderFn,
-                                      opt_valueReaderCallback, opt_defaultKey) {
+                                      opt_valueReaderCallback, opt_defaultKey,
+                                      opt_defaultValue) {
   var key = opt_defaultKey;
-  var value = undefined;
+  var value = opt_defaultValue;
 
   while (reader.nextField()) {
     if (reader.isEndGroup()) {

+ 72 - 26
js/message.js

@@ -104,7 +104,7 @@ jspb.ExtensionFieldInfo = function(fieldNumber, fieldName, ctor, toObjectFn,
 /**
  * Stores binary-related information for a single extension field.
  * @param {!jspb.ExtensionFieldInfo<T>} fieldInfo
- * @param {function(this:jspb.BinaryReader,number,?)} binaryReaderFn
+ * @param {function(this:jspb.BinaryReader,number,?,?)} binaryReaderFn
  * @param {function(this:jspb.BinaryWriter,number,?)
  *        |function(this:jspb.BinaryWriter,number,?,?,?,?,?)} binaryWriterFn
  * @param {function(?,?)=} opt_binaryMessageSerializeFn
@@ -976,153 +976,186 @@ jspb.Message.getMapField = function(msg, fieldNumber, noLazyCreate,
 
 /**
  * Sets the value of a non-extension field.
- * @param {!jspb.Message} msg A jspb proto.
+ * @param {T} msg A jspb proto.
  * @param {number} fieldNumber The field number.
  * @param {string|number|boolean|Uint8Array|Array|undefined} value New value
+ * @return {T} return msg
+ * @template T
  * @protected
  */
 jspb.Message.setField = function(msg, fieldNumber, value) {
+  // TODO(b/35241823): replace this with a bounded generic when available
+  goog.asserts.assertInstanceof(msg, jspb.Message);
   if (fieldNumber < msg.pivot_) {
     msg.array[jspb.Message.getIndex_(msg, fieldNumber)] = value;
   } else {
     jspb.Message.maybeInitEmptyExtensionObject_(msg);
     msg.extensionObject_[fieldNumber] = value;
   }
+  return msg;
 };
 
 
 /**
  * Sets the value of a non-extension integer field of a proto3
- * @param {!jspb.Message} msg A jspb proto.
+ * @param {T} msg A jspb proto.
  * @param {number} fieldNumber The field number.
  * @param {number} value New value
+ * @return {T} return msg
+ * @template T
  * @protected
  */
 jspb.Message.setProto3IntField = function(msg, fieldNumber, value) {
-  jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, 0);
+  return jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, 0);
 };
 
 
 /**
  * Sets the value of a non-extension floating point field of a proto3
- * @param {!jspb.Message} msg A jspb proto.
+ * @param {T} msg A jspb proto.
  * @param {number} fieldNumber The field number.
  * @param {number} value New value
+ * @return {T} return msg
+ * @template T
  * @protected
  */
 jspb.Message.setProto3FloatField = function(msg, fieldNumber, value) {
-  jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, 0.0);
+  return jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, 0.0);
 };
 
 
 /**
  * Sets the value of a non-extension boolean field of a proto3
- * @param {!jspb.Message} msg A jspb proto.
+ * @param {T} msg A jspb proto.
  * @param {number} fieldNumber The field number.
  * @param {boolean} value New value
+ * @return {T} return msg
+ * @template T
  * @protected
  */
 jspb.Message.setProto3BooleanField = function(msg, fieldNumber, value) {
-  jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, false);
+  return jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, false);
 };
 
 
 /**
  * Sets the value of a non-extension String field of a proto3
- * @param {!jspb.Message} msg A jspb proto.
+ * @param {T} msg A jspb proto.
  * @param {number} fieldNumber The field number.
  * @param {string} value New value
+ * @return {T} return msg
+ * @template T
  * @protected
  */
 jspb.Message.setProto3StringField = function(msg, fieldNumber, value) {
-  jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, "");
+  return jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, '');
 };
 
 
 /**
  * Sets the value of a non-extension Bytes field of a proto3
- * @param {!jspb.Message} msg A jspb proto.
+ * @param {T} msg A jspb proto.
  * @param {number} fieldNumber The field number.
  * @param {!Uint8Array|string} value New value
+ * @return {T} return msg
+ * @template T
  * @protected
  */
 jspb.Message.setProto3BytesField = function(msg, fieldNumber, value) {
-  jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, "");
+  return jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, '');
 };
 
 
 /**
  * Sets the value of a non-extension enum field of a proto3
- * @param {!jspb.Message} msg A jspb proto.
+ * @param {T} msg A jspb proto.
  * @param {number} fieldNumber The field number.
  * @param {number} value New value
+ * @return {T} return msg
+ * @template T
  * @protected
  */
 jspb.Message.setProto3EnumField = function(msg, fieldNumber, value) {
-  jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, 0);
+  return jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, 0);
 };
 
 
 /**
  * Sets the value of a non-extension int field of a proto3 that has jstype set
  * to String.
- * @param {!jspb.Message} msg A jspb proto.
+ * @param {T} msg A jspb proto.
  * @param {number} fieldNumber The field number.
  * @param {string} value New value
+ * @return {T} return msg
+ * @template T
  * @protected
  */
 jspb.Message.setProto3StringIntField = function(msg, fieldNumber, value) {
-  jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, "0");
+  return jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, '0');
 };
 
 /**
  * Sets the value of a non-extension primitive field, with proto3 (non-nullable
  * primitives) semantics of ignoring values that are equal to the type's
  * default.
- * @param {!jspb.Message} msg A jspb proto.
+ * @param {T} msg A jspb proto.
  * @param {number} fieldNumber The field number.
  * @param {!Uint8Array|string|number|boolean|undefined} value New value
  * @param {!Uint8Array|string|number|boolean} defaultValue The default value.
+ * @return {T} return msg
+ * @template T
  * @private
  */
 jspb.Message.setFieldIgnoringDefault_ = function(
     msg, fieldNumber, value, defaultValue) {
+  // TODO(b/35241823): replace this with a bounded generic when available
+  goog.asserts.assertInstanceof(msg, jspb.Message);
   if (value !== defaultValue) {
     jspb.Message.setField(msg, fieldNumber, value);
   } else {
     msg.array[jspb.Message.getIndex_(msg, fieldNumber)] = null;
   }
+  return msg;
 };
 
 
 /**
  * Adds a value to a repeated, primitive field.
- * @param {!jspb.Message} msg A jspb proto.
+ * @param {T} msg A jspb proto.
  * @param {number} fieldNumber The field number.
  * @param {string|number|boolean|!Uint8Array} value New value
  * @param {number=} opt_index Index where to put new value.
+ * @return {T} return msg
+ * @template T
  * @protected
  */
 jspb.Message.addToRepeatedField = function(msg, fieldNumber, value, opt_index) {
+  // TODO(b/35241823): replace this with a bounded generic when available
+  goog.asserts.assertInstanceof(msg, jspb.Message);
   var arr = jspb.Message.getRepeatedField(msg, fieldNumber);
   if (opt_index != undefined) {
     arr.splice(opt_index, 0, value);
   } else {
     arr.push(value);
   }
+  return msg;
 };
 
 
 /**
  * Sets the value of a field in a oneof union and clears all other fields in
  * the union.
- * @param {!jspb.Message} msg A jspb proto.
+ * @param {T} msg A jspb proto.
  * @param {number} fieldNumber The field number.
  * @param {!Array<number>} oneof The fields belonging to the union.
  * @param {string|number|boolean|Uint8Array|Array|undefined} value New value
+ * @return {T} return msg
+ * @template T
  * @protected
  */
 jspb.Message.setOneofField = function(msg, fieldNumber, oneof, value) {
+  // TODO(b/35241823): replace this with a bounded generic when available
+  goog.asserts.assertInstanceof(msg, jspb.Message);
   var currentCase = jspb.Message.computeOneofCase(msg, oneof);
   if (currentCase && currentCase !== fieldNumber && value !== undefined) {
     if (msg.wrappers_ && currentCase in msg.wrappers_) {
@@ -1130,7 +1163,7 @@ jspb.Message.setOneofField = function(msg, fieldNumber, oneof, value) {
     }
     jspb.Message.setField(msg, currentCase, undefined);
   }
-  jspb.Message.setField(msg, fieldNumber, value);
+  return jspb.Message.setField(msg, fieldNumber, value);
 };
 
 
@@ -1244,48 +1277,61 @@ jspb.Message.wrapRepeatedField_ = function(msg, ctor, fieldNumber) {
 
 /**
  * Sets a proto field and syncs it to the backing array.
- * @param {!jspb.Message} msg A jspb proto.
+ * @param {T} msg A jspb proto.
  * @param {number} fieldNumber The field number.
  * @param {?jspb.Message|?jspb.Map|undefined} value A new value for this proto
  * field.
+ * @return {T} the msg
+ * @template T
  * @protected
  */
 jspb.Message.setWrapperField = function(msg, fieldNumber, value) {
+  // TODO(b/35241823): replace this with a bounded generic when available
+  goog.asserts.assertInstanceof(msg, jspb.Message);
   if (!msg.wrappers_) {
     msg.wrappers_ = {};
   }
   var data = value ? value.toArray() : value;
   msg.wrappers_[fieldNumber] = value;
-  jspb.Message.setField(msg, fieldNumber, data);
+  return jspb.Message.setField(msg, fieldNumber, data);
 };
 
 
+
 /**
  * Sets a proto field in a oneof union and syncs it to the backing array.
- * @param {!jspb.Message} msg A jspb proto.
+ * @param {T} msg A jspb proto.
  * @param {number} fieldNumber The field number.
  * @param {!Array<number>} oneof The fields belonging to the union.
  * @param {jspb.Message|undefined} value A new value for this proto field.
+ * @return {T} the msg
+ * @template T
  * @protected
  */
 jspb.Message.setOneofWrapperField = function(msg, fieldNumber, oneof, value) {
+  // TODO(b/35241823): replace this with a bounded generic when available
+  goog.asserts.assertInstanceof(msg, jspb.Message);
   if (!msg.wrappers_) {
     msg.wrappers_ = {};
   }
   var data = value ? value.toArray() : value;
   msg.wrappers_[fieldNumber] = value;
-  jspb.Message.setOneofField(msg, fieldNumber, oneof, data);
+  return jspb.Message.setOneofField(msg, fieldNumber, oneof, data);
 };
 
 
 /**
  * Sets a repeated proto field and syncs it to the backing array.
- * @param {!jspb.Message} msg A jspb proto.
+ * @param {T} msg A jspb proto.
  * @param {number} fieldNumber The field number.
  * @param {Array<!jspb.Message>|undefined} value An array of protos.
+ * @return {T} the msg
+ * @template T
  * @protected
  */
 jspb.Message.setRepeatedWrapperField = function(msg, fieldNumber, value) {
+  // TODO(b/35241823): replace this with a bounded generic when available
+  goog.asserts.assertInstanceof(msg, jspb.Message);
   if (!msg.wrappers_) {
     msg.wrappers_ = {};
   }
@@ -1294,7 +1340,7 @@ jspb.Message.setRepeatedWrapperField = function(msg, fieldNumber, value) {
     data[i] = value[i].toArray();
   }
   msg.wrappers_[fieldNumber] = value;
-  jspb.Message.setField(msg, fieldNumber, data);
+  return jspb.Message.setField(msg, fieldNumber, data);
 };
 
 

+ 1 - 0
js/message_test.js

@@ -118,6 +118,7 @@ goog.require('proto.jspb.test.TestReservedNamesExtension');
 goog.require('proto.jspb.test.ExtensionMessage');
 goog.require('proto.jspb.test.TestExtensionsMessage');
 
+goog.require('proto.jspb.test.TestAllowAliasEnum');
 
 describe('Message test suite', function() {
   var stubs = new goog.testing.PropertyReplacer();

+ 9 - 0
js/test.proto

@@ -28,6 +28,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+// LINT: LEGACY_NAMES
 // Author: mwr@google.com (Mark Rawling)
 
 syntax = "proto2";
@@ -311,3 +312,11 @@ message Deeply {
 }
 
 
+
+enum TestAllowAliasEnum {
+  option allow_alias = true;
+
+  TEST_ALLOW_ALIAS_DEFAULT = 0;
+  VALUE1 = 1;
+  value1 = 1;
+}

+ 18 - 1
kokoro/linux/bazel/build.sh

@@ -3,11 +3,28 @@
 # Build file to set up and run tests
 set -ex
 
+# Install the latest Bazel version available
+use_bazel.sh latest
+bazel version
+
+# Print bazel testlogs to stdout when tests failed.
+function print_test_logs {
+  # TODO(yannic): Only print logs of failing tests.
+  testlogs_dir=$(bazel info bazel-testlogs)
+  testlogs=$(find "${testlogs_dir}" -name "*.log")
+  for log in $testlogs; do
+    cat "${log}"
+  done
+}
+
 # Change to repo root
 cd $(dirname $0)/../../..
 
 git submodule update --init --recursive
-bazel test :protobuf_test --copt=-Werror --host_copt=-Werror
+
+trap print_test_logs EXIT
+bazel test :build_files_updated_unittest :protobuf_test --copt=-Werror --host_copt=-Werror
+trap - EXIT
 
 cd examples
 bazel build :all

+ 0 - 1
kokoro/release/python/linux/build_artifacts.sh

@@ -50,7 +50,6 @@ build_artifact_version() {
 }
 
 build_artifact_version 2.7
-build_artifact_version 3.4
 build_artifact_version 3.5
 build_artifact_version 3.6
 build_artifact_version 3.7

+ 0 - 1
kokoro/release/python/macos/build_artifacts.sh

@@ -51,7 +51,6 @@ build_artifact_version() {
 }
 
 build_artifact_version 2.7
-build_artifact_version 3.4
 build_artifact_version 3.5
 build_artifact_version 3.6
 build_artifact_version 3.7

+ 1 - 1
objectivec/google/protobuf/Duration.pbobjc.h

@@ -77,7 +77,7 @@ typedef GPB_ENUM(GPBDuration_FieldNumber) {
  *     if (duration.seconds < 0 && duration.nanos > 0) {
  *       duration.seconds += 1;
  *       duration.nanos -= 1000000000;
- *     } else if (durations.seconds > 0 && duration.nanos < 0) {
+ *     } else if (duration.seconds > 0 && duration.nanos < 0) {
  *       duration.seconds -= 1;
  *       duration.nanos += 1000000000;
  *     }

+ 26 - 2
protobuf_deps.bzl

@@ -5,7 +5,7 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
 def protobuf_deps():
     """Loads common dependencies needed to compile the protobuf library."""
 
-    if "zlib" not in native.existing_rules():
+    if not native.existing_rule("zlib"):
         http_archive(
             name = "zlib",
             build_file = "@com_google_protobuf//:third_party/zlib.BUILD",
@@ -14,10 +14,34 @@ def protobuf_deps():
             urls = ["https://zlib.net/zlib-1.2.11.tar.gz"],
         )
 
-    if "six" not in native.existing_rules():
+    if not native.existing_rule("six"):
         http_archive(
             name = "six",
             build_file = "@//:six.BUILD",
             sha256 = "105f8d68616f8248e24bf0e9372ef04d3cc10104f1980f54d57b2ce73a5ad56a",
             urls = ["https://pypi.python.org/packages/source/s/six/six-1.10.0.tar.gz#md5=34eed507548117b2ab523ab14b2f8b55"],
         )
+
+    if not native.existing_rule("rules_cc"):
+        http_archive(
+            name = "rules_cc",
+            sha256 = "29daf0159f0cf552fcff60b49d8bcd4f08f08506d2da6e41b07058ec50cfeaec",
+            strip_prefix = "rules_cc-b7fe9697c0c76ab2fd431a891dbb9a6a32ed7c3e",
+            urls = ["https://github.com/bazelbuild/rules_cc/archive/b7fe9697c0c76ab2fd431a891dbb9a6a32ed7c3e.tar.gz"],
+        )
+
+    if not native.existing_rule("rules_java"):
+        http_archive(
+            name = "rules_java",
+            sha256 = "f5a3e477e579231fca27bf202bb0e8fbe4fc6339d63b38ccb87c2760b533d1c3",
+            strip_prefix = "rules_java-981f06c3d2bd10225e85209904090eb7b5fb26bd",
+            urls = ["https://github.com/bazelbuild/rules_java/archive/981f06c3d2bd10225e85209904090eb7b5fb26bd.tar.gz"],
+        )
+
+    if not native.existing_rule("rules_proto"):
+        http_archive(
+            name = "rules_proto",
+            sha256 = "88b0a90433866b44bb4450d4c30bc5738b8c4f9c9ba14e9661deb123f56a833d",
+            strip_prefix = "rules_proto-b0cc14be5da05168b01db282fe93bdf17aa2b9f4",
+            urls = ["https://github.com/bazelbuild/rules_proto/archive/b0cc14be5da05168b01db282fe93bdf17aa2b9f4.tar.gz"],
+        )

+ 7 - 0
python/google/protobuf/internal/message_test.py

@@ -1998,6 +1998,13 @@ class Proto3Test(unittest.TestCase):
     m1.MergeFrom(m2)
     self.assertEqual(10, m2.map_int32_foreign_message[123].c)
 
+    # Test merge maps within different message types.
+    m1 = map_unittest_pb2.TestMap()
+    m2 = map_unittest_pb2.TestMessageMap()
+    m2.map_int32_message[123].optional_int32 = 10
+    m1.map_int32_all_types.MergeFrom(m2.map_int32_message)
+    self.assertEqual(10, m1.map_int32_all_types[123].optional_int32)
+
   def testMergeFromBadType(self):
     msg = map_unittest_pb2.TestMap()
     with self.assertRaisesRegexp(

+ 1 - 1
python/google/protobuf/internal/python_message.py

@@ -620,7 +620,7 @@ class _FieldProperty(property):
 def _AddPropertiesForRepeatedField(field, cls):
   """Adds a public property for a "repeated" protocol message field.  Clients
   can use this property to get the value of the field, which will be either a
-  _RepeatedScalarFieldContainer or _RepeatedCompositeFieldContainer (see
+  RepeatedScalarFieldContainer or RepeatedCompositeFieldContainer (see
   below).
 
   Note that when clients add values to these containers, we perform

+ 2 - 2
python/google/protobuf/internal/well_known_types.py

@@ -722,10 +722,10 @@ def _SetStructValue(struct_value, value):
     struct_value.string_value = value
   elif isinstance(value, _INT_OR_FLOAT):
     struct_value.number_value = value
-  elif isinstance(value, dict):
+  elif isinstance(value, (dict, Struct)):
     struct_value.struct_value.Clear()
     struct_value.struct_value.update(value)
-  elif isinstance(value, list):
+  elif isinstance(value, (list, ListValue)):
     struct_value.list_value.Clear()
     struct_value.list_value.extend(value)
   else:

+ 9 - 0
python/google/protobuf/internal/well_known_types_test.py

@@ -871,6 +871,15 @@ class StructTest(unittest.TestCase):
     self.assertEqual([6, True, False, None, inner_struct],
                      list(struct['key5'].items()))
 
+  def testStructAssignment(self):
+    # Tests struct assignment from another struct
+    s1 = struct_pb2.Struct()
+    s2 = struct_pb2.Struct()
+    for value in [1, 'a', [1], ['a'], {'a': 'b'}]:
+      s1['x'] = value
+      s2['x'] = s1['x']
+      self.assertEqual(s1['x'], s2['x'])
+
   def testMergeFrom(self):
     struct = struct_pb2.Struct()
     struct_class = struct.__class__

+ 2 - 3
python/google/protobuf/pyext/map_container.cc

@@ -343,9 +343,8 @@ PyObject* MapReflectionFriend::MergeFrom(PyObject* _self, PyObject* arg) {
   const Reflection* other_reflection = other_message->GetReflection();
   internal::MapFieldBase* field = reflection->MutableMapData(
       message, self->parent_field_descriptor);
-  const internal::MapFieldBase* other_field =
-      other_reflection->GetMapData(*other_message,
-                                   self->parent_field_descriptor);
+  const internal::MapFieldBase* other_field = other_reflection->GetMapData(
+      *other_message, other_map->parent_field_descriptor);
   field->MergeFrom(*other_field);
   self->version++;
   Py_RETURN_NONE;

+ 4 - 2
python/google/protobuf/pyext/message.cc

@@ -47,7 +47,6 @@
 #endif
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/logging.h>
-#include <google/protobuf/io/strtod.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
 #include <google/protobuf/descriptor.pb.h>
@@ -63,14 +62,17 @@
 #include <google/protobuf/pyext/message_factory.h>
 #include <google/protobuf/pyext/repeated_composite_container.h>
 #include <google/protobuf/pyext/repeated_scalar_container.h>
-#include <google/protobuf/pyext/unknown_fields.h>
 #include <google/protobuf/pyext/safe_numerics.h>
 #include <google/protobuf/pyext/scoped_pyobject_ptr.h>
+#include <google/protobuf/pyext/unknown_fields.h>
 #include <google/protobuf/util/message_differencer.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/io/strtod.h>
 #include <google/protobuf/stubs/map_util.h>
 
+// clang-format off
 #include <google/protobuf/port_def.inc>
+// clang-format on
 
 #if PY_MAJOR_VERSION >= 3
   #define PyInt_AsLong PyLong_AsLong

+ 8 - 0
ruby/ext/google/protobuf_c/map.c

@@ -71,6 +71,9 @@ static VALUE table_key(Map* self, VALUE key,
     case UPB_TYPE_BYTES:
     case UPB_TYPE_STRING:
       // Strings: use string content directly.
+      if (TYPE(key) == T_SYMBOL) {
+        key = rb_id2str(SYM2ID(key));
+      }
       Check_Type(key, T_STRING);
       key = native_slot_encode_and_freeze_string(self->key_type, key);
       *out_key = RSTRING_PTR(key);
@@ -397,6 +400,11 @@ VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) {
   void* mem;
   key = table_key(self, key, keybuf, &keyval, &length);
 
+  if (TYPE(value) == T_HASH) {
+    VALUE args[1] = { value };
+    value = rb_class_new_instance(1, args, self->value_type_class);
+  }
+
   mem = value_memory(&v);
   native_slot_set("", self->value_type, self->value_type_class, mem, value);
 

+ 2 - 2
ruby/ext/google/protobuf_c/message.c

@@ -192,7 +192,7 @@ static int extract_method_call(VALUE method_name, MessageHeader* self,
     // Find the field name
     char wrapper_field_name[name_len - 8];
     strncpy(wrapper_field_name, name, name_len - 9);
-    wrapper_field_name[name_len - 7] = '\0';
+    wrapper_field_name[name_len - 9] = '\0';
 
     // Check if field exists and is a wrapper type
     const upb_oneofdef* test_o_wrapper;
@@ -220,7 +220,7 @@ static int extract_method_call(VALUE method_name, MessageHeader* self,
     // Find enum field name
     char enum_name[name_len - 5];
     strncpy(enum_name, name, name_len - 6);
-    enum_name[name_len - 4] = '\0';
+    enum_name[name_len - 6] = '\0';
 
     // Check if enum field exists
     const upb_oneofdef* test_o_enum;

+ 14 - 0
ruby/tests/basic.rb

@@ -204,6 +204,20 @@ module BasicTest
       end
     end
 
+    def test_map_field_with_symbol
+      m = MapMessage.new
+      assert m.map_string_int32 == {}
+      assert m.map_string_msg == {}
+
+      m = MapMessage.new(
+        :map_string_int32 => {a: 1, "b" => 2},
+        :map_string_msg => {a: TestMessage2.new(:foo => 1),
+                            b: TestMessage2.new(:foo => 10)})
+      assert_equal 1, m.map_string_int32[:a]
+      assert_equal 2, m.map_string_int32[:b]
+      assert_equal 10, m.map_string_msg[:b].foo
+    end
+
     def test_map_inspect
       m = MapMessage.new(
         :map_string_int32 => {"a" => 1, "b" => 2},

+ 54 - 0
ruby/tests/well_known_types_test.rb

@@ -139,4 +139,58 @@ class TestWellKnownTypes < Test::Unit::TestCase
     assert any.is(Google::Protobuf::Timestamp)
     assert_equal ts, any.unpack(Google::Protobuf::Timestamp)
   end
+
+  def test_struct_init
+    s = Google::Protobuf::Struct.new(fields: {'a' => Google::Protobuf::Value.new({number_value: 4.4})})
+    assert_equal 4.4, s['a']
+
+    s = Google::Protobuf::Struct.new(fields: {'a' => {number_value: 2.2}})
+    assert_equal 2.2, s['a']
+
+    s = Google::Protobuf::Struct.new(fields: {a: {number_value: 1.1}})
+    assert_equal 1.1, s[:a]
+  end
+
+  def test_struct_nested_init
+    s = Google::Protobuf::Struct.new(
+      fields: {
+        'a' => {string_value: 'A'},
+        'b' => {struct_value: {
+          fields: {
+            'x' => {list_value: {values: [{number_value: 1.0}, {string_value: "ok"}]}},
+            'y' => {bool_value: true}}}
+        },
+        'c' => {struct_value: {}}
+      }
+    )
+    assert_equal 'A', s['a']
+    assert_equal 'A', s[:a]
+    expected_b_x = [Google::Protobuf::Value.new(number_value: 1.0), Google::Protobuf::Value.new(string_value: "ok")]
+    assert_equal expected_b_x, s['b']['x'].values
+    assert_equal expected_b_x, s[:b][:x].values
+    assert_equal expected_b_x, s['b'][:x].values
+    assert_equal expected_b_x, s[:b]['x'].values
+    assert_equal true, s['b']['y']
+    assert_equal true, s[:b][:y]
+    assert_equal true, s[:b]['y']
+    assert_equal true, s['b'][:y]
+    assert_equal Google::Protobuf::Struct.new, s['c']
+    assert_equal Google::Protobuf::Struct.new, s[:c]
+
+    s = Google::Protobuf::Struct.new(
+      fields: {
+        a: {string_value: 'Eh'},
+        b: {struct_value: {
+          fields: {
+            y: {bool_value: false}}}
+        }
+      }
+    )
+    assert_equal 'Eh', s['a']
+    assert_equal 'Eh', s[:a]
+    assert_equal false, s['b']['y']
+    assert_equal false, s[:b][:y]
+    assert_equal false, s['b'][:y]
+    assert_equal false, s[:b]['y']
+  end
 end

+ 5 - 3
src/Makefile.am

@@ -105,6 +105,7 @@ nobase_include_HEADERS =                                         \
   google/protobuf/has_bits.h                                     \
   google/protobuf/implicit_weak_message.h                        \
   google/protobuf/inlined_string_field.h                         \
+  google/protobuf/io/io_win32.h                                \
   google/protobuf/map_entry.h                                    \
   google/protobuf/map_entry_lite.h                               \
   google/protobuf/map_field.h                                    \
@@ -184,7 +185,6 @@ libprotobuf_lite_la_SOURCES =                                  \
   google/protobuf/stubs/int128.cc                              \
   google/protobuf/stubs/int128.h                               \
   google/protobuf/io/io_win32.cc                               \
-  google/protobuf/io/io_win32.h                                \
   google/protobuf/stubs/map_util.h                             \
   google/protobuf/stubs/mathutil.h                             \
   google/protobuf/stubs/status.cc                              \
@@ -213,7 +213,6 @@ libprotobuf_lite_la_SOURCES =                                  \
   google/protobuf/repeated_field.cc                            \
   google/protobuf/wire_format_lite.cc                          \
   google/protobuf/io/coded_stream.cc                           \
-  google/protobuf/io/coded_stream_inl.h                        \
   google/protobuf/io/strtod.cc                                 \
   google/protobuf/io/zero_copy_stream.cc                       \
   google/protobuf/io/zero_copy_stream_impl.cc                  \
@@ -728,6 +727,9 @@ protobuf_test_CPPFLAGS = -I$(GOOGLETEST_SRC_DIR)/include \
 # since test_util.cc takes forever to compile with optimization (with GCC).
 # See configure.ac for more info.
 protobuf_test_CXXFLAGS = $(NO_OPT_CXXFLAGS)
+# Doesn't pass on Windows with MSVC
+NON_MSVC_TEST_SOURCES =                                        \
+  google/protobuf/compiler/command_line_interface_unittest.cc
 protobuf_test_SOURCES =                                        \
   google/protobuf/stubs/bytestream_unittest.cc                 \
   google/protobuf/stubs/common_unittest.cc                     \
@@ -773,7 +775,6 @@ protobuf_test_SOURCES =                                        \
   google/protobuf/io/zero_copy_stream_unittest.cc              \
   google/protobuf/compiler/annotation_test_util.h              \
   google/protobuf/compiler/annotation_test_util.cc             \
-  google/protobuf/compiler/command_line_interface_unittest.cc  \
   google/protobuf/compiler/importer_unittest.cc                \
   google/protobuf/compiler/mock_code_generator.cc              \
   google/protobuf/compiler/mock_code_generator.h               \
@@ -805,6 +806,7 @@ protobuf_test_SOURCES =                                        \
   google/protobuf/util/message_differencer_unittest.cc         \
   google/protobuf/util/time_util_test.cc                       \
   google/protobuf/util/type_resolver_util_test.cc              \
+  $(NON_MSVC_TEST_SOURCES)                                     \
   $(COMMON_TEST_SOURCES)
 nodist_protobuf_test_SOURCES = $(protoc_outputs)
 $(am_protobuf_test_OBJECTS): unittest_proto_middleman

+ 13 - 13
src/google/protobuf/any.pb.cc

@@ -32,7 +32,7 @@ static void InitDefaultsscc_info_Any_google_2fprotobuf_2fany_2eproto() {
 }
 
 PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::internal::SCCInfo<0> scc_info_Any_google_2fprotobuf_2fany_2eproto =
-    {{ATOMIC_VAR_INIT(::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase::kUninitialized), 0, InitDefaultsscc_info_Any_google_2fprotobuf_2fany_2eproto}, {}};
+    {{ATOMIC_VAR_INIT(::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase::kUninitialized), 0, 0, InitDefaultsscc_info_Any_google_2fprotobuf_2fany_2eproto}, {}};
 
 static ::PROTOBUF_NAMESPACE_ID::Metadata file_level_metadata_google_2fprotobuf_2fany_2eproto[1];
 static constexpr ::PROTOBUF_NAMESPACE_ID::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fany_2eproto = nullptr;
@@ -125,11 +125,11 @@ Any::Any(const Any& from)
       _any_metadata_(&type_url_, &value_) {
   _internal_metadata_.MergeFrom(from._internal_metadata_);
   type_url_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
-  if (!from.type_url().empty()) {
+  if (!from._internal_type_url().empty()) {
     type_url_.AssignWithDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from.type_url_);
   }
   value_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
-  if (!from.value().empty()) {
+  if (!from._internal_value().empty()) {
     value_.AssignWithDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from.value_);
   }
   // @@protoc_insertion_point(copy_constructor:google.protobuf.Any)
@@ -182,14 +182,14 @@ const char* Any::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::intern
       // string type_url = 1;
       case 1:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 10)) {
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8(mutable_type_url(), ptr, ctx, "google.protobuf.Any.type_url");
+          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8(_internal_mutable_type_url(), ptr, ctx, "google.protobuf.Any.type_url");
           CHK_(ptr);
         } else goto handle_unusual;
         continue;
       // bytes value = 2;
       case 2:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 18)) {
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(mutable_value(), ptr, ctx);
+          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(_internal_mutable_value(), ptr, ctx);
           CHK_(ptr);
         } else goto handle_unusual;
         continue;
@@ -227,9 +227,9 @@ bool Any::MergePartialFromCodedStream(
       case 1: {
         if (static_cast< ::PROTOBUF_NAMESPACE_ID::uint8>(tag) == (10 & 0xFF)) {
           DO_(::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::ReadString(
-                input, this->mutable_type_url()));
+                input, this->_internal_mutable_type_url()));
           DO_(::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-            this->type_url().data(), static_cast<int>(this->type_url().length()),
+            this->_internal_type_url().data(), static_cast<int>(this->_internal_type_url().length()),
             ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::PARSE,
             "google.protobuf.Any.type_url"));
         } else {
@@ -242,7 +242,7 @@ bool Any::MergePartialFromCodedStream(
       case 2: {
         if (static_cast< ::PROTOBUF_NAMESPACE_ID::uint8>(tag) == (18 & 0xFF)) {
           DO_(::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::ReadBytes(
-                input, this->mutable_value()));
+                input, this->_internal_mutable_value()));
         } else {
           goto handle_unusual;
         }
@@ -279,17 +279,17 @@ failure:
   // string type_url = 1;
   if (this->type_url().size() > 0) {
     ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->type_url().data(), static_cast<int>(this->type_url().length()),
+      this->_internal_type_url().data(), static_cast<int>(this->_internal_type_url().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
       "google.protobuf.Any.type_url");
     target = stream->WriteStringMaybeAliased(
-        1, this->type_url(), target);
+        1, this->_internal_type_url(), target);
   }
 
   // bytes value = 2;
   if (this->value().size() > 0) {
     target = stream->WriteBytesMaybeAliased(
-        2, this->value(), target);
+        2, this->_internal_value(), target);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
@@ -312,14 +312,14 @@ size_t Any::ByteSizeLong() const {
   if (this->type_url().size() > 0) {
     total_size += 1 +
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
-        this->type_url());
+        this->_internal_type_url());
   }
 
   // bytes value = 2;
   if (this->value().size() > 0) {
     total_size += 1 +
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::BytesSize(
-        this->value());
+        this->_internal_value());
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {

+ 36 - 8
src/google/protobuf/any.pb.h

@@ -206,6 +206,11 @@ class PROTOBUF_EXPORT Any :
   std::string* mutable_type_url();
   std::string* release_type_url();
   void set_allocated_type_url(std::string* type_url);
+  private:
+  const std::string& _internal_type_url() const;
+  void _internal_set_type_url(const std::string& value);
+  std::string* _internal_mutable_type_url();
+  public:
 
   // bytes value = 2;
   void clear_value();
@@ -217,6 +222,11 @@ class PROTOBUF_EXPORT Any :
   std::string* mutable_value();
   std::string* release_value();
   void set_allocated_value(std::string* value);
+  private:
+  const std::string& _internal_value() const;
+  void _internal_set_value(const std::string& value);
+  std::string* _internal_mutable_value();
+  public:
 
   // @@protoc_insertion_point(class_scope:google.protobuf.Any)
  private:
@@ -246,12 +256,22 @@ inline void Any::clear_type_url() {
 }
 inline const std::string& Any::type_url() const {
   // @@protoc_insertion_point(field_get:google.protobuf.Any.type_url)
-  return type_url_.GetNoArena();
+  return _internal_type_url();
 }
 inline void Any::set_type_url(const std::string& value) {
+  _internal_set_type_url(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Any.type_url)
+}
+inline std::string* Any::mutable_type_url() {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Any.type_url)
+  return _internal_mutable_type_url();
+}
+inline const std::string& Any::_internal_type_url() const {
+  return type_url_.GetNoArena();
+}
+inline void Any::_internal_set_type_url(const std::string& value) {
   
   type_url_.SetNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value);
-  // @@protoc_insertion_point(field_set:google.protobuf.Any.type_url)
 }
 inline void Any::set_type_url(std::string&& value) {
   
@@ -271,9 +291,8 @@ inline void Any::set_type_url(const char* value, size_t size) {
       ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.Any.type_url)
 }
-inline std::string* Any::mutable_type_url() {
+inline std::string* Any::_internal_mutable_type_url() {
   
-  // @@protoc_insertion_point(field_mutable:google.protobuf.Any.type_url)
   return type_url_.MutableNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 inline std::string* Any::release_type_url() {
@@ -297,12 +316,22 @@ inline void Any::clear_value() {
 }
 inline const std::string& Any::value() const {
   // @@protoc_insertion_point(field_get:google.protobuf.Any.value)
-  return value_.GetNoArena();
+  return _internal_value();
 }
 inline void Any::set_value(const std::string& value) {
+  _internal_set_value(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Any.value)
+}
+inline std::string* Any::mutable_value() {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Any.value)
+  return _internal_mutable_value();
+}
+inline const std::string& Any::_internal_value() const {
+  return value_.GetNoArena();
+}
+inline void Any::_internal_set_value(const std::string& value) {
   
   value_.SetNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value);
-  // @@protoc_insertion_point(field_set:google.protobuf.Any.value)
 }
 inline void Any::set_value(std::string&& value) {
   
@@ -322,9 +351,8 @@ inline void Any::set_value(const void* value, size_t size) {
       ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.Any.value)
 }
-inline std::string* Any::mutable_value() {
+inline std::string* Any::_internal_mutable_value() {
   
-  // @@protoc_insertion_point(field_mutable:google.protobuf.Any.value)
   return value_.MutableNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 inline std::string* Any::release_value() {

+ 0 - 1
src/google/protobuf/any_lite.cc

@@ -35,7 +35,6 @@
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/stubs/strutil.h>
 
-
 namespace google {
 namespace protobuf {
 namespace internal {

+ 0 - 1
src/google/protobuf/any_test.cc

@@ -33,7 +33,6 @@
 #include <gtest/gtest.h>
 
 
-
 namespace google {
 namespace protobuf {
 namespace {

+ 84 - 100
src/google/protobuf/api.pb.cc

@@ -44,7 +44,7 @@ static void InitDefaultsscc_info_Api_google_2fprotobuf_2fapi_2eproto() {
 }
 
 PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::internal::SCCInfo<4> scc_info_Api_google_2fprotobuf_2fapi_2eproto =
-    {{ATOMIC_VAR_INIT(::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase::kUninitialized), 4, InitDefaultsscc_info_Api_google_2fprotobuf_2fapi_2eproto}, {
+    {{ATOMIC_VAR_INIT(::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase::kUninitialized), 4, 0, InitDefaultsscc_info_Api_google_2fprotobuf_2fapi_2eproto}, {
       &scc_info_Method_google_2fprotobuf_2fapi_2eproto.base,
       &scc_info_Option_google_2fprotobuf_2ftype_2eproto.base,
       &scc_info_SourceContext_google_2fprotobuf_2fsource_5fcontext_2eproto.base,
@@ -62,7 +62,7 @@ static void InitDefaultsscc_info_Method_google_2fprotobuf_2fapi_2eproto() {
 }
 
 PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::internal::SCCInfo<1> scc_info_Method_google_2fprotobuf_2fapi_2eproto =
-    {{ATOMIC_VAR_INIT(::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase::kUninitialized), 1, InitDefaultsscc_info_Method_google_2fprotobuf_2fapi_2eproto}, {
+    {{ATOMIC_VAR_INIT(::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase::kUninitialized), 1, 0, InitDefaultsscc_info_Method_google_2fprotobuf_2fapi_2eproto}, {
       &scc_info_Option_google_2fprotobuf_2ftype_2eproto.base,}};
 
 static void InitDefaultsscc_info_Mixin_google_2fprotobuf_2fapi_2eproto() {
@@ -77,7 +77,7 @@ static void InitDefaultsscc_info_Mixin_google_2fprotobuf_2fapi_2eproto() {
 }
 
 PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::internal::SCCInfo<0> scc_info_Mixin_google_2fprotobuf_2fapi_2eproto =
-    {{ATOMIC_VAR_INIT(::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase::kUninitialized), 0, InitDefaultsscc_info_Mixin_google_2fprotobuf_2fapi_2eproto}, {}};
+    {{ATOMIC_VAR_INIT(::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase::kUninitialized), 0, 0, InitDefaultsscc_info_Mixin_google_2fprotobuf_2fapi_2eproto}, {}};
 
 static ::PROTOBUF_NAMESPACE_ID::Metadata file_level_metadata_google_2fprotobuf_2fapi_2eproto[3];
 static constexpr ::PROTOBUF_NAMESPACE_ID::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fapi_2eproto = nullptr;
@@ -208,11 +208,11 @@ Api::Api(const Api& from)
       mixins_(from.mixins_) {
   _internal_metadata_.MergeFrom(from._internal_metadata_);
   name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
-  if (!from.name().empty()) {
+  if (!from._internal_name().empty()) {
     name_.AssignWithDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from.name_);
   }
   version_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
-  if (!from.version().empty()) {
+  if (!from._internal_version().empty()) {
     version_.AssignWithDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from.version_);
   }
   if (from.has_source_context()) {
@@ -283,7 +283,7 @@ const char* Api::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::intern
       // string name = 1;
       case 1:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 10)) {
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8(mutable_name(), ptr, ctx, "google.protobuf.Api.name");
+          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8(_internal_mutable_name(), ptr, ctx, "google.protobuf.Api.name");
           CHK_(ptr);
         } else goto handle_unusual;
         continue;
@@ -296,7 +296,7 @@ const char* Api::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::intern
             ptr = ctx->ParseMessage(add_methods(), ptr);
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
-          } while (::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad<::PROTOBUF_NAMESPACE_ID::uint8>(ptr) == 18);
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<18>(ptr));
         } else goto handle_unusual;
         continue;
       // repeated .google.protobuf.Option options = 3;
@@ -308,13 +308,13 @@ const char* Api::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::intern
             ptr = ctx->ParseMessage(add_options(), ptr);
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
-          } while (::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad<::PROTOBUF_NAMESPACE_ID::uint8>(ptr) == 26);
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<26>(ptr));
         } else goto handle_unusual;
         continue;
       // string version = 4;
       case 4:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 34)) {
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8(mutable_version(), ptr, ctx, "google.protobuf.Api.version");
+          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8(_internal_mutable_version(), ptr, ctx, "google.protobuf.Api.version");
           CHK_(ptr);
         } else goto handle_unusual;
         continue;
@@ -334,7 +334,7 @@ const char* Api::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::intern
             ptr = ctx->ParseMessage(add_mixins(), ptr);
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
-          } while (::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad<::PROTOBUF_NAMESPACE_ID::uint8>(ptr) == 50);
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<50>(ptr));
         } else goto handle_unusual;
         continue;
       // .google.protobuf.Syntax syntax = 7;
@@ -379,9 +379,9 @@ bool Api::MergePartialFromCodedStream(
       case 1: {
         if (static_cast< ::PROTOBUF_NAMESPACE_ID::uint8>(tag) == (10 & 0xFF)) {
           DO_(::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::ReadString(
-                input, this->mutable_name()));
+                input, this->_internal_mutable_name()));
           DO_(::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-            this->name().data(), static_cast<int>(this->name().length()),
+            this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
             ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::PARSE,
             "google.protobuf.Api.name"));
         } else {
@@ -416,9 +416,9 @@ bool Api::MergePartialFromCodedStream(
       case 4: {
         if (static_cast< ::PROTOBUF_NAMESPACE_ID::uint8>(tag) == (34 & 0xFF)) {
           DO_(::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::ReadString(
-                input, this->mutable_version()));
+                input, this->_internal_mutable_version()));
           DO_(::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-            this->version().data(), static_cast<int>(this->version().length()),
+            this->_internal_version().data(), static_cast<int>(this->_internal_version().length()),
             ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::PARSE,
             "google.protobuf.Api.version"));
         } else {
@@ -493,24 +493,24 @@ failure:
   // string name = 1;
   if (this->name().size() > 0) {
     ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->name().data(), static_cast<int>(this->name().length()),
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
       "google.protobuf.Api.name");
     target = stream->WriteStringMaybeAliased(
-        1, this->name(), target);
+        1, this->_internal_name(), target);
   }
 
   // repeated .google.protobuf.Method methods = 2;
-  for (auto it = this->methods().pointer_begin(),
-            end = this->methods().pointer_end(); it < end; ++it) {
+  for (auto it = this->methods_.pointer_begin(),
+            end = this->methods_.pointer_end(); it < end; ++it) {
     stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
       InternalWriteMessageToArray(2, **it, target, stream);
   }
 
   // repeated .google.protobuf.Option options = 3;
-  for (auto it = this->options().pointer_begin(),
-            end = this->options().pointer_end(); it < end; ++it) {
+  for (auto it = this->options_.pointer_begin(),
+            end = this->options_.pointer_end(); it < end; ++it) {
     stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
       InternalWriteMessageToArray(3, **it, target, stream);
@@ -519,11 +519,11 @@ failure:
   // string version = 4;
   if (this->version().size() > 0) {
     ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->version().data(), static_cast<int>(this->version().length()),
+      this->_internal_version().data(), static_cast<int>(this->_internal_version().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
       "google.protobuf.Api.version");
     target = stream->WriteStringMaybeAliased(
-        4, this->version(), target);
+        4, this->_internal_version(), target);
   }
 
   // .google.protobuf.SourceContext source_context = 5;
@@ -535,8 +535,8 @@ failure:
   }
 
   // repeated .google.protobuf.Mixin mixins = 6;
-  for (auto it = this->mixins().pointer_begin(),
-            end = this->mixins().pointer_end(); it < end; ++it) {
+  for (auto it = this->mixins_.pointer_begin(),
+            end = this->mixins_.pointer_end(); it < end; ++it) {
     stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
       InternalWriteMessageToArray(6, **it, target, stream);
@@ -566,50 +566,38 @@ size_t Api::ByteSizeLong() const {
   (void) cached_has_bits;
 
   // repeated .google.protobuf.Method methods = 2;
-  {
-    unsigned int count = static_cast<unsigned int>(this->methods_size());
-    total_size += 1UL * count;
-    for (unsigned int i = 0; i < count; i++) {
-      total_size +=
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
-          this->methods(static_cast<int>(i)));
-    }
+  total_size += 1UL * this->methods_size();
+  for (const auto& msg : this->methods_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
   }
 
   // repeated .google.protobuf.Option options = 3;
-  {
-    unsigned int count = static_cast<unsigned int>(this->options_size());
-    total_size += 1UL * count;
-    for (unsigned int i = 0; i < count; i++) {
-      total_size +=
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
-          this->options(static_cast<int>(i)));
-    }
+  total_size += 1UL * this->options_size();
+  for (const auto& msg : this->options_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
   }
 
   // repeated .google.protobuf.Mixin mixins = 6;
-  {
-    unsigned int count = static_cast<unsigned int>(this->mixins_size());
-    total_size += 1UL * count;
-    for (unsigned int i = 0; i < count; i++) {
-      total_size +=
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
-          this->mixins(static_cast<int>(i)));
-    }
+  total_size += 1UL * this->mixins_size();
+  for (const auto& msg : this->mixins_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
   }
 
   // string name = 1;
   if (this->name().size() > 0) {
     total_size += 1 +
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
-        this->name());
+        this->_internal_name());
   }
 
   // string version = 4;
   if (this->version().size() > 0) {
     total_size += 1 +
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
-        this->version());
+        this->_internal_version());
   }
 
   // .google.protobuf.SourceContext source_context = 5;
@@ -696,9 +684,9 @@ bool Api::IsInitialized() const {
 void Api::InternalSwap(Api* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);
-  CastToBase(&methods_)->InternalSwap(CastToBase(&other->methods_));
-  CastToBase(&options_)->InternalSwap(CastToBase(&other->options_));
-  CastToBase(&mixins_)->InternalSwap(CastToBase(&other->mixins_));
+  methods_.InternalSwap(&other->methods_);
+  options_.InternalSwap(&other->options_);
+  mixins_.InternalSwap(&other->mixins_);
   name_.Swap(&other->name_, &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
     GetArenaNoVirtual());
   version_.Swap(&other->version_, &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
@@ -734,15 +722,15 @@ Method::Method(const Method& from)
       options_(from.options_) {
   _internal_metadata_.MergeFrom(from._internal_metadata_);
   name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
-  if (!from.name().empty()) {
+  if (!from._internal_name().empty()) {
     name_.AssignWithDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from.name_);
   }
   request_type_url_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
-  if (!from.request_type_url().empty()) {
+  if (!from._internal_request_type_url().empty()) {
     request_type_url_.AssignWithDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from.request_type_url_);
   }
   response_type_url_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
-  if (!from.response_type_url().empty()) {
+  if (!from._internal_response_type_url().empty()) {
     response_type_url_.AssignWithDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from.response_type_url_);
   }
   ::memcpy(&request_streaming_, &from.request_streaming_,
@@ -808,14 +796,14 @@ const char* Method::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::int
       // string name = 1;
       case 1:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 10)) {
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8(mutable_name(), ptr, ctx, "google.protobuf.Method.name");
+          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8(_internal_mutable_name(), ptr, ctx, "google.protobuf.Method.name");
           CHK_(ptr);
         } else goto handle_unusual;
         continue;
       // string request_type_url = 2;
       case 2:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 18)) {
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8(mutable_request_type_url(), ptr, ctx, "google.protobuf.Method.request_type_url");
+          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8(_internal_mutable_request_type_url(), ptr, ctx, "google.protobuf.Method.request_type_url");
           CHK_(ptr);
         } else goto handle_unusual;
         continue;
@@ -829,7 +817,7 @@ const char* Method::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::int
       // string response_type_url = 4;
       case 4:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 34)) {
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8(mutable_response_type_url(), ptr, ctx, "google.protobuf.Method.response_type_url");
+          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8(_internal_mutable_response_type_url(), ptr, ctx, "google.protobuf.Method.response_type_url");
           CHK_(ptr);
         } else goto handle_unusual;
         continue;
@@ -849,7 +837,7 @@ const char* Method::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::int
             ptr = ctx->ParseMessage(add_options(), ptr);
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
-          } while (::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad<::PROTOBUF_NAMESPACE_ID::uint8>(ptr) == 50);
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<50>(ptr));
         } else goto handle_unusual;
         continue;
       // .google.protobuf.Syntax syntax = 7;
@@ -894,9 +882,9 @@ bool Method::MergePartialFromCodedStream(
       case 1: {
         if (static_cast< ::PROTOBUF_NAMESPACE_ID::uint8>(tag) == (10 & 0xFF)) {
           DO_(::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::ReadString(
-                input, this->mutable_name()));
+                input, this->_internal_mutable_name()));
           DO_(::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-            this->name().data(), static_cast<int>(this->name().length()),
+            this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
             ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::PARSE,
             "google.protobuf.Method.name"));
         } else {
@@ -909,9 +897,9 @@ bool Method::MergePartialFromCodedStream(
       case 2: {
         if (static_cast< ::PROTOBUF_NAMESPACE_ID::uint8>(tag) == (18 & 0xFF)) {
           DO_(::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::ReadString(
-                input, this->mutable_request_type_url()));
+                input, this->_internal_mutable_request_type_url()));
           DO_(::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-            this->request_type_url().data(), static_cast<int>(this->request_type_url().length()),
+            this->_internal_request_type_url().data(), static_cast<int>(this->_internal_request_type_url().length()),
             ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::PARSE,
             "google.protobuf.Method.request_type_url"));
         } else {
@@ -937,9 +925,9 @@ bool Method::MergePartialFromCodedStream(
       case 4: {
         if (static_cast< ::PROTOBUF_NAMESPACE_ID::uint8>(tag) == (34 & 0xFF)) {
           DO_(::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::ReadString(
-                input, this->mutable_response_type_url()));
+                input, this->_internal_mutable_response_type_url()));
           DO_(::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-            this->response_type_url().data(), static_cast<int>(this->response_type_url().length()),
+            this->_internal_response_type_url().data(), static_cast<int>(this->_internal_response_type_url().length()),
             ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::PARSE,
             "google.protobuf.Method.response_type_url"));
         } else {
@@ -1016,21 +1004,21 @@ failure:
   // string name = 1;
   if (this->name().size() > 0) {
     ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->name().data(), static_cast<int>(this->name().length()),
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
       "google.protobuf.Method.name");
     target = stream->WriteStringMaybeAliased(
-        1, this->name(), target);
+        1, this->_internal_name(), target);
   }
 
   // string request_type_url = 2;
   if (this->request_type_url().size() > 0) {
     ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->request_type_url().data(), static_cast<int>(this->request_type_url().length()),
+      this->_internal_request_type_url().data(), static_cast<int>(this->_internal_request_type_url().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
       "google.protobuf.Method.request_type_url");
     target = stream->WriteStringMaybeAliased(
-        2, this->request_type_url(), target);
+        2, this->_internal_request_type_url(), target);
   }
 
   // bool request_streaming = 3;
@@ -1042,11 +1030,11 @@ failure:
   // string response_type_url = 4;
   if (this->response_type_url().size() > 0) {
     ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->response_type_url().data(), static_cast<int>(this->response_type_url().length()),
+      this->_internal_response_type_url().data(), static_cast<int>(this->_internal_response_type_url().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
       "google.protobuf.Method.response_type_url");
     target = stream->WriteStringMaybeAliased(
-        4, this->response_type_url(), target);
+        4, this->_internal_response_type_url(), target);
   }
 
   // bool response_streaming = 5;
@@ -1056,8 +1044,8 @@ failure:
   }
 
   // repeated .google.protobuf.Option options = 6;
-  for (auto it = this->options().pointer_begin(),
-            end = this->options().pointer_end(); it < end; ++it) {
+  for (auto it = this->options_.pointer_begin(),
+            end = this->options_.pointer_end(); it < end; ++it) {
     stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
       InternalWriteMessageToArray(6, **it, target, stream);
@@ -1087,35 +1075,31 @@ size_t Method::ByteSizeLong() const {
   (void) cached_has_bits;
 
   // repeated .google.protobuf.Option options = 6;
-  {
-    unsigned int count = static_cast<unsigned int>(this->options_size());
-    total_size += 1UL * count;
-    for (unsigned int i = 0; i < count; i++) {
-      total_size +=
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
-          this->options(static_cast<int>(i)));
-    }
+  total_size += 1UL * this->options_size();
+  for (const auto& msg : this->options_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
   }
 
   // string name = 1;
   if (this->name().size() > 0) {
     total_size += 1 +
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
-        this->name());
+        this->_internal_name());
   }
 
   // string request_type_url = 2;
   if (this->request_type_url().size() > 0) {
     total_size += 1 +
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
-        this->request_type_url());
+        this->_internal_request_type_url());
   }
 
   // string response_type_url = 4;
   if (this->response_type_url().size() > 0) {
     total_size += 1 +
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
-        this->response_type_url());
+        this->_internal_response_type_url());
   }
 
   // bool request_streaming = 3;
@@ -1210,7 +1194,7 @@ bool Method::IsInitialized() const {
 void Method::InternalSwap(Method* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);
-  CastToBase(&options_)->InternalSwap(CastToBase(&other->options_));
+  options_.InternalSwap(&other->options_);
   name_.Swap(&other->name_, &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
     GetArenaNoVirtual());
   request_type_url_.Swap(&other->request_type_url_, &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
@@ -1245,11 +1229,11 @@ Mixin::Mixin(const Mixin& from)
       _internal_metadata_(nullptr) {
   _internal_metadata_.MergeFrom(from._internal_metadata_);
   name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
-  if (!from.name().empty()) {
+  if (!from._internal_name().empty()) {
     name_.AssignWithDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from.name_);
   }
   root_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
-  if (!from.root().empty()) {
+  if (!from._internal_root().empty()) {
     root_.AssignWithDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from.root_);
   }
   // @@protoc_insertion_point(copy_constructor:google.protobuf.Mixin)
@@ -1302,14 +1286,14 @@ const char* Mixin::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::inte
       // string name = 1;
       case 1:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 10)) {
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8(mutable_name(), ptr, ctx, "google.protobuf.Mixin.name");
+          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8(_internal_mutable_name(), ptr, ctx, "google.protobuf.Mixin.name");
           CHK_(ptr);
         } else goto handle_unusual;
         continue;
       // string root = 2;
       case 2:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 18)) {
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8(mutable_root(), ptr, ctx, "google.protobuf.Mixin.root");
+          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8(_internal_mutable_root(), ptr, ctx, "google.protobuf.Mixin.root");
           CHK_(ptr);
         } else goto handle_unusual;
         continue;
@@ -1347,9 +1331,9 @@ bool Mixin::MergePartialFromCodedStream(
       case 1: {
         if (static_cast< ::PROTOBUF_NAMESPACE_ID::uint8>(tag) == (10 & 0xFF)) {
           DO_(::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::ReadString(
-                input, this->mutable_name()));
+                input, this->_internal_mutable_name()));
           DO_(::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-            this->name().data(), static_cast<int>(this->name().length()),
+            this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
             ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::PARSE,
             "google.protobuf.Mixin.name"));
         } else {
@@ -1362,9 +1346,9 @@ bool Mixin::MergePartialFromCodedStream(
       case 2: {
         if (static_cast< ::PROTOBUF_NAMESPACE_ID::uint8>(tag) == (18 & 0xFF)) {
           DO_(::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::ReadString(
-                input, this->mutable_root()));
+                input, this->_internal_mutable_root()));
           DO_(::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-            this->root().data(), static_cast<int>(this->root().length()),
+            this->_internal_root().data(), static_cast<int>(this->_internal_root().length()),
             ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::PARSE,
             "google.protobuf.Mixin.root"));
         } else {
@@ -1403,21 +1387,21 @@ failure:
   // string name = 1;
   if (this->name().size() > 0) {
     ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->name().data(), static_cast<int>(this->name().length()),
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
       "google.protobuf.Mixin.name");
     target = stream->WriteStringMaybeAliased(
-        1, this->name(), target);
+        1, this->_internal_name(), target);
   }
 
   // string root = 2;
   if (this->root().size() > 0) {
     ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->root().data(), static_cast<int>(this->root().length()),
+      this->_internal_root().data(), static_cast<int>(this->_internal_root().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
       "google.protobuf.Mixin.root");
     target = stream->WriteStringMaybeAliased(
-        2, this->root(), target);
+        2, this->_internal_root(), target);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
@@ -1440,14 +1424,14 @@ size_t Mixin::ByteSizeLong() const {
   if (this->name().size() > 0) {
     total_size += 1 +
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
-        this->name());
+        this->_internal_name());
   }
 
   // string root = 2;
   if (this->root().size() > 0) {
     total_size += 1 +
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
-        this->root());
+        this->_internal_root());
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {

+ 129 - 28
src/google/protobuf/api.pb.h

@@ -238,6 +238,11 @@ class PROTOBUF_EXPORT Api :
   std::string* mutable_name();
   std::string* release_name();
   void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
 
   // string version = 4;
   void clear_version();
@@ -249,9 +254,17 @@ class PROTOBUF_EXPORT Api :
   std::string* mutable_version();
   std::string* release_version();
   void set_allocated_version(std::string* version);
+  private:
+  const std::string& _internal_version() const;
+  void _internal_set_version(const std::string& value);
+  std::string* _internal_mutable_version();
+  public:
 
   // .google.protobuf.SourceContext source_context = 5;
   bool has_source_context() const;
+  private:
+  bool _internal_has_source_context() const;
+  public:
   void clear_source_context();
   const PROTOBUF_NAMESPACE_ID::SourceContext& source_context() const;
   PROTOBUF_NAMESPACE_ID::SourceContext* release_source_context();
@@ -420,6 +433,11 @@ class PROTOBUF_EXPORT Method :
   std::string* mutable_name();
   std::string* release_name();
   void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
 
   // string request_type_url = 2;
   void clear_request_type_url();
@@ -431,6 +449,11 @@ class PROTOBUF_EXPORT Method :
   std::string* mutable_request_type_url();
   std::string* release_request_type_url();
   void set_allocated_request_type_url(std::string* request_type_url);
+  private:
+  const std::string& _internal_request_type_url() const;
+  void _internal_set_request_type_url(const std::string& value);
+  std::string* _internal_mutable_request_type_url();
+  public:
 
   // string response_type_url = 4;
   void clear_response_type_url();
@@ -442,6 +465,11 @@ class PROTOBUF_EXPORT Method :
   std::string* mutable_response_type_url();
   std::string* release_response_type_url();
   void set_allocated_response_type_url(std::string* response_type_url);
+  private:
+  const std::string& _internal_response_type_url() const;
+  void _internal_set_response_type_url(const std::string& value);
+  std::string* _internal_mutable_response_type_url();
+  public:
 
   // bool request_streaming = 3;
   void clear_request_streaming();
@@ -599,6 +627,11 @@ class PROTOBUF_EXPORT Mixin :
   std::string* mutable_name();
   std::string* release_name();
   void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
 
   // string root = 2;
   void clear_root();
@@ -610,6 +643,11 @@ class PROTOBUF_EXPORT Mixin :
   std::string* mutable_root();
   std::string* release_root();
   void set_allocated_root(std::string* root);
+  private:
+  const std::string& _internal_root() const;
+  void _internal_set_root(const std::string& value);
+  std::string* _internal_mutable_root();
+  public:
 
   // @@protoc_insertion_point(class_scope:google.protobuf.Mixin)
  private:
@@ -638,12 +676,22 @@ inline void Api::clear_name() {
 }
 inline const std::string& Api::name() const {
   // @@protoc_insertion_point(field_get:google.protobuf.Api.name)
-  return name_.GetNoArena();
+  return _internal_name();
 }
 inline void Api::set_name(const std::string& value) {
+  _internal_set_name(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Api.name)
+}
+inline std::string* Api::mutable_name() {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Api.name)
+  return _internal_mutable_name();
+}
+inline const std::string& Api::_internal_name() const {
+  return name_.GetNoArena();
+}
+inline void Api::_internal_set_name(const std::string& value) {
   
   name_.SetNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value);
-  // @@protoc_insertion_point(field_set:google.protobuf.Api.name)
 }
 inline void Api::set_name(std::string&& value) {
   
@@ -663,9 +711,8 @@ inline void Api::set_name(const char* value, size_t size) {
       ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.Api.name)
 }
-inline std::string* Api::mutable_name() {
+inline std::string* Api::_internal_mutable_name() {
   
-  // @@protoc_insertion_point(field_mutable:google.protobuf.Api.name)
   return name_.MutableNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 inline std::string* Api::release_name() {
@@ -746,12 +793,22 @@ inline void Api::clear_version() {
 }
 inline const std::string& Api::version() const {
   // @@protoc_insertion_point(field_get:google.protobuf.Api.version)
-  return version_.GetNoArena();
+  return _internal_version();
 }
 inline void Api::set_version(const std::string& value) {
+  _internal_set_version(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Api.version)
+}
+inline std::string* Api::mutable_version() {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Api.version)
+  return _internal_mutable_version();
+}
+inline const std::string& Api::_internal_version() const {
+  return version_.GetNoArena();
+}
+inline void Api::_internal_set_version(const std::string& value) {
   
   version_.SetNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value);
-  // @@protoc_insertion_point(field_set:google.protobuf.Api.version)
 }
 inline void Api::set_version(std::string&& value) {
   
@@ -771,9 +828,8 @@ inline void Api::set_version(const char* value, size_t size) {
       ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.Api.version)
 }
-inline std::string* Api::mutable_version() {
+inline std::string* Api::_internal_mutable_version() {
   
-  // @@protoc_insertion_point(field_mutable:google.protobuf.Api.version)
   return version_.MutableNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 inline std::string* Api::release_version() {
@@ -890,12 +946,22 @@ inline void Method::clear_name() {
 }
 inline const std::string& Method::name() const {
   // @@protoc_insertion_point(field_get:google.protobuf.Method.name)
-  return name_.GetNoArena();
+  return _internal_name();
 }
 inline void Method::set_name(const std::string& value) {
+  _internal_set_name(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Method.name)
+}
+inline std::string* Method::mutable_name() {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Method.name)
+  return _internal_mutable_name();
+}
+inline const std::string& Method::_internal_name() const {
+  return name_.GetNoArena();
+}
+inline void Method::_internal_set_name(const std::string& value) {
   
   name_.SetNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value);
-  // @@protoc_insertion_point(field_set:google.protobuf.Method.name)
 }
 inline void Method::set_name(std::string&& value) {
   
@@ -915,9 +981,8 @@ inline void Method::set_name(const char* value, size_t size) {
       ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.Method.name)
 }
-inline std::string* Method::mutable_name() {
+inline std::string* Method::_internal_mutable_name() {
   
-  // @@protoc_insertion_point(field_mutable:google.protobuf.Method.name)
   return name_.MutableNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 inline std::string* Method::release_name() {
@@ -941,12 +1006,22 @@ inline void Method::clear_request_type_url() {
 }
 inline const std::string& Method::request_type_url() const {
   // @@protoc_insertion_point(field_get:google.protobuf.Method.request_type_url)
-  return request_type_url_.GetNoArena();
+  return _internal_request_type_url();
 }
 inline void Method::set_request_type_url(const std::string& value) {
+  _internal_set_request_type_url(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Method.request_type_url)
+}
+inline std::string* Method::mutable_request_type_url() {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Method.request_type_url)
+  return _internal_mutable_request_type_url();
+}
+inline const std::string& Method::_internal_request_type_url() const {
+  return request_type_url_.GetNoArena();
+}
+inline void Method::_internal_set_request_type_url(const std::string& value) {
   
   request_type_url_.SetNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value);
-  // @@protoc_insertion_point(field_set:google.protobuf.Method.request_type_url)
 }
 inline void Method::set_request_type_url(std::string&& value) {
   
@@ -966,9 +1041,8 @@ inline void Method::set_request_type_url(const char* value, size_t size) {
       ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.Method.request_type_url)
 }
-inline std::string* Method::mutable_request_type_url() {
+inline std::string* Method::_internal_mutable_request_type_url() {
   
-  // @@protoc_insertion_point(field_mutable:google.protobuf.Method.request_type_url)
   return request_type_url_.MutableNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 inline std::string* Method::release_request_type_url() {
@@ -1006,12 +1080,22 @@ inline void Method::clear_response_type_url() {
 }
 inline const std::string& Method::response_type_url() const {
   // @@protoc_insertion_point(field_get:google.protobuf.Method.response_type_url)
-  return response_type_url_.GetNoArena();
+  return _internal_response_type_url();
 }
 inline void Method::set_response_type_url(const std::string& value) {
+  _internal_set_response_type_url(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Method.response_type_url)
+}
+inline std::string* Method::mutable_response_type_url() {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Method.response_type_url)
+  return _internal_mutable_response_type_url();
+}
+inline const std::string& Method::_internal_response_type_url() const {
+  return response_type_url_.GetNoArena();
+}
+inline void Method::_internal_set_response_type_url(const std::string& value) {
   
   response_type_url_.SetNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value);
-  // @@protoc_insertion_point(field_set:google.protobuf.Method.response_type_url)
 }
 inline void Method::set_response_type_url(std::string&& value) {
   
@@ -1031,9 +1115,8 @@ inline void Method::set_response_type_url(const char* value, size_t size) {
       ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.Method.response_type_url)
 }
-inline std::string* Method::mutable_response_type_url() {
+inline std::string* Method::_internal_mutable_response_type_url() {
   
-  // @@protoc_insertion_point(field_mutable:google.protobuf.Method.response_type_url)
   return response_type_url_.MutableNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 inline std::string* Method::release_response_type_url() {
@@ -1116,12 +1199,22 @@ inline void Mixin::clear_name() {
 }
 inline const std::string& Mixin::name() const {
   // @@protoc_insertion_point(field_get:google.protobuf.Mixin.name)
-  return name_.GetNoArena();
+  return _internal_name();
 }
 inline void Mixin::set_name(const std::string& value) {
+  _internal_set_name(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Mixin.name)
+}
+inline std::string* Mixin::mutable_name() {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Mixin.name)
+  return _internal_mutable_name();
+}
+inline const std::string& Mixin::_internal_name() const {
+  return name_.GetNoArena();
+}
+inline void Mixin::_internal_set_name(const std::string& value) {
   
   name_.SetNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value);
-  // @@protoc_insertion_point(field_set:google.protobuf.Mixin.name)
 }
 inline void Mixin::set_name(std::string&& value) {
   
@@ -1141,9 +1234,8 @@ inline void Mixin::set_name(const char* value, size_t size) {
       ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.Mixin.name)
 }
-inline std::string* Mixin::mutable_name() {
+inline std::string* Mixin::_internal_mutable_name() {
   
-  // @@protoc_insertion_point(field_mutable:google.protobuf.Mixin.name)
   return name_.MutableNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 inline std::string* Mixin::release_name() {
@@ -1167,12 +1259,22 @@ inline void Mixin::clear_root() {
 }
 inline const std::string& Mixin::root() const {
   // @@protoc_insertion_point(field_get:google.protobuf.Mixin.root)
-  return root_.GetNoArena();
+  return _internal_root();
 }
 inline void Mixin::set_root(const std::string& value) {
+  _internal_set_root(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Mixin.root)
+}
+inline std::string* Mixin::mutable_root() {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Mixin.root)
+  return _internal_mutable_root();
+}
+inline const std::string& Mixin::_internal_root() const {
+  return root_.GetNoArena();
+}
+inline void Mixin::_internal_set_root(const std::string& value) {
   
   root_.SetNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value);
-  // @@protoc_insertion_point(field_set:google.protobuf.Mixin.root)
 }
 inline void Mixin::set_root(std::string&& value) {
   
@@ -1192,9 +1294,8 @@ inline void Mixin::set_root(const char* value, size_t size) {
       ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.Mixin.root)
 }
-inline std::string* Mixin::mutable_root() {
+inline std::string* Mixin::_internal_mutable_root() {
   
-  // @@protoc_insertion_point(field_mutable:google.protobuf.Mixin.root)
   return root_.MutableNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 inline std::string* Mixin::release_root() {

+ 1 - 1
src/google/protobuf/arena.h

@@ -50,9 +50,9 @@ using type_info = ::type_info;
 #include <typeinfo>
 #endif
 
-#include <google/protobuf/port.h>
 #include <type_traits>
 #include <google/protobuf/arena_impl.h>
+#include <google/protobuf/port.h>
 
 #include <google/protobuf/port_def.inc>
 

+ 1 - 3
src/google/protobuf/compiler/command_line_interface.cc

@@ -70,7 +70,6 @@
 #include <google/protobuf/compiler/plugin.pb.h>
 #include <google/protobuf/compiler/code_generator.h>
 #include <google/protobuf/compiler/importer.h>
-#include <google/protobuf/io/io_win32.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
@@ -79,8 +78,7 @@
 #include <google/protobuf/text_format.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
-
-
+#include <google/protobuf/io/io_win32.h>
 #include <google/protobuf/stubs/map_util.h>
 #include <google/protobuf/stubs/stl_util.h>
 

+ 2 - 3
src/google/protobuf/compiler/command_line_interface_unittest.cc

@@ -45,22 +45,21 @@
 #include <google/protobuf/stubs/stringprintf.h>
 #include <google/protobuf/testing/file.h>
 #include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/file.h>
 #include <google/protobuf/compiler/mock_code_generator.h>
 #include <google/protobuf/compiler/subprocess.h>
 #include <google/protobuf/compiler/code_generator.h>
 #include <google/protobuf/compiler/command_line_interface.h>
 #include <google/protobuf/test_util2.h>
 #include <google/protobuf/unittest.pb.h>
-#include <google/protobuf/io/io_win32.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/stubs/substitute.h>
-
-#include <google/protobuf/testing/file.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
+#include <google/protobuf/io/io_win32.h>
 
 #include <google/protobuf/stubs/strutil.h>
 

+ 0 - 2
src/google/protobuf/compiler/cpp/cpp_extension.cc

@@ -39,8 +39,6 @@
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/stubs/strutil.h>
 
-
-
 namespace google {
 namespace protobuf {
 namespace compiler {

+ 0 - 1
src/google/protobuf/compiler/cpp/cpp_field.cc

@@ -38,7 +38,6 @@
 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
 #include <google/protobuf/compiler/cpp/cpp_primitive_field.h>
 #include <google/protobuf/compiler/cpp/cpp_string_field.h>
-
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/compiler/cpp/cpp_enum_field.h>

+ 79 - 20
src/google/protobuf/compiler/cpp/cpp_file.cc

@@ -51,8 +51,6 @@
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/stubs/strutil.h>
 
-
-
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -440,17 +438,22 @@ void FileGenerator::GenerateSourceIncludes(io::Printer* printer) {
 void FileGenerator::GenerateSourceDefaultInstance(int idx,
                                                   io::Printer* printer) {
   Formatter format(printer, variables_);
+  MessageGenerator* generator = message_generators_[idx].get();
   format(
       "class $1$ {\n"
       " public:\n"
       "  ::$proto_ns$::internal::ExplicitlyConstructed<$2$> _instance;\n",
-      DefaultInstanceType(message_generators_[idx]->descriptor_, options_),
-      message_generators_[idx]->classname_);
+      DefaultInstanceType(generator->descriptor_, options_),
+      generator->classname_);
   format.Indent();
-  message_generators_[idx]->GenerateExtraDefaultFields(printer);
+  generator->GenerateExtraDefaultFields(printer);
   format.Outdent();
-  format("} $1$;\n",
-         DefaultInstanceName(message_generators_[idx]->descriptor_, options_));
+  format("} $1$;\n", DefaultInstanceName(generator->descriptor_, options_));
+  if (options_.lite_implicit_weak_fields) {
+    format("$1$DefaultTypeInternal* $2$ = &$3$;\n", generator->classname_,
+           DefaultInstancePtr(generator->descriptor_, options_),
+           DefaultInstanceName(generator->descriptor_, options_));
+  }
 }
 
 // A list of things defined in one .pb.cc file that we need to reference from
@@ -513,19 +516,43 @@ void FileGenerator::GenerateInternalForwardDeclarations(
   }
 
   for (auto scc : Sorted(refs.weak_sccs)) {
-    format(
-        "extern __attribute__((weak)) ::$proto_ns$::internal::SCCInfo<$1$> "
-        "$2$;\n",
-        scc->children.size(), SccInfoSymbol(scc, options_));
+    // We do things a little bit differently for proto1-style weak fields versus
+    // lite implicit weak fields, even though they are trying to accomplish
+    // similar things. We need to support implicit weak fields on iOS, and the
+    // Apple linker only supports weak definitions, not weak declarations. For
+    // that reason we need a pointer type which we can weakly define to be null.
+    // However, code size considerations prevent us from using the same approach
+    // for proto1-style weak fields.
+    if (options_.lite_implicit_weak_fields) {
+      format("extern ::$proto_ns$::internal::SCCInfo<$1$> $2$;\n",
+             scc->children.size(), SccInfoSymbol(scc, options_));
+      format(
+          "__attribute__((weak)) ::$proto_ns$::internal::SCCInfo<$1$>*\n"
+          "    $2$ = nullptr;\n",
+          scc->children.size(), SccInfoPtrSymbol(scc, options_));
+    } else {
+      format(
+          "extern __attribute__((weak)) ::$proto_ns$::internal::SCCInfo<$1$> "
+          "$2$;\n",
+          scc->children.size(), SccInfoSymbol(scc, options_));
+    }
   }
 
   {
     NamespaceOpener ns(format);
     for (auto instance : Sorted(refs.weak_default_instances)) {
       ns.ChangeTo(Namespace(instance, options_));
-      format("extern __attribute__((weak)) $1$ $2$;\n",
-             DefaultInstanceType(instance, options_),
-             DefaultInstanceName(instance, options_));
+      if (options_.lite_implicit_weak_fields) {
+        format("extern $1$ $2$;\n", DefaultInstanceType(instance, options_),
+               DefaultInstanceName(instance, options_));
+        format("__attribute__((weak)) $1$* $2$ = nullptr;\n",
+               DefaultInstanceType(instance, options_),
+               DefaultInstancePtr(instance, options_));
+      } else {
+        format("extern __attribute__((weak)) $1$ $2$;\n",
+               DefaultInstanceType(instance, options_),
+               DefaultInstanceName(instance, options_));
+      }
     }
   }
 
@@ -555,7 +582,8 @@ void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* printer) {
   GenerateInternalForwardDeclarations(refs, printer);
 
   if (IsSCCRepresentative(message_generators_[idx]->descriptor_)) {
-    GenerateInitForSCC(GetSCC(message_generators_[idx]->descriptor_), printer);
+    GenerateInitForSCC(GetSCC(message_generators_[idx]->descriptor_), refs,
+                       printer);
   }
 
   {  // package namespace
@@ -649,7 +677,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
 
     // Now generate the InitDefaults for each SCC.
     for (auto scc : sccs_) {
-      GenerateInitForSCC(scc, printer);
+      GenerateInitForSCC(scc, refs, printer);
     }
 
     if (HasDescriptorMethods(file_, options_)) {
@@ -904,7 +932,9 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) {
   }
 }
 
-void FileGenerator::GenerateInitForSCC(const SCC* scc, io::Printer* printer) {
+void FileGenerator::GenerateInitForSCC(const SCC* scc,
+                                       const CrossFileReferences& refs,
+                                       io::Printer* printer) {
   Formatter format(printer, variables_);
   // We use static and not anonymous namespace because symbol names are
   // substantially shorter.
@@ -954,17 +984,46 @@ void FileGenerator::GenerateInitForSCC(const SCC* scc, io::Printer* printer) {
   format.Outdent();
   format("}\n\n");
 
+  // If we are using lite implicit weak fields then we need to distinguish
+  // between regular SCC dependencies and ones that we need to reference weakly
+  // through an extra pointer indirection.
+  std::vector<const SCC*> regular_sccs;
+  std::vector<const SCC*> implicit_weak_sccs;
+  for (const SCC* child : scc->children) {
+    if (options_.lite_implicit_weak_fields &&
+        refs.weak_sccs.find(child) != refs.weak_sccs.end()) {
+      implicit_weak_sccs.push_back(child);
+    } else {
+      regular_sccs.push_back(child);
+    }
+  }
+
   format(
       "$dllexport_decl $::$proto_ns$::internal::SCCInfo<$1$> $2$ =\n"
       "    "
       "{{ATOMIC_VAR_INIT(::$proto_ns$::internal::SCCInfoBase::kUninitialized), "
-      "$1$, InitDefaults$2$}, {",
+      "$3$, $4$, InitDefaults$2$}, {",
       scc->children.size(),  // 1
-      SccInfoSymbol(scc, options_));
-  for (const SCC* child : scc->children) {
+      SccInfoSymbol(scc, options_), regular_sccs.size(),
+      implicit_weak_sccs.size());
+  for (const SCC* child : regular_sccs) {
     format("\n      &$1$.base,", SccInfoSymbol(child, options_));
   }
+  for (const SCC* child : implicit_weak_sccs) {
+    format(
+        "\n      reinterpret_cast<::$proto_ns$::internal::SCCInfoBase**>("
+        "\n          &$1$),",
+        SccInfoPtrSymbol(child, options_));
+  }
   format("}};\n\n");
+
+  if (options_.lite_implicit_weak_fields) {
+    format(
+        "$dllexport_decl $::$proto_ns$::internal::SCCInfo<$1$>*\n"
+        "    $2$ = &$3$;\n\n",
+        scc->children.size(), SccInfoPtrSymbol(scc, options_),
+        SccInfoSymbol(scc, options_));
+  }
 }
 
 void FileGenerator::GenerateTables(io::Printer* printer) {

+ 2 - 1
src/google/protobuf/compiler/cpp/cpp_file.h

@@ -113,7 +113,8 @@ class FileGenerator {
   void GenerateSourceIncludes(io::Printer* printer);
   void GenerateSourceDefaultInstance(int idx, io::Printer* printer);
 
-  void GenerateInitForSCC(const SCC* scc, io::Printer* printer);
+  void GenerateInitForSCC(const SCC* scc, const CrossFileReferences& refs,
+                          io::Printer* printer);
   void GenerateTables(io::Printer* printer);
   void GenerateReflectionInitializationCode(io::Printer* printer);
 

+ 0 - 2
src/google/protobuf/compiler/cpp/cpp_generator.cc

@@ -45,8 +45,6 @@
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/zero_copy_stream.h>
 
-
-
 namespace google {
 namespace protobuf {
 namespace compiler {

+ 22 - 12
src/google/protobuf/compiler/cpp/cpp_helpers.cc

@@ -44,7 +44,6 @@
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/descriptor.h>
-
 #include <google/protobuf/compiler/scc.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/zero_copy_stream.h>
@@ -52,8 +51,6 @@
 #include <google/protobuf/wire_format_lite.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
-
-
 #include <google/protobuf/stubs/hash.h>
 
 #include <google/protobuf/port_def.inc>
@@ -204,6 +201,10 @@ void SetIntVar(const Options& options, const std::string& type,
   (*variables)[type] = IntTypeName(options, type);
 }
 
+bool HasInternalAccessors(const FieldOptions::CType ctype) {
+  return ctype == FieldOptions::STRING;
+}
+
 }  // namespace
 
 void SetCommonVars(const Options& options,
@@ -373,12 +374,22 @@ std::string DefaultInstanceName(const Descriptor* descriptor,
   return "_" + ClassName(descriptor, false) + "_default_instance_";
 }
 
+std::string DefaultInstancePtr(const Descriptor* descriptor,
+                               const Options& options) {
+  return DefaultInstanceName(descriptor, options) + "ptr_";
+}
+
 std::string QualifiedDefaultInstanceName(const Descriptor* descriptor,
                                          const Options& options) {
   return QualifiedFileLevelSymbol(
       descriptor->file(), DefaultInstanceName(descriptor, options), options);
 }
 
+std::string QualifiedDefaultInstancePtr(const Descriptor* descriptor,
+                                        const Options& options) {
+  return QualifiedDefaultInstanceName(descriptor, options) + "ptr_";
+}
+
 std::string DescriptorTableName(const FileDescriptor* file,
                                 const Options& options) {
   return UniqueName("descriptor_table", file, options);
@@ -1125,7 +1136,7 @@ bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options,
                          MessageSCCAnalyzer* scc_analyzer) {
   return UsingImplicitWeakFields(field->file(), options) &&
          field->type() == FieldDescriptor::TYPE_MESSAGE &&
-         !field->is_required() && !field->is_map() &&
+         !field->is_required() && !field->is_map() && !field->is_extension() &&
          field->containing_oneof() == nullptr &&
          !IsWellKnownMessage(field->message_type()->file()) &&
          field->message_type()->file()->name() !=
@@ -1479,7 +1490,8 @@ class ParseLoopGenerator {
         name = "StringPieceParser" + utf8;
         break;
     }
-    format_("ptr = $pi_ns$::Inline$1$($2$_$3$(), ptr, ctx$4$);\n", name,
+    format_("ptr = $pi_ns$::Inline$1$($2$$3$_$4$(), ptr, ctx$5$);\n", name,
+            HasInternalAccessors(ctype) ? "_internal_" : "",
             field->is_repeated() && !field->is_packable() ? "add" : "mutable",
             FieldName(field), field_name);
   }
@@ -1551,10 +1563,9 @@ class ParseLoopGenerator {
                   FieldName(field));
             } else {
               format_(
-                  "ptr = ctx->ParseMessage("
-                  "CastToBase(&$1$_)->AddWeak(reinterpret_cast<const "
-                  "::$proto_ns$::MessageLite*>(&$2$::_$3$_default_instance_)), "
-                  "ptr);\n",
+                  "ptr = ctx->ParseMessage($1$_.AddWeak(reinterpret_cast<const "
+                  "::$proto_ns$::MessageLite*>($2$::_$3$_default_instance_ptr_)"
+                  "), ptr);\n",
                   FieldName(field), Namespace(field->message_type(), options_),
                   ClassName(field->message_type()));
             }
@@ -1757,12 +1768,11 @@ class ParseLoopGenerator {
       }
       GenerateFieldBody(wiretype, field);
       if (is_repeat) {
-        string type = tag_size == 2 ? "uint16" : "uint8";
         format_.Outdent();
         format_(
             "  if (!ctx->DataAvailable(ptr)) break;\n"
-            "} while ($pi_ns$::UnalignedLoad<$1$>(ptr) == $2$);\n",
-            IntTypeName(options_, type), SmallVarintValue(tag));
+            "} while ($pi_ns$::ExpectTag<$1$>(ptr));\n",
+            tag);
       }
       format_.Outdent();
       if (fallback_tag) {

+ 14 - 1
src/google/protobuf/compiler/cpp/cpp_helpers.h

@@ -49,7 +49,6 @@
 #include <google/protobuf/port.h>
 #include <google/protobuf/stubs/strutil.h>
 
-
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -133,10 +132,19 @@ std::string DefaultInstanceType(const Descriptor* descriptor,
 std::string DefaultInstanceName(const Descriptor* descriptor,
                                 const Options& options);
 
+// Non-qualified name of the default instance pointer. This is used only for
+// implicit weak fields, where we need an extra indirection.
+std::string DefaultInstancePtr(const Descriptor* descriptor,
+                               const Options& options);
+
 // Fully qualified name of the default_instance of this message.
 std::string QualifiedDefaultInstanceName(const Descriptor* descriptor,
                                          const Options& options);
 
+// Fully qualified name of the default instance pointer.
+std::string QualifiedDefaultInstancePtr(const Descriptor* descriptor,
+                                        const Options& options);
+
 // DescriptorTable variable name.
 std::string DescriptorTableName(const FileDescriptor* file,
                                 const Options& options);
@@ -549,6 +557,11 @@ inline std::string SccInfoSymbol(const SCC* scc, const Options& options) {
                     scc->GetRepresentative(), options);
 }
 
+inline std::string SccInfoPtrSymbol(const SCC* scc, const Options& options) {
+  return UniqueName("scc_info_ptr_" + ClassName(scc->GetRepresentative()),
+                    scc->GetRepresentative(), options);
+}
+
 void ListAllFields(const Descriptor* d,
                    std::vector<const FieldDescriptor*>* fields);
 void ListAllFields(const FileDescriptor* d,

+ 51 - 16
src/google/protobuf/compiler/cpp/cpp_message.cc

@@ -55,8 +55,6 @@
 #include <google/protobuf/wire_format.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
-
-
 #include <google/protobuf/stubs/hash.h>
 
 
@@ -738,7 +736,12 @@ void MessageGenerator::GenerateFieldAccessorDeclarations(io::Printer* printer) {
     if (field->is_repeated()) {
       format("$deprecated_attr$int ${1$$name$_size$}$() const;\n", field);
     } else if (HasHasMethod(field)) {
-      format("$deprecated_attr$bool ${1$has_$name$$}$() const;\n", field);
+      format(
+          "$deprecated_attr$bool ${1$has_$name$$}$() const;\n"
+          "private:\n"
+          "bool _internal_has_$name$() const;\n"
+          "public:\n",
+          field);
     } else if (HasPrivateHasMethod(field)) {
       format(
           "private:\n"
@@ -800,9 +803,12 @@ void MessageGenerator::GenerateSingularFieldHasBits(
     format.Set("has_mask",
                strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8));
     format(
+        "inline bool $classname$::_internal_has_$name$() const {\n"
+        "  return (_has_bits_[$has_array_index$] & 0x$has_mask$u) != 0;\n"
+        "}\n"
         "inline bool $classname$::has_$name$() const {\n"
         "$annotate_accessor$"
-        "  return (_has_bits_[$has_array_index$] & 0x$has_mask$u) != 0;\n"
+        "  return _internal_has_$name$();\n"
         "}\n");
   } else {
     // Message fields have a has_$name$() method.
@@ -849,13 +855,28 @@ void MessageGenerator::GenerateOneofMemberHasBits(const FieldDescriptor* field,
   // Oneofs also have has_$name$() but only as a private helper
   // method, so that generated code is slightly cleaner (vs.  comparing
   // _oneof_case_[index] against a constant everywhere).
+  //
+  // If has_$name$() is private, there is no need to add an internal accessor.
+  // Only annotate public accessors.
+  if (HasPrivateHasMethod(field)) {
+    format(
+        "inline bool $classname$::has_$name$() const {\n"
+        "  return $oneof_name$_case() == k$field_name$;\n"
+        "}\n");
+  } else {
+    format(
+        "inline bool $classname$::_internal_has_$name$() const {\n"
+        "  return $oneof_name$_case() == k$field_name$;\n"
+        "}\n"
+        "inline bool $classname$::has_$name$() const {\n"
+        "$annotate_accessor$"
+        "  return _internal_has_$name$();\n"
+        "}\n");
+  }
+  // set_has_$name$() for oneof fields is always private; hence should not be
+  // annotated.
   format(
-      "inline bool $classname$::has_$name$() const {\n"
-      "$annotate_accessor$"
-      "  return $oneof_name$_case() == k$field_name$;\n"
-      "}\n"
       "inline void $classname$::set_has_$name$() {\n"
-      "$annotate_accessor$"
       "  _oneof_case_[$oneof_index$] = k$field_name$;\n"
       "}\n");
 }
@@ -918,8 +939,12 @@ void MessageGenerator::GenerateFieldAccessorDefinitions(io::Printer* printer) {
       format(
           "inline int $classname$::$name$_size() const {\n"
           "$annotate_accessor$"
-          "  return $name$_.size();\n"
-          "}\n");
+          "  return $name$_$1$.size();\n"
+          "}\n",
+          IsImplicitWeakField(field, options_, scc_analyzer_) &&
+                  field->message_type()
+              ? ".weak"
+              : "");
     } else if (field->containing_oneof()) {
       format.Set("field_name", UnderscoresToCamelCase(field->name(), true));
       format.Set("oneof_name", field->containing_oneof()->name());
@@ -1943,10 +1968,18 @@ void MessageGenerator::GenerateDefaultInstanceInitializer(
                                          options_));  // 1
         continue;
       }
-      format(
-          "$package_ns$::$name$_ = const_cast< $1$*>(\n"
-          "    $1$::internal_default_instance());\n",
-          FieldMessageTypeName(field, options_));
+      if (IsImplicitWeakField(field, options_, scc_analyzer_)) {
+        format(
+            "$package_ns$::$name$_ = reinterpret_cast<$1$*>(\n"
+            "    $2$);\n",
+            FieldMessageTypeName(field, options_),
+            QualifiedDefaultInstancePtr(field->message_type(), options_));
+      } else {
+        format(
+            "$package_ns$::$name$_ = const_cast< $1$*>(\n"
+            "    $1$::internal_default_instance());\n",
+            FieldMessageTypeName(field, options_));
+      }
     } else if (field->containing_oneof() &&
                HasDescriptorMethods(descriptor_->file(), options_)) {
       field_generators_.get(field).GenerateConstructorCode(printer);
@@ -4295,7 +4328,9 @@ void MessageGenerator::GenerateIsInitialized(io::Printer* printer) {
       if (field->is_repeated()) {
         if (IsImplicitWeakField(field, options_, scc_analyzer_)) {
           format(
-              "if (!::$proto_ns$::internal::AllAreInitializedWeak(this->$1$_))"
+              "if "
+              "(!::$proto_ns$::internal::AllAreInitializedWeak(this->$1$_.weak)"
+              ")"
               " return false;\n",
               FieldName(field));
         } else {

+ 53 - 95
src/google/protobuf/compiler/cpp/cpp_message_field.cc

@@ -62,6 +62,8 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
       (*variables)["type"] + "*", (*variables)["name"] + "_", implicit_weak);
   (*variables)["type_default_instance"] =
       QualifiedDefaultInstanceName(descriptor->message_type(), options);
+  (*variables)["type_default_instance_ptr"] =
+      QualifiedDefaultInstancePtr(descriptor->message_type(), options);
   (*variables)["type_reference_function"] =
       implicit_weak
           ? ("  " + ReferenceFunctionName(descriptor->message_type(), options) +
@@ -149,47 +151,40 @@ void MessageFieldGenerator::GenerateInlineAccessorDefinitions(
   format(
       "inline const $type$& $classname$::$name$() const {\n"
       "$annotate_accessor$"
+      "$type_reference_function$"
       "  const $type$* p = $casted_member$;\n"
       "  // @@protoc_insertion_point(field_get:$full_name$)\n"
       "  return p != nullptr ? *p : *reinterpret_cast<const $type$*>(\n"
       "      &$type_default_instance$);\n"
       "}\n");
 
-  format(
-      "inline $type$* $classname$::$release_name$() {\n"
-      "$annotate_accessor$"
-      "  // @@protoc_insertion_point(field_release:$full_name$)\n"
-      "$type_reference_function$"
-      "  $clear_hasbit$\n"
-      "  $type$* temp = $casted_member$;\n");
   if (SupportsArenas(descriptor_)) {
     format(
+        "inline $type$* $classname$::$release_name$() {\n"
+        "  auto temp = unsafe_arena_release_$name$();\n"
         "  if (GetArenaNoVirtual() != nullptr) {\n"
         "    temp = ::$proto_ns$::internal::DuplicateIfNonNull(temp);\n"
-        "  }\n");
+        "  }\n"
+        "  return temp;\n"
+        "}\n"
+        "inline $type$* $classname$::unsafe_arena_release_$name$() {\n");
+  } else {
+    format("inline $type$* $classname$::$release_name$() {\n");
   }
   format(
+      "$annotate_accessor$"
+      "  // @@protoc_insertion_point(field_release:$full_name$)\n"
+      "$type_reference_function$"
+      "  $clear_hasbit$\n"
+      "  $type$* temp = $casted_member$;\n"
       "  $name$_ = nullptr;\n"
       "  return temp;\n"
       "}\n");
 
-  if (SupportsArenas(descriptor_)) {
-    format(
-        "inline $type$* $classname$::unsafe_arena_release_$name$() {\n"
-        "$annotate_accessor$"
-        "  // "
-        "@@protoc_insertion_point(field_unsafe_arena_release:$full_name$)\n"
-        "$type_reference_function$"
-        "  $clear_hasbit$\n"
-        "  $type$* temp = $casted_member$;\n"
-        "  $name$_ = nullptr;\n"
-        "  return temp;\n"
-        "}\n");
-  }
-
   format(
       "inline $type$* $classname$::mutable_$name$() {\n"
       "$annotate_accessor$"
+      "$type_reference_function$"
       "  $set_hasbit$\n"
       "  if ($name$_ == nullptr) {\n"
       "    auto* p = CreateMaybeMessage<$type$>(GetArenaNoVirtual());\n");
@@ -283,9 +278,9 @@ void MessageFieldGenerator::GenerateInternalAccessorDefinitions(
         "    const $classname$* msg) {\n"
         "  if (msg->$name$_ != nullptr) {\n"
         "    return *msg->$name$_;\n"
-        "  } else if (&$type_default_instance$ != nullptr) {\n"
+        "  } else if ($type_default_instance_ptr$ != nullptr) {\n"
         "    return *reinterpret_cast<const ::$proto_ns$::MessageLite*>(\n"
-        "        &$type_default_instance$);\n"
+        "        $type_default_instance_ptr$);\n"
         "  } else {\n"
         "    return "
         "*::$proto_ns$::internal::ImplicitWeakMessage::default_instance();\n"
@@ -300,14 +295,14 @@ void MessageFieldGenerator::GenerateInternalAccessorDefinitions(
       }
       format(
           "  if (msg->$name$_ == nullptr) {\n"
-          "    if (&$type_default_instance$ == nullptr) {\n"
+          "    if ($type_default_instance_ptr$ == nullptr) {\n"
           "      msg->$name$_ = ::$proto_ns$::Arena::CreateMessage<\n"
           "          ::$proto_ns$::internal::ImplicitWeakMessage>(\n"
           "              msg->GetArenaNoVirtual());\n"
           "    } else {\n"
           "      msg->$name$_ = reinterpret_cast<const "
           "::$proto_ns$::MessageLite*>(\n"
-          "          &$type_default_instance$)->New("
+          "          $type_default_instance_ptr$)->New("
           "msg->GetArenaNoVirtual());\n"
           "    }\n"
           "  }\n"
@@ -322,13 +317,13 @@ void MessageFieldGenerator::GenerateInternalAccessorDefinitions(
       }
       format(
           "  if (msg->$name$_ == nullptr) {\n"
-          "    if (&$type_default_instance$ == nullptr) {\n"
+          "    if ($type_default_instance_ptr$ == nullptr) {\n"
           "      msg->$name$_ = "
           "new ::$proto_ns$::internal::ImplicitWeakMessage;\n"
           "    } else {\n"
           "      msg->$name$_ = "
           "reinterpret_cast<const ::$proto_ns$::MessageLite*>(\n"
-          "          &$type_default_instance$)->New();\n"
+          "          $type_default_instance_ptr$)->New();\n"
           "    }\n"
           "  }\n"
           "  return msg->$name$_;\n"
@@ -637,7 +632,11 @@ RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {}
 void RepeatedMessageFieldGenerator::GeneratePrivateMembers(
     io::Printer* printer) const {
   Formatter format(printer, variables_);
-  format("::$proto_ns$::RepeatedPtrField< $type$ > $name$_;\n");
+  if (implicit_weak_field_) {
+    format("::$proto_ns$::WeakRepeatedPtrField< $type$ > $name$_;\n");
+  } else {
+    format("::$proto_ns$::RepeatedPtrField< $type$ > $name$_;\n");
+  }
 }
 
 void RepeatedMessageFieldGenerator::GenerateAccessorDeclarations(
@@ -657,20 +656,22 @@ void RepeatedMessageFieldGenerator::GenerateAccessorDeclarations(
 void RepeatedMessageFieldGenerator::GenerateInlineAccessorDefinitions(
     io::Printer* printer) const {
   Formatter format(printer, variables_);
+  format.Set("weak", implicit_weak_field_ ? ".weak" : "");
+
   format(
       "inline $type$* $classname$::mutable_$name$(int index) {\n"
       "$annotate_accessor$"
       // TODO(dlj): move insertion points
       "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
       "$type_reference_function$"
-      "  return $name$_.Mutable(index);\n"
+      "  return $name$_$weak$.Mutable(index);\n"
       "}\n"
       "inline ::$proto_ns$::RepeatedPtrField< $type$ >*\n"
       "$classname$::mutable_$name$() {\n"
       "$annotate_accessor$"
       "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
       "$type_reference_function$"
-      "  return &$name$_;\n"
+      "  return &$name$_$weak$;\n"
       "}\n");
 
   if (options_.safe_boundary_check) {
@@ -678,7 +679,7 @@ void RepeatedMessageFieldGenerator::GenerateInlineAccessorDefinitions(
         "inline const $type$& $classname$::$name$(int index) const {\n"
         "$annotate_accessor$"
         "  // @@protoc_insertion_point(field_get:$full_name$)\n"
-        "  return $name$_.InternalCheckedGet(index,\n"
+        "  return $name$_$weak$.InternalCheckedGet(index,\n"
         "      *reinterpret_cast<const $type$*>(&$type_default_instance$));\n"
         "}\n");
   } else {
@@ -687,7 +688,7 @@ void RepeatedMessageFieldGenerator::GenerateInlineAccessorDefinitions(
         "$annotate_accessor$"
         "  // @@protoc_insertion_point(field_get:$full_name$)\n"
         "$type_reference_function$"
-        "  return $name$_.Get(index);\n"
+        "  return $name$_$weak$.Get(index);\n"
         "}\n");
   }
 
@@ -695,7 +696,7 @@ void RepeatedMessageFieldGenerator::GenerateInlineAccessorDefinitions(
       "inline $type$* $classname$::add_$name$() {\n"
       "$annotate_accessor$"
       "  // @@protoc_insertion_point(field_add:$full_name$)\n"
-      "  return $name$_.Add();\n"
+      "  return $name$_$weak$.Add();\n"
       "}\n");
 
   format(
@@ -704,39 +705,26 @@ void RepeatedMessageFieldGenerator::GenerateInlineAccessorDefinitions(
       "$annotate_accessor$"
       "  // @@protoc_insertion_point(field_list:$full_name$)\n"
       "$type_reference_function$"
-      "  return $name$_;\n"
+      "  return $name$_$weak$;\n"
       "}\n");
 }
 
 void RepeatedMessageFieldGenerator::GenerateClearingCode(
     io::Printer* printer) const {
   Formatter format(printer, variables_);
-  if (implicit_weak_field_) {
-    format(
-        "CastToBase(&$name$_)->Clear<"
-        "::$proto_ns$::internal::ImplicitWeakTypeHandler<$type$>>();\n");
-  } else {
-    format("$name$_.Clear();\n");
-  }
+  format("$name$_.Clear();\n");
 }
 
 void RepeatedMessageFieldGenerator::GenerateMergingCode(
     io::Printer* printer) const {
   Formatter format(printer, variables_);
-  if (implicit_weak_field_) {
-    format(
-        "CastToBase(&$name$_)->MergeFrom<"
-        "::$proto_ns$::internal::ImplicitWeakTypeHandler<$type$>>(CastToBase("
-        "from.$name$_));\n");
-  } else {
-    format("$name$_.MergeFrom(from.$name$_);\n");
-  }
+  format("$name$_.MergeFrom(from.$name$_);\n");
 }
 
 void RepeatedMessageFieldGenerator::GenerateSwappingCode(
     io::Printer* printer) const {
   Formatter format(printer, variables_);
-  format("CastToBase(&$name$_)->InternalSwap(CastToBase(&other->$name$_));\n");
+  format("$name$_.InternalSwap(&other->$name$_);\n");
 }
 
 void RepeatedMessageFieldGenerator::GenerateConstructorCode(
@@ -751,9 +739,9 @@ void RepeatedMessageFieldGenerator::GenerateMergeFromCodedStream(
     if (implicit_weak_field_) {
       format(
           "DO_(::$proto_ns$::internal::WireFormatLite::"
-          "ReadMessage(input, CastToBase(&$name$_)->AddWeak(\n"
+          "ReadMessage(input, $name$_.AddWeak(\n"
           "    reinterpret_cast<const ::$proto_ns$::MessageLite*>(\n"
-          "        &$type_default_instance$))));\n");
+          "        $type_default_instance_ptr$))));\n");
     } else {
       format(
           "DO_(::$proto_ns$::internal::WireFormatLite::"
@@ -770,55 +758,25 @@ void RepeatedMessageFieldGenerator::GenerateMergeFromCodedStream(
 void RepeatedMessageFieldGenerator::GenerateSerializeWithCachedSizesToArray(
     io::Printer* printer) const {
   Formatter format(printer, variables_);
-  if (implicit_weak_field_) {
-    format(
-        "for (unsigned int i = 0,\n"
-        "    n = static_cast<unsigned int>(this->$name$_size()); i < n; i++) "
-        "{\n"
-        "  stream->EnsureSpace(&target);\n"
-        "  target = ::$proto_ns$::internal::WireFormatLite::\n"
-        "    InternalWrite$declared_type$ToArray(\n"
-        "      $number$,\n"
-        "    CastToBase($name$_).Get<"
-        "::$proto_ns$::internal::ImplicitWeakTypeHandler<$type$>>("
-        "static_cast<int>(i)), target, stream);\n"
-        "}\n");
-  } else {
-    format(
-        "for (auto it = this->$name$().pointer_begin(),\n"
-        "          end = this->$name$().pointer_end(); it < end; ++it) {\n"
-        "  stream->EnsureSpace(&target);\n"
-        "  target = ::$proto_ns$::internal::WireFormatLite::\n"
-        "    InternalWrite$declared_type$ToArray($number$, **it, target, "
-        "stream);\n"
-        "}\n");
-  }
+  format(
+      "for (auto it = this->$name$_.pointer_begin(),\n"
+      "          end = this->$name$_.pointer_end(); it < end; ++it) {\n"
+      "  stream->EnsureSpace(&target);\n"
+      "  target = ::$proto_ns$::internal::WireFormatLite::\n"
+      "    InternalWrite$declared_type$ToArray($number$, **it, target, "
+      "stream);\n"
+      "}\n");
 }
 
 void RepeatedMessageFieldGenerator::GenerateByteSize(
     io::Printer* printer) const {
   Formatter format(printer, variables_);
   format(
-      "{\n"
-      "  unsigned int count = static_cast<unsigned "
-      "int>(this->$name$_size());\n");
-  format.Indent();
-  format(
-      "total_size += $tag_size$UL * count;\n"
-      "for (unsigned int i = 0; i < count; i++) {\n"
+      "total_size += $tag_size$UL * this->$name$_size();\n"
+      "for (const auto& msg : this->$name$_) {\n"
       "  total_size +=\n"
-      "    ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n");
-  if (implicit_weak_field_) {
-    format(
-        "      CastToBase($name$_).Get<"
-        "::$proto_ns$::internal::ImplicitWeakTypeHandler<$type$>>("
-        "static_cast<int>(i)));\n");
-  } else {
-    format("      this->$name$(static_cast<int>(i)));\n");
-  }
-  format("}\n");
-  format.Outdent();
-  format("}\n");
+      "    ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(msg);\n"
+      "}\n");
 }
 
 }  // namespace cpp

+ 0 - 1
src/google/protobuf/compiler/cpp/cpp_primitive_field.cc

@@ -38,7 +38,6 @@
 #include <google/protobuf/wire_format.h>
 #include <google/protobuf/stubs/strutil.h>
 
-
 namespace google {
 namespace protobuf {
 namespace compiler {

+ 103 - 70
src/google/protobuf/compiler/cpp/cpp_string_field.cc

@@ -39,7 +39,6 @@
 #include <google/protobuf/stubs/strutil.h>
 
 
-
 namespace google {
 namespace protobuf {
 namespace compiler {
@@ -197,6 +196,12 @@ void StringFieldGenerator::GenerateAccessorDeclarations(
           descriptor_);
     }
   }
+  format(
+      "private:\n"
+      "const std::string& _internal_$name$() const;\n"
+      "void _internal_set_$name$(const std::string& value);\n"
+      "std::string* _internal_mutable_$name$();\n"
+      "public:\n");
 
   if (unknown_ctype) {
     format.Outdent();
@@ -208,18 +213,31 @@ void StringFieldGenerator::GenerateAccessorDeclarations(
 void StringFieldGenerator::GenerateInlineAccessorDefinitions(
     io::Printer* printer) const {
   Formatter format(printer, variables_);
+  format(
+      "inline const std::string& $classname$::$name$() const {\n"
+      "$annotate_accessor$"
+      "  // @@protoc_insertion_point(field_get:$full_name$)\n"
+      "  return _internal_$name$();\n"
+      "}\n"
+      "inline void $classname$::set_$name$(const std::string& value) {\n"
+      "$annotate_accessor$"
+      "  _internal_set_$name$(value);\n"
+      "  // @@protoc_insertion_point(field_set:$full_name$)\n"
+      "}\n"
+      "inline std::string* $classname$::mutable_$name$() {\n"
+      "$annotate_accessor$"
+      "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+      "  return _internal_mutable_$name$();\n"
+      "}\n");
   if (SupportsArenas(descriptor_)) {
     format(
-        "inline const std::string& $classname$::$name$() const {\n"
-        "$annotate_accessor$"
-        "  // @@protoc_insertion_point(field_get:$full_name$)\n"
+        "inline const std::string& $classname$::_internal_$name$() const {\n"
         "  return $name$_.Get();\n"
         "}\n"
-        "inline void $classname$::set_$name$(const std::string& value) {\n"
-        "$annotate_accessor$"
+        "inline void $classname$::_internal_set_$name$(const std::string& "
+        "value) {\n"
         "  $set_hasbit$\n"
         "  $name$_.Set$lite$($default_variable$, value, GetArenaNoVirtual());\n"
-        "  // @@protoc_insertion_point(field_set:$full_name$)\n"
         "}\n"
         "inline void $classname$::set_$name$(std::string&& value) {\n"
         "$annotate_accessor$"
@@ -257,10 +275,8 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions(
         "GetArenaNoVirtual());\n"
         "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
         "}\n"
-        "inline std::string* $classname$::mutable_$name$() {\n"
-        "$annotate_accessor$"
+        "inline std::string* $classname$::_internal_mutable_$name$() {\n"
         "  $set_hasbit$\n"
-        "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
         "  return $name$_.Mutable($default_variable$, GetArenaNoVirtual());\n"
         "}\n"
         "inline std::string* $classname$::$release_name$() {\n"
@@ -324,16 +340,13 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions(
   } else {
     // No-arena case.
     format(
-        "inline const std::string& $classname$::$name$() const {\n"
-        "$annotate_accessor$"
-        "  // @@protoc_insertion_point(field_get:$full_name$)\n"
+        "inline const std::string& $classname$::_internal_$name$() const {\n"
         "  return $name$_.GetNoArena();\n"
         "}\n"
-        "inline void $classname$::set_$name$(const std::string& value) {\n"
-        "$annotate_accessor$"
+        "inline void $classname$::_internal_set_$name$(const std::string& "
+        "value) {\n"
         "  $set_hasbit$\n"
         "  $name$_.SetNoArena($default_variable$, value);\n"
-        "  // @@protoc_insertion_point(field_set:$full_name$)\n"
         "}\n"
         "inline void $classname$::set_$name$(std::string&& value) {\n"
         "$annotate_accessor$"
@@ -368,10 +381,8 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions(
         "      $string_piece$(reinterpret_cast<const char*>(value), size));\n"
         "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
         "}\n"
-        "inline std::string* $classname$::mutable_$name$() {\n"
-        "$annotate_accessor$"
+        "inline std::string* $classname$::_internal_mutable_$name$() {\n"
         "  $set_hasbit$\n"
-        "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
         "  return $name$_.MutableNoArena($default_variable$);\n"
         "}\n"
         "inline std::string* $classname$::$release_name$() {\n"
@@ -500,7 +511,7 @@ void StringFieldGenerator::GenerateMergingCode(io::Printer* printer) const {
   Formatter format(printer, variables_);
   if (SupportsArenas(descriptor_) || descriptor_->containing_oneof() != NULL) {
     // TODO(gpike): improve this
-    format("set_$name$(from.$name$());\n");
+    format("_internal_set_$name$(from._internal_$name$());\n");
   } else {
     format(
         "$set_hasbit$\n"
@@ -537,9 +548,9 @@ void StringFieldGenerator::GenerateCopyConstructorCode(
   GenerateConstructorCode(printer);
 
   if (HasFieldPresence(descriptor_->file())) {
-    format("if (from.has_$name$()) {\n");
+    format("if (from._internal_has_$name$()) {\n");
   } else {
-    format("if (!from.$name$().empty()) {\n");
+    format("if (!from._internal_$name$().empty()) {\n");
   }
 
   format.Indent();
@@ -547,7 +558,7 @@ void StringFieldGenerator::GenerateCopyConstructorCode(
   if (SupportsArenas(descriptor_) || descriptor_->containing_oneof() != NULL) {
     // TODO(gpike): improve this
     format(
-        "$name$_.Set$lite$($default_variable$, from.$name$(),\n"
+        "$name$_.Set$lite$($default_variable$, from._internal_$name$(),\n"
         "  GetArenaNoVirtual());\n");
   } else {
     format("$name$_.AssignWithDefault($default_variable$, from.$name$_);\n");
@@ -612,18 +623,19 @@ void StringFieldGenerator::GenerateMergeFromCodedStream(
         "  $name$_.UnsafeSetTaggedPointer(str);\n"
         "} else {\n"
         "  DO_(::$proto_ns$::internal::WireFormatLite::Read$declared_type$(\n"
-        "        input, this->mutable_$name$()));\n"
+        "        input, this->_internal_mutable_$name$()));\n"
         "}\n");
   } else {
     format(
         "DO_(::$proto_ns$::internal::WireFormatLite::Read$declared_type$(\n"
-        "      input, this->mutable_$name$()));\n");
+        "      input, this->_internal_mutable_$name$()));\n");
   }
 
   if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
     GenerateUtf8CheckCodeForString(
         descriptor_, options_, true,
-        "this->$name$().data(), static_cast<int>(this->$name$().length()),\n",
+        "this->_internal_$name$().data(), "
+        "static_cast<int>(this->_internal_$name$().length()),\n",
         format);
   }
 }
@@ -638,12 +650,13 @@ void StringFieldGenerator::GenerateSerializeWithCachedSizesToArray(
   if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
     GenerateUtf8CheckCodeForString(
         descriptor_, options_, false,
-        "this->$name$().data(), static_cast<int>(this->$name$().length()),\n",
+        "this->_internal_$name$().data(), "
+        "static_cast<int>(this->_internal_$name$().length()),\n",
         format);
   }
   format(
       "target = stream->Write$declared_type$MaybeAliased(\n"
-      "    $number$, this->$name$(), target);\n");
+      "    $number$, this->_internal_$name$(), target);\n");
 }
 
 void StringFieldGenerator::GenerateByteSize(io::Printer* printer) const {
@@ -651,7 +664,7 @@ void StringFieldGenerator::GenerateByteSize(io::Printer* printer) const {
   format(
       "total_size += $tag_size$ +\n"
       "  ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n"
-      "    this->$name$());\n");
+      "    this->_internal_$name$());\n");
 }
 
 uint32 StringFieldGenerator::CalculateFieldTag() const {
@@ -666,6 +679,13 @@ StringOneofFieldGenerator::StringOneofFieldGenerator(
   inlined_ = false;
 
   SetCommonOneofFieldVariables(descriptor, &variables_);
+  variables_["field_name"] = UnderscoresToCamelCase(descriptor->name(), true);
+  variables_["oneof_index"] =
+      StrCat(descriptor->containing_oneof()->index());
+  // has_$name$() for oneof fields is private if has_bit is not present. In that
+  // case, use _has_$name$() instead of _internal_has_$name$().
+  variables_["internal"] =
+      HasFieldPresence(descriptor->file()) ? "_internal_" : "";
 }
 
 StringOneofFieldGenerator::~StringOneofFieldGenerator() {}
@@ -673,26 +693,39 @@ StringOneofFieldGenerator::~StringOneofFieldGenerator() {}
 void StringOneofFieldGenerator::GenerateInlineAccessorDefinitions(
     io::Printer* printer) const {
   Formatter format(printer, variables_);
+  format(
+      "inline const std::string& $classname$::$name$() const {\n"
+      "$annotate_accessor$"
+      "  // @@protoc_insertion_point(field_get:$full_name$)\n"
+      "  return _internal_$name$();\n"
+      "}\n"
+      "inline void $classname$::set_$name$(const std::string& value) {\n"
+      "$annotate_accessor$"
+      "  _internal_set_$name$(value);\n"
+      "  // @@protoc_insertion_point(field_set:$full_name$)\n"
+      "}\n"
+      "inline std::string* $classname$::mutable_$name$() {\n"
+      "$annotate_accessor$"
+      "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+      "  return _internal_mutable_$name$();\n"
+      "}\n");
   if (SupportsArenas(descriptor_)) {
     format(
-        "inline const std::string& $classname$::$name$() const {\n"
-        "$annotate_accessor$"
-        "  // @@protoc_insertion_point(field_get:$full_name$)\n"
-        "  if (has_$name$()) {\n"
+        "inline const std::string& $classname$::_internal_$name$() const {\n"
+        "  if ($internal$has_$name$()) {\n"
         "    return $field_member$.Get();\n"
         "  }\n"
         "  return *$default_variable$;\n"
         "}\n"
-        "inline void $classname$::set_$name$(const std::string& value) {\n"
-        "$annotate_accessor$"
-        "  if (!has_$name$()) {\n"
+        "inline void $classname$::_internal_set_$name$(const std::string& "
+        "value) {\n"
+        "  if (!$internal$has_$name$()) {\n"
         "    clear_$oneof_name$();\n"
         "    set_has_$name$();\n"
         "    $field_member$.UnsafeSetDefault($default_variable$);\n"
         "  }\n"
         "  $field_member$.Set$lite$($default_variable$, value,\n"
         "      GetArenaNoVirtual());\n"
-        "  // @@protoc_insertion_point(field_set:$full_name$)\n"
         "}\n"
         "inline void $classname$::set_$name$(std::string&& value) {\n"
         "$annotate_accessor$"
@@ -748,16 +781,14 @@ void StringOneofFieldGenerator::GenerateInlineAccessorDefinitions(
         "      GetArenaNoVirtual());\n"
         "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
         "}\n"
-        "inline std::string* $classname$::mutable_$name$() {\n"
-        "$annotate_accessor$"
-        "  if (!has_$name$()) {\n"
+        "inline std::string* $classname$::_internal_mutable_$name$() {\n"
+        "  if (!$internal$has_$name$()) {\n"
         "    clear_$oneof_name$();\n"
         "    set_has_$name$();\n"
         "    $field_member$.UnsafeSetDefault($default_variable$);\n"
         "  }\n"
         "  return $field_member$.Mutable($default_variable$,\n"
         "      GetArenaNoVirtual());\n"
-        "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
         "}\n"
         "inline std::string* $classname$::$release_name$() {\n"
         "$annotate_accessor$"
@@ -816,24 +847,20 @@ void StringOneofFieldGenerator::GenerateInlineAccessorDefinitions(
   } else {
     // No-arena case.
     format(
-        "inline const std::string& $classname$::$name$() const {\n"
-        "$annotate_accessor$"
-        "  // @@protoc_insertion_point(field_get:$full_name$)\n"
-        "  if (has_$name$()) {\n"
+        "inline const std::string& $classname$::_internal_$name$() const {\n"
+        "  if ($internal$has_$name$()) {\n"
         "    return $field_member$.GetNoArena();\n"
         "  }\n"
         "  return *$default_variable$;\n"
         "}\n"
-        "inline void $classname$::set_$name$(const std::string& value) {\n"
-        "$annotate_accessor$"
-        "  // @@protoc_insertion_point(field_set:$full_name$)\n"
-        "  if (!has_$name$()) {\n"
+        "inline void $classname$::_internal_set_$name$(const std::string& "
+        "value) {\n"
+        "  if (!$internal$has_$name$()) {\n"
         "    clear_$oneof_name$();\n"
         "    set_has_$name$();\n"
         "    $field_member$.UnsafeSetDefault($default_variable$);\n"
         "  }\n"
         "  $field_member$.SetNoArena($default_variable$, value);\n"
-        "  // @@protoc_insertion_point(field_set:$full_name$)\n"
         "}\n"
         "inline void $classname$::set_$name$(std::string&& value) {\n"
         "$annotate_accessor$"
@@ -885,14 +912,12 @@ void StringOneofFieldGenerator::GenerateInlineAccessorDefinitions(
         "      reinterpret_cast<const char*>(value), size));\n"
         "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
         "}\n"
-        "inline std::string* $classname$::mutable_$name$() {\n"
-        "$annotate_accessor$"
-        "  if (!has_$name$()) {\n"
+        "inline std::string* $classname$::_internal_mutable_$name$() {\n"
+        "  if (!$internal$has_$name$()) {\n"
         "    clear_$oneof_name$();\n"
         "    set_has_$name$();\n"
         "    $field_member$.UnsafeSetDefault($default_variable$);\n"
         "  }\n"
-        "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
         "  return $field_member$.MutableNoArena($default_variable$);\n"
         "}\n"
         "inline std::string* $classname$::$release_name$() {\n"
@@ -979,18 +1004,19 @@ void StringOneofFieldGenerator::GenerateMergeFromCodedStream(
         "  $field_member$.UnsafeSetTaggedPointer(new_value);\n"
         "} else {\n"
         "  DO_(::$proto_ns$::internal::WireFormatLite::Read$declared_type$(\n"
-        "        input, this->mutable_$name$()));\n"
+        "        input, this->_internal_mutable_$name$()));\n"
         "}\n");
   } else {
     format(
         "DO_(::$proto_ns$::internal::WireFormatLite::Read$declared_type$(\n"
-        "      input, this->mutable_$name$()));\n");
+        "      input, this->_internal_mutable_$name$()));\n");
   }
 
   if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
     GenerateUtf8CheckCodeForString(
         descriptor_, options_, true,
-        "this->$name$().data(), static_cast<int>(this->$name$().length()),\n",
+        "this->_internal_$name$().data(), "
+        "static_cast<int>(this->_internal_$name$().length()),\n",
         format);
   }
 }
@@ -1064,7 +1090,10 @@ void RepeatedStringFieldGenerator::GenerateAccessorDeclarations(
       "const;\n"
       "$deprecated_attr$::$proto_ns$::RepeatedPtrField<std::string>* "
       "${1$mutable_$name$$}$()"
-      ";\n",
+      ";\n"
+      "private:\n"
+      "std::string* _internal_add_$name$();\n"
+      "public:\n",
       descriptor_);
 
   if (unknown_ctype) {
@@ -1077,6 +1106,12 @@ void RepeatedStringFieldGenerator::GenerateAccessorDeclarations(
 void RepeatedStringFieldGenerator::GenerateInlineAccessorDefinitions(
     io::Printer* printer) const {
   Formatter format(printer, variables_);
+  format(
+      "inline std::string* $classname$::add_$name$() {\n"
+      "$annotate_accessor$"
+      "  // @@protoc_insertion_point(field_add_mutable:$full_name$)\n"
+      "  return _internal_add_$name$();\n"
+      "}\n");
   if (options_.safe_boundary_check) {
     format(
         "inline const std::string& $classname$::$name$(int index) const {\n"
@@ -1135,9 +1170,7 @@ void RepeatedStringFieldGenerator::GenerateInlineAccessorDefinitions(
       "    reinterpret_cast<const char*>(value), size);\n"
       "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
       "}\n"
-      "inline std::string* $classname$::add_$name$() {\n"
-      "$annotate_accessor$"
-      "  // @@protoc_insertion_point(field_add_mutable:$full_name$)\n"
+      "inline std::string* $classname$::_internal_add_$name$() {\n"
       "  return $name$_.Add();\n"
       "}\n"
       "inline void $classname$::add_$name$(const std::string& value) {\n"
@@ -1200,7 +1233,7 @@ void RepeatedStringFieldGenerator::GenerateMergingCode(
 void RepeatedStringFieldGenerator::GenerateSwappingCode(
     io::Printer* printer) const {
   Formatter format(printer, variables_);
-  format("$name$_.InternalSwap(CastToBase(&other->$name$_));\n");
+  format("$name$_.InternalSwap(&other->$name$_);\n");
 }
 
 void RepeatedStringFieldGenerator::GenerateConstructorCode(
@@ -1219,12 +1252,12 @@ void RepeatedStringFieldGenerator::GenerateMergeFromCodedStream(
   Formatter format(printer, variables_);
   format(
       "DO_(::$proto_ns$::internal::WireFormatLite::Read$declared_type$(\n"
-      "      input, this->add_$name$()));\n");
+      "      input, this->_internal_add_$name$()));\n");
   if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
     GenerateUtf8CheckCodeForString(
         descriptor_, options_, true,
-        "this->$name$(this->$name$_size() - 1).data(),\n"
-        "static_cast<int>(this->$name$(this->$name$_size() - 1).length()),\n",
+        "$name$_.Get($name$_.size() - 1).data(),\n"
+        "static_cast<int>($name$_.Get($name$_.size() - 1).length()),\n",
         format);
   }
 }
@@ -1233,8 +1266,8 @@ void RepeatedStringFieldGenerator::GenerateSerializeWithCachedSizesToArray(
     io::Printer* printer) const {
   Formatter format(printer, variables_);
   format(
-      "for (auto it = this->$name$().pointer_begin(),\n"
-      "          end = this->$name$().pointer_end(); it < end; ++it) {\n"
+      "for (auto it = $field_member$.pointer_begin(),\n"
+      "          end = $field_member$.pointer_end(); it < end; ++it) {\n"
       "  const auto& s = **it;\n");
   // format("for (const std::string& s : this->$name$()) {\n");
   format.Indent();
@@ -1254,11 +1287,11 @@ void RepeatedStringFieldGenerator::GenerateByteSize(
   Formatter format(printer, variables_);
   format(
       "total_size += $tag_size$ *\n"
-      "    ::$proto_ns$::internal::FromIntSize(this->$name$_size());\n"
-      "for (int i = 0, n = this->$name$_size(); i < n; i++) {\n"
+      "    ::$proto_ns$::internal::FromIntSize($name$_.size());\n"
+      "for (int i = 0, n = $name$_.size(); i < n; i++) {\n"
       "  total_size += "
       "::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n"
-      "    this->$name$(i));\n"
+      "    $name$_.Get(i));\n"
       "}\n");
 }
 

+ 1 - 1
src/google/protobuf/compiler/csharp/csharp_doc_comment.cc

@@ -57,7 +57,7 @@ void WriteDocCommentBodyImpl(io::Printer* printer, SourceLocation location) {
     comments = StringReplace(comments, "&", "&amp;", true);
     comments = StringReplace(comments, "<", "&lt;", true);
     std::vector<string> lines;
-    SplitStringAllowEmpty(comments, "\n", &lines);
+    lines = Split(comments, "\n", false);
     // TODO: We really should work out which part to put in the summary and which to put in the remarks...
     // but that needs to be part of a bigger effort to understand the markdown better anyway.
     printer->Print("/// <summary>\n");

+ 1 - 1
src/google/protobuf/compiler/csharp/csharp_helpers.h

@@ -36,7 +36,7 @@
 #define GOOGLE_PROTOBUF_COMPILER_CSHARP_HELPERS_H__
 
 #include <string>
-#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/compiler/code_generator.h>

+ 1 - 1
src/google/protobuf/compiler/csharp/csharp_names.h

@@ -39,7 +39,7 @@
 #define GOOGLE_PROTOBUF_COMPILER_CSHARP_NAMES_H__
 
 #include <string>
-#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/common.h>
 
 #include <google/protobuf/port_def.inc>
 

+ 5 - 5
src/google/protobuf/compiler/csharp/csharp_reflection_class.cc

@@ -213,7 +213,7 @@ void ReflectionClassGenerator::WriteDescriptor(io::Printer* printer) {
     for (int i = 0; i < file_->extension_count(); i++) {
       extensions.push_back(GetFullExtensionName(file_->extension(i)));
     }
-    printer->Print("new pb::Extension[] { $extensions$ }, ", "extensions", JoinStrings(extensions, ", "));
+    printer->Print("new pb::Extension[] { $extensions$ }, ", "extensions", Join(extensions, ", "));
   }
   else {
     printer->Print("null, ");
@@ -264,7 +264,7 @@ void ReflectionClassGenerator::WriteGeneratedCodeInfo(const Descriptor* descript
       for (int i = 0; i < descriptor->field_count(); i++) {
           fields.push_back(GetPropertyName(descriptor->field(i)));
       }
-      printer->Print("new[]{ \"$fields$\" }, ", "fields", JoinStrings(fields, "\", \""));
+      printer->Print("new[]{ \"$fields$\" }, ", "fields", Join(fields, "\", \""));
   }
   else {
       printer->Print("null, ");
@@ -276,7 +276,7 @@ void ReflectionClassGenerator::WriteGeneratedCodeInfo(const Descriptor* descript
       for (int i = 0; i < descriptor->oneof_decl_count(); i++) {
           oneofs.push_back(UnderscoresToCamelCase(descriptor->oneof_decl(i)->name(), true));
       }
-      printer->Print("new[]{ \"$oneofs$\" }, ", "oneofs", JoinStrings(oneofs, "\", \""));
+      printer->Print("new[]{ \"$oneofs$\" }, ", "oneofs", Join(oneofs, "\", \""));
   }
   else {
       printer->Print("null, ");
@@ -288,7 +288,7 @@ void ReflectionClassGenerator::WriteGeneratedCodeInfo(const Descriptor* descript
       for (int i = 0; i < descriptor->enum_type_count(); i++) {
           enums.push_back(GetClassName(descriptor->enum_type(i)));
       }
-      printer->Print("new[]{ typeof($enums$) }, ", "enums", JoinStrings(enums, "), typeof("));
+      printer->Print("new[]{ typeof($enums$) }, ", "enums", Join(enums, "), typeof("));
   }
   else {
       printer->Print("null, ");
@@ -300,7 +300,7 @@ void ReflectionClassGenerator::WriteGeneratedCodeInfo(const Descriptor* descript
     for (int i = 0; i < descriptor->extension_count(); i++) {
       extensions.push_back(GetFullExtensionName(descriptor->extension(i)));
     }
-    printer->Print("new pb::Extension[] { $extensions$ }, ", "extensions", JoinStrings(extensions, ", "));
+    printer->Print("new pb::Extension[] { $extensions$ }, ", "extensions", Join(extensions, ", "));
   }
   else {
     printer->Print("null, ");

+ 1 - 4
src/google/protobuf/compiler/importer.cc

@@ -46,14 +46,11 @@
 #include <memory>
 
 #include <google/protobuf/compiler/importer.h>
-
 #include <google/protobuf/compiler/parser.h>
-#include <google/protobuf/io/io_win32.h>
 #include <google/protobuf/io/tokenizer.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 #include <google/protobuf/stubs/strutil.h>
-
-
+#include <google/protobuf/io/io_win32.h>
 
 #ifdef _WIN32
 #include <ctype.h>

+ 0 - 1
src/google/protobuf/compiler/java/java_context.cc

@@ -35,7 +35,6 @@
 #include <google/protobuf/compiler/java/java_name_resolver.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/stubs/strutil.h>
-
 #include <google/protobuf/stubs/map_util.h>
 
 namespace google {

+ 47 - 33
src/google/protobuf/compiler/java/java_doc_comment.cc

@@ -174,7 +174,8 @@ void WriteMessageDocComment(io::Printer* printer, const Descriptor* message) {
 
 void WriteFieldDocComment(io::Printer* printer, const FieldDescriptor* field) {
   // We start the comment with the main body based on the comments from the
-  // .proto file (if present). We then continue with the field declaration, e.g.:
+  // .proto file (if present). We then continue with the field declaration,
+  // e.g.:
   //   optional string foo = 5;
   // And then we end with the javadoc tags if applicable.
   // If the field is a group, the debug string might end with {.
@@ -185,17 +186,17 @@ void WriteFieldDocComment(io::Printer* printer, const FieldDescriptor* field) {
   printer->Print(" */\n");
 }
 
-void WriteFieldAccessorDocComment(io::Printer* printer, 
+void WriteFieldAccessorDocComment(io::Printer* printer,
                                   const FieldDescriptor* field,
                                   const FieldAccessorType type,
                                   const bool builder) {
   printer->Print("/**\n");
   WriteDocCommentBody(printer, field);
-  printer->Print(" * <code>$def$</code>\n", "def", 
+  printer->Print(" * <code>$def$</code>\n", "def",
                  EscapeJavadoc(FirstLineOf(field->DebugString())));
   switch (type) {
     case HAZZER:
-      printer->Print(" * @return Whether the $name$ field is set.\n", "name", 
+      printer->Print(" * @return Whether the $name$ field is set.\n", "name",
                      field->camelcase_name());
       break;
     case GETTER:
@@ -211,16 +212,16 @@ void WriteFieldAccessorDocComment(io::Printer* printer,
       break;
     // Repeated
     case LIST_COUNT:
-      printer->Print(" * @return The number of $name$(s).\n", "name",
-                 field->camelcase_name());
+      printer->Print(" * @return The count of $name$.\n", "name",
+                     field->camelcase_name());
       break;
     case LIST_GETTER:
-      printer->Print(" * @return A list containing the $name$(s).\n", "name",
+      printer->Print(" * @return A list containing the $name$.\n", "name",
                      field->camelcase_name());
       break;
     case LIST_INDEXED_GETTER:
       printer->Print(" * @param index The index of the element to return.\n");
-      printer->Print(" * @return The $name$(s) at the given index.\n", "name",
+      printer->Print(" * @return The $name$ at the given index.\n", "name",
                      field->camelcase_name());
       break;
     case LIST_INDEXED_SETTER:
@@ -233,8 +234,8 @@ void WriteFieldAccessorDocComment(io::Printer* printer,
                      field->camelcase_name());
       break;
     case LIST_MULTI_ADDER:
-      printer->Print(" * @param values The $name$(s) to add.\n", "name",
-                 field->camelcase_name());
+      printer->Print(" * @param values The $name$ to add.\n", "name",
+                     field->camelcase_name());
       break;
   }
   if (builder) {
@@ -243,25 +244,28 @@ void WriteFieldAccessorDocComment(io::Printer* printer,
   printer->Print(" */\n");
 }
 
-void WriteFieldEnumValueAccessorDocComment(io::Printer* printer, 
+void WriteFieldEnumValueAccessorDocComment(io::Printer* printer,
                                            const FieldDescriptor* field,
                                            const FieldAccessorType type,
                                            const bool builder) {
   printer->Print("/**\n");
   WriteDocCommentBody(printer, field);
-  printer->Print(" * <code>$def$</code>\n", "def", 
+  printer->Print(" * <code>$def$</code>\n", "def",
                  EscapeJavadoc(FirstLineOf(field->DebugString())));
   switch (type) {
     case HAZZER:
       // Should never happen
       break;
     case GETTER:
-      printer->Print(" * @return The enum value for $name$.\n", "name",
-                 field->camelcase_name());
+      printer->Print(
+          " * @return The enum numeric value on the wire for $name$.\n", "name",
+          field->camelcase_name());
       break;
     case SETTER:
-      printer->Print(" * @param value The enum value for $name$ to set.\n",
-                     "name", field->camelcase_name());
+      printer->Print(
+          " * @param value The enum numeric value on the wire for $name$ to "
+          "set.\n",
+          "name", field->camelcase_name());
       break;
     case CLEARER:
       // Print nothing
@@ -271,26 +275,36 @@ void WriteFieldEnumValueAccessorDocComment(io::Printer* printer,
       // Should never happen
       break;
     case LIST_GETTER:
-      printer->Print(" * @return A list containing the enum values for "
-                     "$name$(s).\n", "name", field->camelcase_name());
+      printer->Print(
+          " * @return A list containing the enum numeric values on the wire "
+          "for $name$.\n",
+          "name", field->camelcase_name());
       break;
     case LIST_INDEXED_GETTER:
       printer->Print(" * @param index The index of the value to return.\n");
-      printer->Print(" * @return The enum value of the $name$ at the given "
-                     "index.\n", "name", field->camelcase_name());
+      printer->Print(
+          " * @return The enum numeric value on the wire of $name$ at the "
+          "given index.\n",
+          "name", field->camelcase_name());
       break;
     case LIST_INDEXED_SETTER:
       printer->Print(" * @param index The index to set the value at.\n");
-      printer->Print(" * @param value The enum value of the $name$ to set.\n",
-                     "name", field->camelcase_name());
+      printer->Print(
+          " * @param value The enum numeric value on the wire for $name$ to "
+          "set.\n",
+          "name", field->camelcase_name());
       break;
     case LIST_ADDER:
-      printer->Print(" * @param value The enum value of the $name$ to add.\n",
-                     "name", field->camelcase_name());
+      printer->Print(
+          " * @param value The enum numeric value on the wire for $name$ to "
+          "add.\n",
+          "name", field->camelcase_name());
       break;
     case LIST_MULTI_ADDER:
-      printer->Print(" * @param values The enum values of the $name$(s) to "
-                     "add.\n", "name", field->camelcase_name());
+      printer->Print(
+          " * @param values The enum numeric values on the wire for $name$ to "
+          "add.\n",
+          "name", field->camelcase_name());
       break;
   }
   if (builder) {
@@ -299,13 +313,13 @@ void WriteFieldEnumValueAccessorDocComment(io::Printer* printer,
   printer->Print(" */\n");
 }
 
-void WriteFieldStringBytesAccessorDocComment(io::Printer* printer, 
+void WriteFieldStringBytesAccessorDocComment(io::Printer* printer,
                                              const FieldDescriptor* field,
                                              const FieldAccessorType type,
                                              const bool builder) {
   printer->Print("/**\n");
   WriteDocCommentBody(printer, field);
-  printer->Print(" * <code>$def$</code>\n", "def", 
+  printer->Print(" * <code>$def$</code>\n", "def",
                  EscapeJavadoc(FirstLineOf(field->DebugString())));
   switch (type) {
     case HAZZER:
@@ -313,11 +327,11 @@ void WriteFieldStringBytesAccessorDocComment(io::Printer* printer,
       break;
     case GETTER:
       printer->Print(" * @return The bytes for $name$.\n", "name",
-                 field->camelcase_name());
+                     field->camelcase_name());
       break;
     case SETTER:
-      printer->Print(" * @param value The bytes for $name$ to set.\n",
-                     "name", field->camelcase_name());
+      printer->Print(" * @param value The bytes for $name$ to set.\n", "name",
+                     field->camelcase_name());
       break;
     case CLEARER:
       // Print nothing
@@ -327,7 +341,7 @@ void WriteFieldStringBytesAccessorDocComment(io::Printer* printer,
       // Should never happen
       break;
     case LIST_GETTER:
-      printer->Print(" * @return A list containing the bytes for $name$(s).\n",
+      printer->Print(" * @return A list containing the bytes for $name$.\n",
                      "name", field->camelcase_name());
       break;
     case LIST_INDEXED_GETTER:
@@ -345,7 +359,7 @@ void WriteFieldStringBytesAccessorDocComment(io::Printer* printer,
                      "name", field->camelcase_name());
       break;
     case LIST_MULTI_ADDER:
-      printer->Print(" * @param values The bytes of the $name$(s) to add.\n",
+      printer->Print(" * @param values The bytes of the $name$ to add.\n",
                      "name", field->camelcase_name());
       break;
   }

+ 20 - 22
src/google/protobuf/compiler/java/java_doc_comment.h

@@ -53,35 +53,33 @@ namespace compiler {
 namespace java {
 
 enum FieldAccessorType {
-
-    HAZZER,
-    GETTER,
-    SETTER,
-    CLEARER,
-    // Repeated
-    LIST_COUNT,
-    LIST_GETTER,
-    LIST_INDEXED_GETTER,
-    LIST_INDEXED_SETTER,
-    LIST_ADDER,
-    LIST_MULTI_ADDER
-
+  HAZZER,
+  GETTER,
+  SETTER,
+  CLEARER,
+  // Repeated
+  LIST_COUNT,
+  LIST_GETTER,
+  LIST_INDEXED_GETTER,
+  LIST_INDEXED_SETTER,
+  LIST_ADDER,
+  LIST_MULTI_ADDER
 };
 
 void WriteMessageDocComment(io::Printer* printer, const Descriptor* message);
 void WriteFieldDocComment(io::Printer* printer, const FieldDescriptor* field);
 void WriteFieldAccessorDocComment(io::Printer* printer,
-                                const FieldDescriptor* field,
-                                const FieldAccessorType type,
-                                const bool builder = false);
+                                  const FieldDescriptor* field,
+                                  const FieldAccessorType type,
+                                  const bool builder = false);
 void WriteFieldEnumValueAccessorDocComment(io::Printer* printer,
-                                const FieldDescriptor* field,
-                                const FieldAccessorType type,
-                                const bool builder = false);
+                                           const FieldDescriptor* field,
+                                           const FieldAccessorType type,
+                                           const bool builder = false);
 void WriteFieldStringBytesAccessorDocComment(io::Printer* printer,
-                                const FieldDescriptor* field,
-                                const FieldAccessorType type,
-                                const bool builder = false);
+                                             const FieldDescriptor* field,
+                                             const FieldAccessorType type,
+                                             const bool builder = false);
 void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_);
 void WriteEnumValueDocComment(io::Printer* printer,
                               const EnumValueDescriptor* value);

+ 8 - 3
src/google/protobuf/compiler/java/java_enum.cc

@@ -44,7 +44,6 @@
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/stubs/strutil.h>
 
-
 namespace google {
 namespace protobuf {
 namespace compiler {
@@ -175,8 +174,9 @@ void EnumGenerator::Generate(io::Printer* printer) {
       "}\n"
       "\n"
       "/**\n"
-      " * @param value The number of the enum to look for.\n"
-      " * @return The enum associated with the given number.\n"
+      " * @param value The numeric wire value of the corresponding enum "
+      "entry.\n"
+      " * @return The enum associated with the given numeric wire value.\n"
       " * @deprecated Use {@link #forNumber(int)} instead.\n"
       " */\n"
       "@java.lang.Deprecated\n"
@@ -184,6 +184,11 @@ void EnumGenerator::Generate(io::Printer* printer) {
       "  return forNumber(value);\n"
       "}\n"
       "\n"
+      "/**\n"
+      " * @param value The numeric wire value of the corresponding enum "
+      "entry.\n"
+      " * @return The enum associated with the given numeric wire value.\n"
+      " */\n"
       "public static $classname$ forNumber(int value) {\n"
       "  switch (value) {\n",
       "classname", descriptor_->name());

+ 1 - 2
src/google/protobuf/compiler/java/java_enum_field.cc

@@ -46,7 +46,6 @@
 #include <google/protobuf/wire_format.h>
 #include <google/protobuf/stubs/strutil.h>
 
-
 namespace google {
 namespace protobuf {
 namespace compiler {
@@ -221,7 +220,7 @@ void ImmutableEnumFieldGenerator::GenerateBuilderMembers(
         "}\n");
     printer->Annotate("{", "}", descriptor_);
     WriteFieldEnumValueAccessorDocComment(printer, descriptor_, SETTER,
-                               /* builder */ true);
+                                          /* builder */ true);
     printer->Print(variables_,
                    "$deprecation$public Builder "
                    "${$set$capitalized_name$Value$}$(int value) {\n"

+ 0 - 1
src/google/protobuf/compiler/java/java_enum_field_lite.cc

@@ -46,7 +46,6 @@
 #include <google/protobuf/wire_format.h>
 #include <google/protobuf/stubs/strutil.h>
 
-
 namespace google {
 namespace protobuf {
 namespace compiler {

+ 0 - 1
src/google/protobuf/compiler/java/java_enum_lite.cc

@@ -43,7 +43,6 @@
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/stubs/strutil.h>
-
 #include <google/protobuf/stubs/map_util.h>
 
 namespace google {

+ 0 - 1
src/google/protobuf/compiler/java/java_extension.cc

@@ -41,7 +41,6 @@
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/stubs/strutil.h>
 
-
 namespace google {
 namespace protobuf {
 namespace compiler {

+ 0 - 1
src/google/protobuf/compiler/java/java_field.cc

@@ -55,7 +55,6 @@
 #include <google/protobuf/stubs/substitute.h>
 
 
-
 namespace google {
 namespace protobuf {
 namespace compiler {

+ 0 - 1
src/google/protobuf/compiler/java/java_file.cc

@@ -54,7 +54,6 @@
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/stubs/strutil.h>
 
-
 namespace google {
 namespace protobuf {
 namespace compiler {

+ 0 - 3
src/google/protobuf/compiler/java/java_helpers.cc

@@ -44,9 +44,6 @@
 #include <google/protobuf/wire_format.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
-
-
-
 #include <google/protobuf/stubs/hash.h>  // for hash<T *>
 
 namespace google {

+ 0 - 2
src/google/protobuf/compiler/java/java_message.cc

@@ -55,8 +55,6 @@
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
 
-
-
 namespace google {
 namespace protobuf {
 namespace compiler {

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác