浏览代码

Merge tag 'refs/tags/sync-piper' into sync-stage

Joshua Haberman 5 年之前
父节点
当前提交
820d1ca5af
共有 100 个文件被更改,包括 1157 次插入634 次删除
  1. 2 2
      .github/mergeable.yml
  2. 1 1
      .github/workflows/codespell.yml
  3. 25 3
      BUILD
  4. 2 2
      WORKSPACE
  5. 0 8
      conformance/text_format_failure_list_java.txt
  6. 9 8
      java/core/src/main/java/com/google/protobuf/CodedInputStream.java
  7. 4 1
      java/core/src/main/java/com/google/protobuf/Descriptors.java
  8. 0 2
      java/core/src/main/java/com/google/protobuf/ExtensionRegistryFactory.java
  9. 0 2
      java/core/src/main/java/com/google/protobuf/ExtensionRegistryLite.java
  10. 0 2
      java/core/src/main/java/com/google/protobuf/FieldType.java
  11. 4 3
      java/core/src/main/java/com/google/protobuf/NioByteString.java
  12. 69 0
      java/core/src/main/java/com/google/protobuf/TextFormat.java
  13. 0 1
      java/core/src/main/java/com/google/protobuf/TypeRegistry.java
  14. 14 7
      java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
  15. 83 82
      java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
  16. 59 59
      java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
  17. 90 89
      java/core/src/test/java/com/google/protobuf/MapLiteTest.java
  18. 96 94
      java/core/src/test/java/com/google/protobuf/MapTest.java
  19. 88 0
      java/core/src/test/java/com/google/protobuf/TextFormatTest.java
  20. 42 26
      java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java
  21. 7 1
      java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java
  22. 0 1
      java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
  23. 18 6
      java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java
  24. 1 1
      java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java
  25. 2 2
      java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
  26. 9 1
      kokoro/linux/dockerfile/test/python27/Dockerfile
  27. 9 1
      kokoro/linux/dockerfile/test/python35/Dockerfile
  28. 9 1
      kokoro/linux/dockerfile/test/python36/Dockerfile
  29. 9 1
      kokoro/linux/dockerfile/test/python37/Dockerfile
  30. 9 1
      kokoro/linux/dockerfile/test/python38/Dockerfile
  31. 1 1
      kokoro/linux/python27/continuous.cfg
  32. 1 1
      kokoro/linux/python27/presubmit.cfg
  33. 1 1
      kokoro/linux/python27_cpp/continuous.cfg
  34. 1 1
      kokoro/linux/python27_cpp/presubmit.cfg
  35. 1 1
      kokoro/linux/python35/continuous.cfg
  36. 1 1
      kokoro/linux/python35/presubmit.cfg
  37. 1 1
      kokoro/linux/python35_cpp/continuous.cfg
  38. 1 1
      kokoro/linux/python35_cpp/presubmit.cfg
  39. 1 1
      kokoro/linux/python36/continuous.cfg
  40. 1 1
      kokoro/linux/python36/presubmit.cfg
  41. 1 1
      kokoro/linux/python36_cpp/continuous.cfg
  42. 1 1
      kokoro/linux/python36_cpp/presubmit.cfg
  43. 1 1
      kokoro/linux/python37/continuous.cfg
  44. 1 1
      kokoro/linux/python37/presubmit.cfg
  45. 1 1
      kokoro/linux/python37_cpp/continuous.cfg
  46. 1 1
      kokoro/linux/python37_cpp/presubmit.cfg
  47. 1 1
      kokoro/linux/python38/continuous.cfg
  48. 1 1
      kokoro/linux/python38/presubmit.cfg
  49. 1 1
      kokoro/linux/python38_cpp/continuous.cfg
  50. 1 1
      kokoro/linux/python38_cpp/presubmit.cfg
  51. 0 11
      kokoro/macos/php5.6_mac/build.sh
  52. 0 5
      kokoro/macos/php5.6_mac/continuous.cfg
  53. 0 5
      kokoro/macos/php5.6_mac/presubmit.cfg
  54. 2 2
      php/ext/google/protobuf/message.c
  55. 17 3
      php/ext/google/protobuf/package.xml
  56. 2 2
      php/ext/google/protobuf/protobuf.h
  57. 2 2
      php/release.sh
  58. 1 1
      python/google/protobuf/pyext/message.cc
  59. 2 1
      python/google/protobuf/text_format.py
  60. 16 1
      python/protobuf_distutils/README.md
  61. 4 1
      python/tox.ini
  62. 2 1
      src/google/protobuf/any.h
  63. 0 3
      src/google/protobuf/any_lite.cc
  64. 8 0
      src/google/protobuf/any_test.cc
  65. 28 6
      src/google/protobuf/arena.cc
  66. 3 1
      src/google/protobuf/arena.h
  67. 29 6
      src/google/protobuf/arena_impl.h
  68. 15 10
      src/google/protobuf/arenastring.h
  69. 3 0
      src/google/protobuf/arenastring_unittest.cc
  70. 5 1
      src/google/protobuf/compiler/command_line_interface_unittest.cc
  71. 0 4
      src/google/protobuf/compiler/cpp/cpp_field.h
  72. 0 1
      src/google/protobuf/compiler/cpp/cpp_file.cc
  73. 0 7
      src/google/protobuf/compiler/cpp/cpp_message.cc
  74. 0 3
      src/google/protobuf/compiler/cpp/cpp_message.h
  75. 1 0
      src/google/protobuf/compiler/java/java_file.cc
  76. 1 0
      src/google/protobuf/compiler/java/java_file.h
  77. 58 12
      src/google/protobuf/compiler/java/java_name_resolver.cc
  78. 18 0
      src/google/protobuf/compiler/java/java_name_resolver.h
  79. 1 0
      src/google/protobuf/compiler/main.cc
  80. 6 0
      src/google/protobuf/compiler/parser_unittest.cc
  81. 62 52
      src/google/protobuf/descriptor.cc
  82. 9 11
      src/google/protobuf/descriptor_database.cc
  83. 30 5
      src/google/protobuf/descriptor_unittest.cc
  84. 0 8
      src/google/protobuf/extension_set.cc
  85. 4 1
      src/google/protobuf/extension_set.h
  86. 8 1
      src/google/protobuf/extension_set_unittest.cc
  87. 1 0
      src/google/protobuf/generated_message_reflection.cc
  88. 13 4
      src/google/protobuf/generated_message_util.cc
  89. 11 1
      src/google/protobuf/generated_message_util.h
  90. 1 1
      src/google/protobuf/has_bits.h
  91. 1 1
      src/google/protobuf/implicit_weak_message.h
  92. 6 5
      src/google/protobuf/map.h
  93. 1 1
      src/google/protobuf/map_entry.h
  94. 10 11
      src/google/protobuf/map_entry_lite.h
  95. 22 0
      src/google/protobuf/map_field.h
  96. 1 1
      src/google/protobuf/map_field_lite.h
  97. 19 0
      src/google/protobuf/map_field_test.cc
  98. 39 0
      src/google/protobuf/map_test.cc
  99. 13 13
      src/google/protobuf/map_type_handler.h
  100. 1 1
      src/google/protobuf/message.cc

+ 2 - 2
.github/mergeable.yml

@@ -11,8 +11,8 @@ mergeable:
                 regex: 'release notes: yes'
                 message: 'Please include release notes: yes'
             - must_include:
-                regex: '^(c#|c\+\+|cleanup|conformance tests|integration|java|javascript|go|objective-c|php|python|ruby|bazel)'
-                message: 'Please include at least a language label (e.g., c++, java, python). Or apply one of the following labels: bazel, cleanup, conformance tests, integration.'
+                regex: '^(c#|c\+\+|cleanup|conformance tests|integration|java|javascript|go|objective-c|php|python|ruby|bazel|cmake|protoc)'
+                message: 'Please include at least a language label (e.g., c++, java, python). Or apply one of the following labels: bazel, cmake, cleanup, conformance tests, integration, protoc.'
           - must_include:
               regex: 'release notes: no'
               message: 'Please include release notes: no'

+ 1 - 1
.github/workflows/codespell.yml

@@ -13,4 +13,4 @@ jobs:
         with:
           check_filenames: true
           skip: ./.git,./conformance/third_party,*.snk,*.pb,*.pb.cc,*.pb.h,./src/google/protobuf/testdata,./objectivec/Tests,./python/compatibility_tests/v2.5.0/tests/google/protobuf/internal
-          ignore_words_list: "alow,alse,ba,cleare,copyable,cloneable,dedup,dur,errorprone,fo,fundementals,hel,importd,inout,leapyear,nd,ois,ons,parseable,process',te,testof,ue,unparseable,wasn,wee,gae,keyserver,objext,od"
+          ignore_words_list: "alow,alse,ba,cleare,copyable,cloneable,dedup,dur,errorprone,files',fo,fundementals,hel,importd,inout,leapyear,nd,ois,ons,parseable,process',te,testof,ue,unparseable,wasn,wee,gae,keyserver,objext,od"

+ 25 - 3
BUILD

@@ -14,10 +14,10 @@ exports_files(["LICENSE"])
 # build configuration
 ################################################################################
 
+# TODO(yannic): Remove in 3.14.0.
 string_flag(
     name = "incompatible_use_com_google_googletest",
-    # TODO(yannic): Flip to `true` for `3.13.0`.
-    build_setting_default = "false",
+    build_setting_default = "true",
     values = ["true", "false"]
 )
 
@@ -369,7 +369,15 @@ cc_library(
 
 cc_proto_blacklist_test(
     name = "cc_proto_blacklist_test",
-    deps = [proto + "_cc_proto" for proto in WELL_KNOWN_PROTO_MAP.keys()]
+    deps = [proto + "_cc_proto" for proto in WELL_KNOWN_PROTO_MAP.keys()],
+    tags = [
+        # Exclude this target from wildcard expansion (//...). Due to
+        # https://github.com/bazelbuild/bazel/issues/10590, this test has to
+        # be nominated using the `@com_google_protobuf//` prefix. We do that,
+        # e.g., in kokoro/linux/bazel/build.sh.
+        # See also https://github.com/protocolbuffers/protobuf/pull/7096.
+        "manual",
+    ],
 )
 
 ################################################################################
@@ -757,6 +765,13 @@ cc_binary(
     copts = COPTS + [
         "-DPYTHON_PROTO2_CPP_IMPL_V2",
     ],
+    tags = [
+        # Exclude this target from wildcard expansion (//...) because it may
+        # not even be buildable. It will be built if it is needed according
+        # to :use_fast_cpp_protos.
+        # https://docs.bazel.build/versions/master/be/common-definitions.html#common-attributes
+        "manual",
+    ],
     linkshared = 1,
     linkstatic = 1,
     deps = select({
@@ -781,6 +796,13 @@ cc_binary(
         "python/",
         "src/",
     ],
+    tags = [
+        # Exclude this target from wildcard expansion (//...) because it may
+        # not even be buildable. It will be built if it is needed according
+        # to :use_fast_cpp_protos.
+        # https://docs.bazel.build/versions/master/be/common-definitions.html#common-attributes
+        "manual",
+    ],
     linkshared = 1,
     linkstatic = 1,
     deps = [

+ 2 - 2
WORKSPACE

@@ -29,13 +29,13 @@ bind(
     actual = "//util/python:python_headers",
 )
 
-# TODO(yannic): Remove in 3.13.0.
+# TODO(yannic): Remove in 3.14.0.
 bind(
     name = "gtest",
     actual = "@com_google_googletest//:gtest",
 )
 
-# TODO(yannic): Remove in 3.13.0.
+# TODO(yannic): Remove in 3.14.0.
 bind(
     name = "gtest_main",
     actual = "@com_google_googletest//:gtest_main",

+ 0 - 8
conformance/text_format_failure_list_java.txt

@@ -5,14 +5,6 @@ Recommended.Proto3.ProtobufInput.ScalarUnknownFields_Drop.TextFormatOutput
 Required.Proto3.TextFormatInput.AnyField.ProtobufOutput
 Required.Proto3.TextFormatInput.AnyField.TextFormatOutput
 
-Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapesBytes.ProtobufOutput
-Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapesBytes.TextFormatOutput
-Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapesString.ProtobufOutput
-Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapesString.TextFormatOutput
-Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeBytes.ProtobufOutput
-Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeBytes.TextFormatOutput
-Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeString.ProtobufOutput
-Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeString.TextFormatOutput
 Required.Proto3.TextFormatInput.StringFieldBadUTF8Hex
 Required.Proto3.TextFormatInput.StringFieldBadUTF8Octal
 Required.Proto3.TextFormatInput.StringLiteralBasicEscapesBytes.ProtobufOutput

+ 9 - 8
java/core/src/main/java/com/google/protobuf/CodedInputStream.java

@@ -41,6 +41,7 @@ import static com.google.protobuf.WireFormat.MAX_VARINT_SIZE;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.Buffer;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -2009,14 +2010,14 @@ public abstract class CodedInputStream {
       int prevPos = buffer.position();
       int prevLimit = buffer.limit();
       try {
-        buffer.position(bufferPos(begin));
-        buffer.limit(bufferPos(end));
+        ((Buffer) buffer).position(bufferPos(begin));
+        ((Buffer) buffer).limit(bufferPos(end));
         return buffer.slice();
       } catch (IllegalArgumentException e) {
         throw InvalidProtocolBufferException.truncatedMessage();
       } finally {
-        buffer.position(prevPos);
-        buffer.limit(prevLimit);
+        ((Buffer) buffer).position(prevPos);
+        ((Buffer) buffer).limit(prevLimit);
       }
     }
   }
@@ -3910,14 +3911,14 @@ public abstract class CodedInputStream {
       int prevPos = currentByteBuffer.position();
       int prevLimit = currentByteBuffer.limit();
       try {
-        currentByteBuffer.position(begin);
-        currentByteBuffer.limit(end);
+        ((Buffer) currentByteBuffer).position(begin);
+        ((Buffer) currentByteBuffer).limit(end);
         return currentByteBuffer.slice();
       } catch (IllegalArgumentException e) {
         throw InvalidProtocolBufferException.truncatedMessage();
       } finally {
-        currentByteBuffer.position(prevPos);
-        currentByteBuffer.limit(prevLimit);
+        ((Buffer) currentByteBuffer).position(prevPos);
+        ((Buffer) currentByteBuffer).limit(prevLimit);
       }
     }
   }

+ 4 - 1
java/core/src/main/java/com/google/protobuf/Descriptors.java

@@ -764,7 +764,10 @@ public final class Descriptors {
     /**
      * Finds a field by name.
      *
-     * @param name The unqualified name of the field (e.g. "foo").
+     * @param name The unqualified name of the field (e.g. "foo"). For protocol buffer messages that
+     *     follow <a
+     *     href=https://developers.google.com/protocol-buffers/docs/style#message_and_field_names>Google's
+     *     guidance on naming</a> this will be a snake case string, such as <pre>song_name</pre>.
      * @return The field's descriptor, or {@code null} if not found.
      */
     public FieldDescriptor findFieldByName(final String name) {

+ 0 - 2
java/core/src/main/java/com/google/protobuf/ExtensionRegistryFactory.java

@@ -46,7 +46,6 @@ final class ExtensionRegistryFactory {
   @Nullable */
   static final Class<?> EXTENSION_REGISTRY_CLASS = reflectExtensionRegistry();
 
-  /* @Nullable */
   static Class<?> reflectExtensionRegistry() {
     try {
       return Class.forName(FULL_REGISTRY_CLASS_NAME);
@@ -77,7 +76,6 @@ final class ExtensionRegistryFactory {
         && EXTENSION_REGISTRY_CLASS.isAssignableFrom(registry.getClass());
   }
 
-  /* @Nullable */
   private static final ExtensionRegistryLite invokeSubclassFactory(String methodName) {
     if (EXTENSION_REGISTRY_CLASS == null) {
       return null;

+ 0 - 2
java/core/src/main/java/com/google/protobuf/ExtensionRegistryLite.java

@@ -84,10 +84,8 @@ public class ExtensionRegistryLite {
   static final String EXTENSION_CLASS_NAME = "com.google.protobuf.Extension";
 
   private static class ExtensionClassHolder {
-    /* @Nullable */
     static final Class<?> INSTANCE = resolveExtensionClass();
 
-    /* @Nullable */
     static Class<?> resolveExtensionClass() {
       try {
         return Class.forName(EXTENSION_CLASS_NAME);

+ 0 - 2
java/core/src/main/java/com/google/protobuf/FieldType.java

@@ -204,7 +204,6 @@ public enum FieldType {
    *
    * @return the {@link FieldType} or {@code null} if not found.
    */
-  /* @Nullable */
   public static FieldType forId(int id) {
     if (id < 0 || id >= VALUES.length) {
       return null;
@@ -228,7 +227,6 @@ public enum FieldType {
    *
    * @return the generic super class/interface, or {@code null} if not found.
    */
-  /* @Nullable */
   private static Type getGenericSuperList(Class<?> clazz) {
     // First look at interfaces.
     Type[] genericInterfaces = clazz.getGenericInterfaces();

+ 4 - 3
java/core/src/main/java/com/google/protobuf/NioByteString.java

@@ -37,6 +37,7 @@ import java.io.InputStream;
 import java.io.InvalidObjectException;
 import java.io.ObjectInputStream;
 import java.io.OutputStream;
+import java.nio.Buffer;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.InvalidMarkException;
@@ -109,7 +110,7 @@ final class NioByteString extends ByteString.LeafByteString {
   protected void copyToInternal(
       byte[] target, int sourceOffset, int targetOffset, int numberToCopy) {
     ByteBuffer slice = buffer.slice();
-    slice.position(sourceOffset);
+    ((Buffer) slice).position(sourceOffset);
     slice.get(target, targetOffset, numberToCopy);
   }
 
@@ -285,8 +286,8 @@ final class NioByteString extends ByteString.LeafByteString {
     }
 
     ByteBuffer slice = buffer.slice();
-    slice.position(beginIndex - buffer.position());
-    slice.limit(endIndex - buffer.position());
+    ((Buffer) slice).position(beginIndex - buffer.position());
+    ((Buffer) slice).limit(endIndex - buffer.position());
     return slice;
   }
 }

+ 69 - 0
java/core/src/main/java/com/google/protobuf/TextFormat.java

@@ -30,6 +30,8 @@
 
 package com.google.protobuf;
 
+import static java.nio.charset.StandardCharsets.UTF_8;
+
 import com.google.protobuf.Descriptors.Descriptor;
 import com.google.protobuf.Descriptors.EnumDescriptor;
 import com.google.protobuf.Descriptors.EnumValueDescriptor;
@@ -2375,6 +2377,73 @@ public final class TextFormat {
                 result[pos++] = (byte) code;
                 break;
 
+              case 'u':
+                // Unicode escape
+                ++i;
+                if (i + 3 < input.size()
+                    && isHex(input.byteAt(i))
+                    && isHex(input.byteAt(i + 1))
+                    && isHex(input.byteAt(i + 2))
+                    && isHex(input.byteAt(i + 3))) {
+                  char ch =
+                      (char)
+                          (digitValue(input.byteAt(i)) << 12
+                              | digitValue(input.byteAt(i + 1)) << 8
+                              | digitValue(input.byteAt(i + 2)) << 4
+                              | digitValue(input.byteAt(i + 3)));
+                  if (Character.isSurrogate(ch)) {
+                    throw new InvalidEscapeSequenceException(
+                        "Invalid escape sequence: '\\u' refers to a surrogate");
+                  }
+                  byte[] chUtf8 = Character.toString(ch).getBytes(UTF_8);
+                  System.arraycopy(chUtf8, 0, result, pos, chUtf8.length);
+                  pos += chUtf8.length;
+                  i += 3;
+                } else {
+                  throw new InvalidEscapeSequenceException(
+                      "Invalid escape sequence: '\\u' with too few hex chars");
+                }
+                break;
+
+              case 'U':
+                // Unicode escape
+                ++i;
+                if (i + 7 >= input.size()) {
+                  throw new InvalidEscapeSequenceException(
+                      "Invalid escape sequence: '\\U' with too few hex chars");
+                }
+                int codepoint = 0;
+                for (int offset = i; offset < i + 8; offset++) {
+                  byte b = input.byteAt(offset);
+                  if (!isHex(b)) {
+                    throw new InvalidEscapeSequenceException(
+                        "Invalid escape sequence: '\\U' with too few hex chars");
+                  }
+                  codepoint = (codepoint << 4) | digitValue(b);
+                }
+                if (!Character.isValidCodePoint(codepoint)) {
+                  throw new InvalidEscapeSequenceException(
+                      "Invalid escape sequence: '\\U"
+                          + input.substring(i, i + 8).toStringUtf8()
+                          + "' is not a valid code point value");
+                }
+                Character.UnicodeBlock unicodeBlock = Character.UnicodeBlock.of(codepoint);
+                if (unicodeBlock.equals(Character.UnicodeBlock.LOW_SURROGATES)
+                    || unicodeBlock.equals(Character.UnicodeBlock.HIGH_SURROGATES)
+                    || unicodeBlock.equals(Character.UnicodeBlock.HIGH_PRIVATE_USE_SURROGATES)) {
+                  throw new InvalidEscapeSequenceException(
+                      "Invalid escape sequence: '\\U"
+                          + input.substring(i, i + 8).toStringUtf8()
+                          + "' refers to a surrogate code unit");
+                }
+                int[] codepoints = new int[1];
+                codepoints[0] = codepoint;
+                byte[] chUtf8 = new String(codepoints, 0, 1).getBytes(UTF_8);
+                System.arraycopy(chUtf8, 0, result, pos, chUtf8.length);
+                pos += chUtf8.length;
+                i += 7;
+                break;
+
               default:
                 throw new InvalidEscapeSequenceException(
                     "Invalid escape sequence: '\\" + (char) c + '\'');

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

@@ -70,7 +70,6 @@ public class TypeRegistry {
   /**
    * 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));

+ 14 - 7
java/core/src/main/java/com/google/protobuf/UnsafeUtil.java

@@ -41,7 +41,6 @@ import java.util.logging.Logger;
 
 /** Utility class for working with unsafe operations. */
 final class UnsafeUtil {
-  private static final Logger logger = Logger.getLogger(UnsafeUtil.class.getName());
   private static final sun.misc.Unsafe UNSAFE = getUnsafe();
   private static final Class<?> MEMORY_CLASS = Android.getMemoryClass();
   private static final boolean IS_ANDROID_64 = determineAndroidSupportByAddressSize(long.class);
@@ -363,9 +362,13 @@ final class UnsafeUtil {
 
       return true;
     } catch (Throwable e) {
-      logger.log(
-          Level.WARNING,
-          "platform method missing - proto runtime falling back to safer methods: " + e);
+      // Because log statements are fairly sparse in this class, this logger is initialized
+      // non-statically. Static initialization adds undue runtime costs to the first client to
+      // initialize this class.
+      Logger.getLogger(UnsafeUtil.class.getName())
+          .log(
+              Level.WARNING,
+              "platform method missing - proto runtime falling back to safer methods: " + e);
     }
     return false;
   }
@@ -397,9 +400,13 @@ final class UnsafeUtil {
       clazz.getMethod("copyMemory", Object.class, long.class, Object.class, long.class, long.class);
       return true;
     } catch (Throwable e) {
-      logger.log(
-          Level.WARNING,
-          "platform method missing - proto runtime falling back to safer methods: " + e);
+      // Because log statements are fairly sparse in this class, this logger is initialized
+      // non-statically. Static initialization adds undue runtime costs to the first client to
+      // initialize this class.
+      Logger.getLogger(UnsafeUtil.class.getName())
+          .log(
+              Level.WARNING,
+              "platform method missing - proto runtime falling back to safer methods: " + e);
     }
     return false;
   }

+ 83 - 82
java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java

@@ -77,44 +77,44 @@ public final class MapForProto2LiteTest extends TestCase {
 
   private void copyMapValues(TestMap source, TestMap.Builder destination) {
     destination
-        .putAllInt32ToInt32Field(source.getInt32ToInt32Field())
-        .putAllInt32ToStringField(source.getInt32ToStringField())
-        .putAllInt32ToBytesField(source.getInt32ToBytesField())
-        .putAllInt32ToEnumField(source.getInt32ToEnumField())
-        .putAllInt32ToMessageField(source.getInt32ToMessageField())
-        .putAllStringToInt32Field(source.getStringToInt32Field());
+        .putAllInt32ToInt32Field(source.getInt32ToInt32FieldMap())
+        .putAllInt32ToStringField(source.getInt32ToStringFieldMap())
+        .putAllInt32ToBytesField(source.getInt32ToBytesFieldMap())
+        .putAllInt32ToEnumField(source.getInt32ToEnumFieldMap())
+        .putAllInt32ToMessageField(source.getInt32ToMessageFieldMap())
+        .putAllStringToInt32Field(source.getStringToInt32FieldMap());
   }
 
   private void assertMapValuesSet(TestMap message) {
-    assertEquals(3, message.getInt32ToInt32Field().size());
-    assertEquals(11, message.getInt32ToInt32Field().get(1).intValue());
-    assertEquals(22, message.getInt32ToInt32Field().get(2).intValue());
-    assertEquals(33, message.getInt32ToInt32Field().get(3).intValue());
+    assertEquals(3, message.getInt32ToInt32FieldMap().size());
+    assertEquals(11, message.getInt32ToInt32FieldMap().get(1).intValue());
+    assertEquals(22, message.getInt32ToInt32FieldMap().get(2).intValue());
+    assertEquals(33, message.getInt32ToInt32FieldMap().get(3).intValue());
 
-    assertEquals(3, message.getInt32ToStringField().size());
-    assertEquals("11", message.getInt32ToStringField().get(1));
-    assertEquals("22", message.getInt32ToStringField().get(2));
-    assertEquals("33", message.getInt32ToStringField().get(3));
+    assertEquals(3, message.getInt32ToStringFieldMap().size());
+    assertEquals("11", message.getInt32ToStringFieldMap().get(1));
+    assertEquals("22", message.getInt32ToStringFieldMap().get(2));
+    assertEquals("33", message.getInt32ToStringFieldMap().get(3));
 
-    assertEquals(3, message.getInt32ToBytesField().size());
-    assertEquals(TestUtil.toBytes("11"), message.getInt32ToBytesField().get(1));
-    assertEquals(TestUtil.toBytes("22"), message.getInt32ToBytesField().get(2));
-    assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3));
+    assertEquals(3, message.getInt32ToBytesFieldMap().size());
+    assertEquals(TestUtil.toBytes("11"), message.getInt32ToBytesFieldMap().get(1));
+    assertEquals(TestUtil.toBytes("22"), message.getInt32ToBytesFieldMap().get(2));
+    assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesFieldMap().get(3));
 
-    assertEquals(3, message.getInt32ToEnumField().size());
-    assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumField().get(1));
-    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(2));
-    assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3));
+    assertEquals(3, message.getInt32ToEnumFieldMap().size());
+    assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumFieldMap().get(1));
+    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumFieldMap().get(2));
+    assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumFieldMap().get(3));
 
-    assertEquals(3, message.getInt32ToMessageField().size());
-    assertEquals(11, message.getInt32ToMessageField().get(1).getValue());
-    assertEquals(22, message.getInt32ToMessageField().get(2).getValue());
-    assertEquals(33, message.getInt32ToMessageField().get(3).getValue());
+    assertEquals(3, message.getInt32ToMessageFieldMap().size());
+    assertEquals(11, message.getInt32ToMessageFieldMap().get(1).getValue());
+    assertEquals(22, message.getInt32ToMessageFieldMap().get(2).getValue());
+    assertEquals(33, message.getInt32ToMessageFieldMap().get(3).getValue());
 
-    assertEquals(3, message.getStringToInt32Field().size());
-    assertEquals(11, message.getStringToInt32Field().get("1").intValue());
-    assertEquals(22, message.getStringToInt32Field().get("2").intValue());
-    assertEquals(33, message.getStringToInt32Field().get("3").intValue());
+    assertEquals(3, message.getStringToInt32FieldMap().size());
+    assertEquals(11, message.getStringToInt32FieldMap().get("1").intValue());
+    assertEquals(22, message.getStringToInt32FieldMap().get("2").intValue());
+    assertEquals(33, message.getStringToInt32FieldMap().get("3").intValue());
   }
 
   private void updateMapValues(TestMap.Builder builder) {
@@ -152,35 +152,35 @@ public final class MapForProto2LiteTest extends TestCase {
   }
 
   private void assertMapValuesUpdated(TestMap message) {
-    assertEquals(3, message.getInt32ToInt32Field().size());
-    assertEquals(111, message.getInt32ToInt32Field().get(1).intValue());
-    assertEquals(33, message.getInt32ToInt32Field().get(3).intValue());
-    assertEquals(44, message.getInt32ToInt32Field().get(4).intValue());
+    assertEquals(3, message.getInt32ToInt32FieldMap().size());
+    assertEquals(111, message.getInt32ToInt32FieldMap().get(1).intValue());
+    assertEquals(33, message.getInt32ToInt32FieldMap().get(3).intValue());
+    assertEquals(44, message.getInt32ToInt32FieldMap().get(4).intValue());
 
-    assertEquals(3, message.getInt32ToStringField().size());
-    assertEquals("111", message.getInt32ToStringField().get(1));
-    assertEquals("33", message.getInt32ToStringField().get(3));
-    assertEquals("44", message.getInt32ToStringField().get(4));
+    assertEquals(3, message.getInt32ToStringFieldMap().size());
+    assertEquals("111", message.getInt32ToStringFieldMap().get(1));
+    assertEquals("33", message.getInt32ToStringFieldMap().get(3));
+    assertEquals("44", message.getInt32ToStringFieldMap().get(4));
 
-    assertEquals(3, message.getInt32ToBytesField().size());
-    assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesField().get(1));
-    assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3));
-    assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesField().get(4));
+    assertEquals(3, message.getInt32ToBytesFieldMap().size());
+    assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesFieldMap().get(1));
+    assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesFieldMap().get(3));
+    assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesFieldMap().get(4));
 
-    assertEquals(3, message.getInt32ToEnumField().size());
-    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1));
-    assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3));
-    assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumField().get(4));
+    assertEquals(3, message.getInt32ToEnumFieldMap().size());
+    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumFieldMap().get(1));
+    assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumFieldMap().get(3));
+    assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumFieldMap().get(4));
 
-    assertEquals(3, message.getInt32ToMessageField().size());
-    assertEquals(111, message.getInt32ToMessageField().get(1).getValue());
-    assertEquals(33, message.getInt32ToMessageField().get(3).getValue());
-    assertEquals(44, message.getInt32ToMessageField().get(4).getValue());
+    assertEquals(3, message.getInt32ToMessageFieldMap().size());
+    assertEquals(111, message.getInt32ToMessageFieldMap().get(1).getValue());
+    assertEquals(33, message.getInt32ToMessageFieldMap().get(3).getValue());
+    assertEquals(44, message.getInt32ToMessageFieldMap().get(4).getValue());
 
-    assertEquals(3, message.getStringToInt32Field().size());
-    assertEquals(111, message.getStringToInt32Field().get("1").intValue());
-    assertEquals(33, message.getStringToInt32Field().get("3").intValue());
-    assertEquals(44, message.getStringToInt32Field().get("4").intValue());
+    assertEquals(3, message.getStringToInt32FieldMap().size());
+    assertEquals(111, message.getStringToInt32FieldMap().get("1").intValue());
+    assertEquals(33, message.getStringToInt32FieldMap().get("3").intValue());
+    assertEquals(44, message.getStringToInt32FieldMap().get("4").intValue());
   }
 
   private void assertMapValuesCleared(TestMapOrBuilder testMapOrBuilder) {
@@ -206,13 +206,13 @@ public final class MapForProto2LiteTest extends TestCase {
     TestMap.Builder builder = TestMap.newBuilder();
     TestMap message = builder.build();
     builder.putInt32ToInt32Field(1, 2);
-    assertTrue(message.getInt32ToInt32Field().isEmpty());
+    assertTrue(message.getInt32ToInt32FieldMap().isEmpty());
     message = builder.build();
-    assertEquals(newMap(1, 2), message.getInt32ToInt32Field());
-    assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
+    assertEquals(newMap(1, 2), message.getInt32ToInt32FieldMap());
+    assertEquals(newMap(1, 2), builder.getInt32ToInt32FieldMap());
     builder.putInt32ToInt32Field(2, 3);
-    assertEquals(newMap(1, 2), message.getInt32ToInt32Field());
-    assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field());
+    assertEquals(newMap(1, 2), message.getInt32ToInt32FieldMap());
+    assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32FieldMap());
   }
 
   public void testGetMapIsImmutable() {
@@ -254,30 +254,31 @@ public final class MapForProto2LiteTest extends TestCase {
 
   public void testMutableMapLifecycle() {
     TestMap.Builder builder = TestMap.newBuilder().putInt32ToInt32Field(1, 2);
-    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
-    assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
+    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32FieldMap());
+    assertEquals(newMap(1, 2), builder.getInt32ToInt32FieldMap());
     builder.putInt32ToInt32Field(2, 3);
-    assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field());
+    assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32FieldMap());
 
     builder.putInt32ToEnumField(1, TestMap.EnumValue.BAR);
-    assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumField());
-    assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.getInt32ToEnumField());
+    assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumFieldMap());
+    assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.getInt32ToEnumFieldMap());
     builder.putInt32ToEnumField(2, TestMap.EnumValue.FOO);
     assertEquals(
-        newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO), builder.getInt32ToEnumField());
+        newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO),
+        builder.getInt32ToEnumFieldMap());
 
     builder.putInt32ToStringField(1, "1");
-    assertEquals(newMap(1, "1"), builder.build().getInt32ToStringField());
-    assertEquals(newMap(1, "1"), builder.getInt32ToStringField());
+    assertEquals(newMap(1, "1"), builder.build().getInt32ToStringFieldMap());
+    assertEquals(newMap(1, "1"), builder.getInt32ToStringFieldMap());
     builder.putInt32ToStringField(2, "2");
-    assertEquals(newMap(1, "1", 2, "2"), builder.getInt32ToStringField());
+    assertEquals(newMap(1, "1", 2, "2"), builder.getInt32ToStringFieldMap());
 
     builder.putInt32ToMessageField(1, TestMap.MessageValue.getDefaultInstance());
     assertEquals(
         newMap(1, TestMap.MessageValue.getDefaultInstance()),
-        builder.build().getInt32ToMessageField());
+        builder.build().getInt32ToMessageFieldMap());
     assertEquals(
-        newMap(1, TestMap.MessageValue.getDefaultInstance()), builder.getInt32ToMessageField());
+        newMap(1, TestMap.MessageValue.getDefaultInstance()), builder.getInt32ToMessageFieldMap());
     builder.putInt32ToMessageField(2, TestMap.MessageValue.getDefaultInstance());
     assertEquals(
         newMap(
@@ -285,7 +286,7 @@ public final class MapForProto2LiteTest extends TestCase {
             TestMap.MessageValue.getDefaultInstance(),
             2,
             TestMap.MessageValue.getDefaultInstance()),
-        builder.getInt32ToMessageField());
+        builder.getInt32ToMessageFieldMap());
   }
 
   public void testGettersAndSetters() throws Exception {
@@ -415,7 +416,7 @@ public final class MapForProto2LiteTest extends TestCase {
     } catch (InvalidProtocolBufferException expected) {
       assertTrue(expected.getUnfinishedMessage() instanceof TestMap);
       map = (TestMap) expected.getUnfinishedMessage();
-      assertTrue(map.getInt32ToMessageField().isEmpty());
+      assertTrue(map.getInt32ToMessageFieldMap().isEmpty());
     }
 
     map =
@@ -476,14 +477,14 @@ public final class MapForProto2LiteTest extends TestCase {
     TestMap message = TestMap.parseFrom(data);
     // Entries with unknown enum values will be stored into UnknownFieldSet so
     // there is only one entry in the map.
-    assertEquals(1, message.getInt32ToEnumField().size());
-    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1));
+    assertEquals(1, message.getInt32ToEnumFieldMap().size());
+    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumFieldMap().get(1));
     // Serializing and parsing should preserve the unknown entry.
     data = message.toByteString();
     TestUnknownEnumValue messageWithUnknownEnums = TestUnknownEnumValue.parseFrom(data);
-    assertEquals(2, messageWithUnknownEnums.getInt32ToInt32Field().size());
-    assertEquals(1, messageWithUnknownEnums.getInt32ToInt32Field().get(1).intValue());
-    assertEquals(54321, messageWithUnknownEnums.getInt32ToInt32Field().get(2).intValue());
+    assertEquals(2, messageWithUnknownEnums.getInt32ToInt32FieldMap().size());
+    assertEquals(1, messageWithUnknownEnums.getInt32ToInt32FieldMap().get(1).intValue());
+    assertEquals(54321, messageWithUnknownEnums.getInt32ToInt32FieldMap().get(2).intValue());
   }
 
   public void testIterationOrder() throws Exception {
@@ -493,7 +494,7 @@ public final class MapForProto2LiteTest extends TestCase {
 
     assertEquals(
         Arrays.asList("1", "2", "3"),
-        new ArrayList<String>(message.getStringToInt32Field().keySet()));
+        new ArrayList<String>(message.getStringToInt32FieldMap().keySet()));
   }
 
   private static <K, V> Map<K, V> newMap(K key1, V value1) {
@@ -513,10 +514,10 @@ public final class MapForProto2LiteTest extends TestCase {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValues(builder);
     TestMap message = builder.build();
-    assertEquals(message.getStringToInt32Field(), message.getStringToInt32FieldMap());
-    assertEquals(message.getInt32ToBytesField(), message.getInt32ToBytesFieldMap());
-    assertEquals(message.getInt32ToEnumField(), message.getInt32ToEnumFieldMap());
-    assertEquals(message.getInt32ToMessageField(), message.getInt32ToMessageFieldMap());
+    assertEquals(message.getStringToInt32FieldMap(), message.getStringToInt32FieldMap());
+    assertEquals(message.getInt32ToBytesFieldMap(), message.getInt32ToBytesFieldMap());
+    assertEquals(message.getInt32ToEnumFieldMap(), message.getInt32ToEnumFieldMap());
+    assertEquals(message.getInt32ToMessageFieldMap(), message.getInt32ToMessageFieldMap());
   }
 
   public void testContains() {

+ 59 - 59
java/core/src/test/java/com/google/protobuf/MapForProto2Test.java

@@ -119,12 +119,12 @@ public class MapForProto2Test extends TestCase {
 
   private void copyMapValues(TestMap source, TestMap.Builder destination) {
     destination
-        .putAllInt32ToInt32Field(source.getInt32ToInt32Field())
-        .putAllInt32ToStringField(source.getInt32ToStringField())
-        .putAllInt32ToBytesField(source.getInt32ToBytesField())
-        .putAllInt32ToEnumField(source.getInt32ToEnumField())
-        .putAllInt32ToMessageField(source.getInt32ToMessageField())
-        .putAllStringToInt32Field(source.getStringToInt32Field());
+        .putAllInt32ToInt32Field(source.getInt32ToInt32FieldMap())
+        .putAllInt32ToStringField(source.getInt32ToStringFieldMap())
+        .putAllInt32ToBytesField(source.getInt32ToBytesFieldMap())
+        .putAllInt32ToEnumField(source.getInt32ToEnumFieldMap())
+        .putAllInt32ToMessageField(source.getInt32ToMessageFieldMap())
+        .putAllStringToInt32Field(source.getStringToInt32FieldMap());
   }
 
   private void assertMapValuesSet(TestMapOrBuilder message) {
@@ -236,35 +236,35 @@ public class MapForProto2Test extends TestCase {
   }
 
   private void assertMapValuesUpdated(TestMap message) {
-    assertEquals(3, message.getInt32ToInt32Field().size());
-    assertEquals(111, message.getInt32ToInt32Field().get(1).intValue());
-    assertEquals(33, message.getInt32ToInt32Field().get(3).intValue());
-    assertEquals(44, message.getInt32ToInt32Field().get(4).intValue());
-
-    assertEquals(3, message.getInt32ToStringField().size());
-    assertEquals("111", message.getInt32ToStringField().get(1));
-    assertEquals("33", message.getInt32ToStringField().get(3));
-    assertEquals("44", message.getInt32ToStringField().get(4));
-
-    assertEquals(3, message.getInt32ToBytesField().size());
-    assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesField().get(1));
-    assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3));
-    assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesField().get(4));
-
-    assertEquals(3, message.getInt32ToEnumField().size());
-    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1));
-    assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3));
-    assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumField().get(4));
-
-    assertEquals(3, message.getInt32ToMessageField().size());
-    assertEquals(111, message.getInt32ToMessageField().get(1).getValue());
-    assertEquals(33, message.getInt32ToMessageField().get(3).getValue());
-    assertEquals(44, message.getInt32ToMessageField().get(4).getValue());
-
-    assertEquals(3, message.getStringToInt32Field().size());
-    assertEquals(111, message.getStringToInt32Field().get("1").intValue());
-    assertEquals(33, message.getStringToInt32Field().get("3").intValue());
-    assertEquals(44, message.getStringToInt32Field().get("4").intValue());
+    assertEquals(3, message.getInt32ToInt32FieldMap().size());
+    assertEquals(111, message.getInt32ToInt32FieldMap().get(1).intValue());
+    assertEquals(33, message.getInt32ToInt32FieldMap().get(3).intValue());
+    assertEquals(44, message.getInt32ToInt32FieldMap().get(4).intValue());
+
+    assertEquals(3, message.getInt32ToStringFieldMap().size());
+    assertEquals("111", message.getInt32ToStringFieldMap().get(1));
+    assertEquals("33", message.getInt32ToStringFieldMap().get(3));
+    assertEquals("44", message.getInt32ToStringFieldMap().get(4));
+
+    assertEquals(3, message.getInt32ToBytesFieldMap().size());
+    assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesFieldMap().get(1));
+    assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesFieldMap().get(3));
+    assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesFieldMap().get(4));
+
+    assertEquals(3, message.getInt32ToEnumFieldMap().size());
+    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumFieldMap().get(1));
+    assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumFieldMap().get(3));
+    assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumFieldMap().get(4));
+
+    assertEquals(3, message.getInt32ToMessageFieldMap().size());
+    assertEquals(111, message.getInt32ToMessageFieldMap().get(1).getValue());
+    assertEquals(33, message.getInt32ToMessageFieldMap().get(3).getValue());
+    assertEquals(44, message.getInt32ToMessageFieldMap().get(4).getValue());
+
+    assertEquals(3, message.getStringToInt32FieldMap().size());
+    assertEquals(111, message.getStringToInt32FieldMap().get("1").intValue());
+    assertEquals(33, message.getStringToInt32FieldMap().get("3").intValue());
+    assertEquals(44, message.getStringToInt32FieldMap().get("4").intValue());
   }
 
   private void assertMapValuesCleared(TestMapOrBuilder testMapOrBuilder) {
@@ -563,7 +563,7 @@ public class MapForProto2Test extends TestCase {
     } catch (InvalidProtocolBufferException expected) {
       assertTrue(expected.getUnfinishedMessage() instanceof TestMap);
       map = (TestMap) expected.getUnfinishedMessage();
-      assertTrue(map.getInt32ToMessageField().isEmpty());
+      assertTrue(map.getInt32ToMessageFieldMap().isEmpty());
     }
 
     map =
@@ -698,8 +698,8 @@ public class MapForProto2Test extends TestCase {
     builder.clearField(f("int32_to_int32_field"));
     builder.clearField(f("int32_to_message_field"));
     message = builder.build();
-    assertEquals(0, message.getInt32ToInt32Field().size());
-    assertEquals(0, message.getInt32ToMessageField().size());
+    assertEquals(0, message.getInt32ToInt32FieldMap().size());
+    assertEquals(0, message.getInt32ToMessageFieldMap().size());
 
     // Test setField()
     setMapValues(builder, "int32_to_int32_field", mapForValues(11, 22, 33, 44));
@@ -710,10 +710,10 @@ public class MapForProto2Test extends TestCase {
             111, MessageValue.newBuilder().setValue(222).build(),
             333, MessageValue.newBuilder().setValue(444).build()));
     message = builder.build();
-    assertEquals(22, message.getInt32ToInt32Field().get(11).intValue());
-    assertEquals(44, message.getInt32ToInt32Field().get(33).intValue());
-    assertEquals(222, message.getInt32ToMessageField().get(111).getValue());
-    assertEquals(444, message.getInt32ToMessageField().get(333).getValue());
+    assertEquals(22, message.getInt32ToInt32FieldMap().get(11).intValue());
+    assertEquals(44, message.getInt32ToInt32FieldMap().get(33).intValue());
+    assertEquals(222, message.getInt32ToMessageFieldMap().get(111).getValue());
+    assertEquals(444, message.getInt32ToMessageFieldMap().get(333).getValue());
 
     // Test addRepeatedField
     builder.addRepeatedField(
@@ -726,8 +726,8 @@ public class MapForProto2Test extends TestCase {
             555,
             MessageValue.newBuilder().setValue(666).build()));
     message = builder.build();
-    assertEquals(66, message.getInt32ToInt32Field().get(55).intValue());
-    assertEquals(666, message.getInt32ToMessageField().get(555).getValue());
+    assertEquals(66, message.getInt32ToInt32FieldMap().get(55).intValue());
+    assertEquals(666, message.getInt32ToMessageFieldMap().get(555).getValue());
 
     // Test addRepeatedField (overriding existing values)
     builder.addRepeatedField(
@@ -740,8 +740,8 @@ public class MapForProto2Test extends TestCase {
             555,
             MessageValue.newBuilder().setValue(555).build()));
     message = builder.build();
-    assertEquals(55, message.getInt32ToInt32Field().get(55).intValue());
-    assertEquals(555, message.getInt32ToMessageField().get(555).getValue());
+    assertEquals(55, message.getInt32ToInt32FieldMap().get(55).intValue());
+    assertEquals(555, message.getInt32ToMessageFieldMap().get(555).getValue());
 
     // Test setRepeatedField
     for (int i = 0; i < builder.getRepeatedFieldCount(f("int32_to_int32_field")); i++) {
@@ -755,9 +755,9 @@ public class MapForProto2Test extends TestCase {
       builder.setRepeatedField(f("int32_to_int32_field"), i, mapEntryBuilder.build());
     }
     message = builder.build();
-    assertEquals(11, message.getInt32ToInt32Field().get(22).intValue());
-    assertEquals(33, message.getInt32ToInt32Field().get(44).intValue());
-    assertEquals(55, message.getInt32ToInt32Field().get(55).intValue());
+    assertEquals(11, message.getInt32ToInt32FieldMap().get(22).intValue());
+    assertEquals(33, message.getInt32ToInt32FieldMap().get(44).intValue());
+    assertEquals(55, message.getInt32ToInt32FieldMap().get(55).intValue());
   }
 
   // See additional coverage in TextFormatTest.java.
@@ -844,16 +844,16 @@ public class MapForProto2Test extends TestCase {
     TestMap message = TestMap.parseFrom(data);
     // Entries with unknown enum values will be stored into UnknownFieldSet so
     // there is only one entry in the map.
-    assertEquals(1, message.getInt32ToEnumField().size());
-    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1));
+    assertEquals(1, message.getInt32ToEnumFieldMap().size());
+    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumFieldMap().get(1));
     // UnknownFieldSet should not be empty.
     assertFalse(message.getUnknownFields().asMap().isEmpty());
     // Serializing and parsing should preserve the unknown entry.
     data = message.toByteString();
     TestUnknownEnumValue messageWithUnknownEnums = TestUnknownEnumValue.parseFrom(data);
-    assertEquals(2, messageWithUnknownEnums.getInt32ToInt32Field().size());
-    assertEquals(1, messageWithUnknownEnums.getInt32ToInt32Field().get(1).intValue());
-    assertEquals(54321, messageWithUnknownEnums.getInt32ToInt32Field().get(2).intValue());
+    assertEquals(2, messageWithUnknownEnums.getInt32ToInt32FieldMap().size());
+    assertEquals(1, messageWithUnknownEnums.getInt32ToInt32FieldMap().get(1).intValue());
+    assertEquals(54321, messageWithUnknownEnums.getInt32ToInt32FieldMap().get(2).intValue());
   }
 
   public void testRequiredMessage() throws Exception {
@@ -885,7 +885,7 @@ public class MapForProto2Test extends TestCase {
 
     assertEquals(
         Arrays.asList("1", "2", "3"),
-        new ArrayList<String>(message.getStringToInt32Field().keySet()));
+        new ArrayList<String>(message.getStringToInt32FieldMap().keySet()));
   }
 
   public void testContains() {
@@ -1172,9 +1172,9 @@ public class MapForProto2Test extends TestCase {
     setMapValuesUsingAccessors(builder);
     assertMapValuesSet(builder);
     TestMap message = builder.build();
-    assertEquals(message.getStringToInt32Field(), message.getStringToInt32FieldMap());
-    assertEquals(message.getInt32ToBytesField(), message.getInt32ToBytesFieldMap());
-    assertEquals(message.getInt32ToEnumField(), message.getInt32ToEnumFieldMap());
-    assertEquals(message.getInt32ToMessageField(), message.getInt32ToMessageFieldMap());
+    assertEquals(message.getStringToInt32FieldMap(), message.getStringToInt32FieldMap());
+    assertEquals(message.getInt32ToBytesFieldMap(), message.getInt32ToBytesFieldMap());
+    assertEquals(message.getInt32ToEnumFieldMap(), message.getInt32ToEnumFieldMap());
+    assertEquals(message.getInt32ToMessageFieldMap(), message.getInt32ToMessageFieldMap());
   }
 }

+ 90 - 89
java/core/src/test/java/com/google/protobuf/MapLiteTest.java

@@ -84,44 +84,44 @@ public final class MapLiteTest extends TestCase {
 
   private void copyMapValues(TestMap source, TestMap.Builder destination) {
     destination
-        .putAllInt32ToInt32Field(source.getInt32ToInt32Field())
-        .putAllInt32ToStringField(source.getInt32ToStringField())
-        .putAllInt32ToBytesField(source.getInt32ToBytesField())
-        .putAllInt32ToEnumField(source.getInt32ToEnumField())
-        .putAllInt32ToMessageField(source.getInt32ToMessageField())
-        .putAllStringToInt32Field(source.getStringToInt32Field());
+        .putAllInt32ToInt32Field(source.getInt32ToInt32FieldMap())
+        .putAllInt32ToStringField(source.getInt32ToStringFieldMap())
+        .putAllInt32ToBytesField(source.getInt32ToBytesFieldMap())
+        .putAllInt32ToEnumField(source.getInt32ToEnumFieldMap())
+        .putAllInt32ToMessageField(source.getInt32ToMessageFieldMap())
+        .putAllStringToInt32Field(source.getStringToInt32FieldMap());
   }
 
   private void assertMapValuesSet(TestMap message) {
-    assertEquals(3, message.getInt32ToInt32Field().size());
-    assertEquals(11, message.getInt32ToInt32Field().get(1).intValue());
-    assertEquals(22, message.getInt32ToInt32Field().get(2).intValue());
-    assertEquals(33, message.getInt32ToInt32Field().get(3).intValue());
+    assertEquals(3, message.getInt32ToInt32FieldMap().size());
+    assertEquals(11, message.getInt32ToInt32FieldMap().get(1).intValue());
+    assertEquals(22, message.getInt32ToInt32FieldMap().get(2).intValue());
+    assertEquals(33, message.getInt32ToInt32FieldMap().get(3).intValue());
 
-    assertEquals(3, message.getInt32ToStringField().size());
-    assertEquals("11", message.getInt32ToStringField().get(1));
-    assertEquals("22", message.getInt32ToStringField().get(2));
-    assertEquals("33", message.getInt32ToStringField().get(3));
+    assertEquals(3, message.getInt32ToStringFieldMap().size());
+    assertEquals("11", message.getInt32ToStringFieldMap().get(1));
+    assertEquals("22", message.getInt32ToStringFieldMap().get(2));
+    assertEquals("33", message.getInt32ToStringFieldMap().get(3));
 
-    assertEquals(3, message.getInt32ToBytesField().size());
-    assertEquals(TestUtil.toBytes("11"), message.getInt32ToBytesField().get(1));
-    assertEquals(TestUtil.toBytes("22"), message.getInt32ToBytesField().get(2));
-    assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3));
+    assertEquals(3, message.getInt32ToBytesFieldMap().size());
+    assertEquals(TestUtil.toBytes("11"), message.getInt32ToBytesFieldMap().get(1));
+    assertEquals(TestUtil.toBytes("22"), message.getInt32ToBytesFieldMap().get(2));
+    assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesFieldMap().get(3));
 
-    assertEquals(3, message.getInt32ToEnumField().size());
-    assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumField().get(1));
-    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(2));
-    assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3));
+    assertEquals(3, message.getInt32ToEnumFieldMap().size());
+    assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumFieldMap().get(1));
+    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumFieldMap().get(2));
+    assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumFieldMap().get(3));
 
-    assertEquals(3, message.getInt32ToMessageField().size());
-    assertEquals(11, message.getInt32ToMessageField().get(1).getValue());
-    assertEquals(22, message.getInt32ToMessageField().get(2).getValue());
-    assertEquals(33, message.getInt32ToMessageField().get(3).getValue());
+    assertEquals(3, message.getInt32ToMessageFieldMap().size());
+    assertEquals(11, message.getInt32ToMessageFieldMap().get(1).getValue());
+    assertEquals(22, message.getInt32ToMessageFieldMap().get(2).getValue());
+    assertEquals(33, message.getInt32ToMessageFieldMap().get(3).getValue());
 
-    assertEquals(3, message.getStringToInt32Field().size());
-    assertEquals(11, message.getStringToInt32Field().get("1").intValue());
-    assertEquals(22, message.getStringToInt32Field().get("2").intValue());
-    assertEquals(33, message.getStringToInt32Field().get("3").intValue());
+    assertEquals(3, message.getStringToInt32FieldMap().size());
+    assertEquals(11, message.getStringToInt32FieldMap().get("1").intValue());
+    assertEquals(22, message.getStringToInt32FieldMap().get("2").intValue());
+    assertEquals(33, message.getStringToInt32FieldMap().get("3").intValue());
   }
 
   private void updateMapValues(TestMap.Builder builder) {
@@ -159,35 +159,35 @@ public final class MapLiteTest extends TestCase {
   }
 
   private void assertMapValuesUpdated(TestMap message) {
-    assertEquals(3, message.getInt32ToInt32Field().size());
-    assertEquals(111, message.getInt32ToInt32Field().get(1).intValue());
-    assertEquals(33, message.getInt32ToInt32Field().get(3).intValue());
-    assertEquals(44, message.getInt32ToInt32Field().get(4).intValue());
+    assertEquals(3, message.getInt32ToInt32FieldMap().size());
+    assertEquals(111, message.getInt32ToInt32FieldMap().get(1).intValue());
+    assertEquals(33, message.getInt32ToInt32FieldMap().get(3).intValue());
+    assertEquals(44, message.getInt32ToInt32FieldMap().get(4).intValue());
 
-    assertEquals(3, message.getInt32ToStringField().size());
-    assertEquals("111", message.getInt32ToStringField().get(1));
-    assertEquals("33", message.getInt32ToStringField().get(3));
-    assertEquals("44", message.getInt32ToStringField().get(4));
+    assertEquals(3, message.getInt32ToStringFieldMap().size());
+    assertEquals("111", message.getInt32ToStringFieldMap().get(1));
+    assertEquals("33", message.getInt32ToStringFieldMap().get(3));
+    assertEquals("44", message.getInt32ToStringFieldMap().get(4));
 
-    assertEquals(3, message.getInt32ToBytesField().size());
-    assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesField().get(1));
-    assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3));
-    assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesField().get(4));
+    assertEquals(3, message.getInt32ToBytesFieldMap().size());
+    assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesFieldMap().get(1));
+    assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesFieldMap().get(3));
+    assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesFieldMap().get(4));
 
-    assertEquals(3, message.getInt32ToEnumField().size());
-    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1));
-    assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3));
-    assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumField().get(4));
+    assertEquals(3, message.getInt32ToEnumFieldMap().size());
+    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumFieldMap().get(1));
+    assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumFieldMap().get(3));
+    assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumFieldMap().get(4));
 
-    assertEquals(3, message.getInt32ToMessageField().size());
-    assertEquals(111, message.getInt32ToMessageField().get(1).getValue());
-    assertEquals(33, message.getInt32ToMessageField().get(3).getValue());
-    assertEquals(44, message.getInt32ToMessageField().get(4).getValue());
+    assertEquals(3, message.getInt32ToMessageFieldMap().size());
+    assertEquals(111, message.getInt32ToMessageFieldMap().get(1).getValue());
+    assertEquals(33, message.getInt32ToMessageFieldMap().get(3).getValue());
+    assertEquals(44, message.getInt32ToMessageFieldMap().get(4).getValue());
 
-    assertEquals(3, message.getStringToInt32Field().size());
-    assertEquals(111, message.getStringToInt32Field().get("1").intValue());
-    assertEquals(33, message.getStringToInt32Field().get("3").intValue());
-    assertEquals(44, message.getStringToInt32Field().get("4").intValue());
+    assertEquals(3, message.getStringToInt32FieldMap().size());
+    assertEquals(111, message.getStringToInt32FieldMap().get("1").intValue());
+    assertEquals(33, message.getStringToInt32FieldMap().get("3").intValue());
+    assertEquals(44, message.getStringToInt32FieldMap().get("4").intValue());
   }
 
   private void assertMapValuesCleared(TestMapOrBuilder testMapOrBuilder) {
@@ -213,12 +213,12 @@ public final class MapLiteTest extends TestCase {
     TestMap.Builder builder = TestMap.newBuilder();
     TestMap message = builder.build();
     builder.putInt32ToInt32Field(1, 2);
-    assertTrue(message.getInt32ToInt32Field().isEmpty());
-    assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
+    assertTrue(message.getInt32ToInt32FieldMap().isEmpty());
+    assertEquals(newMap(1, 2), builder.getInt32ToInt32FieldMap());
     message = builder.build();
     builder.putInt32ToInt32Field(2, 3);
-    assertEquals(newMap(1, 2), message.getInt32ToInt32Field());
-    assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field());
+    assertEquals(newMap(1, 2), message.getInt32ToInt32FieldMap());
+    assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32FieldMap());
   }
 
   public void testGetMapIsImmutable() {
@@ -266,30 +266,31 @@ public final class MapLiteTest extends TestCase {
 
   public void testMutableMapLifecycle() {
     TestMap.Builder builder = TestMap.newBuilder().putInt32ToInt32Field(1, 2);
-    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
-    assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
+    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32FieldMap());
+    assertEquals(newMap(1, 2), builder.getInt32ToInt32FieldMap());
     builder.putInt32ToInt32Field(2, 3);
-    assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field());
+    assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32FieldMap());
 
     builder.putInt32ToEnumField(1, TestMap.EnumValue.BAR);
-    assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumField());
-    assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.getInt32ToEnumField());
+    assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumFieldMap());
+    assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.getInt32ToEnumFieldMap());
     builder.putInt32ToEnumField(2, TestMap.EnumValue.FOO);
     assertEquals(
-        newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO), builder.getInt32ToEnumField());
+        newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO),
+        builder.getInt32ToEnumFieldMap());
 
     builder.putInt32ToStringField(1, "1");
-    assertEquals(newMap(1, "1"), builder.build().getInt32ToStringField());
-    assertEquals(newMap(1, "1"), builder.getInt32ToStringField());
+    assertEquals(newMap(1, "1"), builder.build().getInt32ToStringFieldMap());
+    assertEquals(newMap(1, "1"), builder.getInt32ToStringFieldMap());
     builder.putInt32ToStringField(2, "2");
-    assertEquals(newMap(1, "1", 2, "2"), builder.getInt32ToStringField());
+    assertEquals(newMap(1, "1", 2, "2"), builder.getInt32ToStringFieldMap());
 
     builder.putInt32ToMessageField(1, TestMap.MessageValue.getDefaultInstance());
     assertEquals(
         newMap(1, TestMap.MessageValue.getDefaultInstance()),
-        builder.build().getInt32ToMessageField());
+        builder.build().getInt32ToMessageFieldMap());
     assertEquals(
-        newMap(1, TestMap.MessageValue.getDefaultInstance()), builder.getInt32ToMessageField());
+        newMap(1, TestMap.MessageValue.getDefaultInstance()), builder.getInt32ToMessageFieldMap());
     builder.putInt32ToMessageField(2, TestMap.MessageValue.getDefaultInstance());
     assertEquals(
         newMap(
@@ -297,7 +298,7 @@ public final class MapLiteTest extends TestCase {
             TestMap.MessageValue.getDefaultInstance(),
             2,
             TestMap.MessageValue.getDefaultInstance()),
-        builder.getInt32ToMessageField());
+        builder.getInt32ToMessageFieldMap());
   }
 
   public void testGettersAndSetters() throws Exception {
@@ -342,12 +343,12 @@ public final class MapLiteTest extends TestCase {
     TestMap source = sourceBuilder.build();
 
     TestMap.Builder destinationBuilder = TestMap.newBuilder();
-    destinationBuilder.putAllInt32ToEnumFieldValue(source.getInt32ToEnumFieldValue());
+    destinationBuilder.putAllInt32ToEnumFieldValue(source.getInt32ToEnumFieldValueMap());
     TestMap destination = destinationBuilder.build();
 
-    assertEquals(0, destination.getInt32ToEnumFieldValue().get(0).intValue());
-    assertEquals(1, destination.getInt32ToEnumFieldValue().get(1).intValue());
-    assertEquals(1000, destination.getInt32ToEnumFieldValue().get(2).intValue());
+    assertEquals(0, destination.getInt32ToEnumFieldValueMap().get(0).intValue());
+    assertEquals(1, destination.getInt32ToEnumFieldValueMap().get(1).intValue());
+    assertEquals(1000, destination.getInt32ToEnumFieldValueMap().get(2).intValue());
     assertEquals(3, destination.getInt32ToEnumFieldCount());
   }
 
@@ -459,7 +460,7 @@ public final class MapLiteTest extends TestCase {
     } catch (InvalidProtocolBufferException expected) {
       assertTrue(expected.getUnfinishedMessage() instanceof TestMap);
       map = (TestMap) expected.getUnfinishedMessage();
-      assertTrue(map.getInt32ToMessageField().isEmpty());
+      assertTrue(map.getInt32ToMessageFieldMap().isEmpty());
     }
 
     map =
@@ -524,24 +525,24 @@ public final class MapLiteTest extends TestCase {
             .putInt32ToEnumFieldValue(2, 1000); // unknown value.
     TestMap message = builder.build();
 
-    assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumField().get(0));
-    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1));
-    assertEquals(TestMap.EnumValue.UNRECOGNIZED, message.getInt32ToEnumField().get(2));
+    assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumFieldMap().get(0));
+    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumFieldMap().get(1));
+    assertEquals(TestMap.EnumValue.UNRECOGNIZED, message.getInt32ToEnumFieldMap().get(2));
 
     builder.putAllInt32ToEnumFieldValue(newMap(2, 1000)); // unknown value.
     message = builder.build();
-    assertEquals(TestMap.EnumValue.UNRECOGNIZED, message.getInt32ToEnumField().get(2));
+    assertEquals(TestMap.EnumValue.UNRECOGNIZED, message.getInt32ToEnumFieldMap().get(2));
 
     // Unknown enum values should be preserved after:
     //   1. Serialization and parsing.
     //   2. toBuild().
     //   3. mergeFrom().
     message = TestMap.parseFrom(message.toByteString());
-    assertEquals(1000, message.getInt32ToEnumFieldValue().get(2).intValue());
+    assertEquals(1000, message.getInt32ToEnumFieldValueMap().get(2).intValue());
     builder = message.toBuilder();
-    assertEquals(1000, builder.getInt32ToEnumFieldValue().get(2).intValue());
+    assertEquals(1000, builder.getInt32ToEnumFieldValueMap().get(2).intValue());
     builder = TestMap.newBuilder().mergeFrom(message);
-    assertEquals(1000, builder.getInt32ToEnumFieldValue().get(2).intValue());
+    assertEquals(1000, builder.getInt32ToEnumFieldValueMap().get(2).intValue());
 
     // hashCode()/equals() should take unknown enum values into account.
     builder.putAllInt32ToEnumFieldValue(newMap(2, 1001));
@@ -550,7 +551,7 @@ public final class MapLiteTest extends TestCase {
     assertFalse(message.equals(message2));
     // Unknown values will be converted to UNRECOGNIZED so the resulted enum map
     // should be the same.
-    assertEquals(message2.getInt32ToEnumField(), message.getInt32ToEnumField());
+    assertEquals(message2.getInt32ToEnumFieldMap(), message.getInt32ToEnumFieldMap());
   }
 
   public void testIterationOrder() throws Exception {
@@ -559,18 +560,18 @@ public final class MapLiteTest extends TestCase {
     TestMap message = builder.build();
 
     assertEquals(
-        Arrays.asList("1", "2", "3"), new ArrayList<>(message.getStringToInt32Field().keySet()));
+        Arrays.asList("1", "2", "3"), new ArrayList<>(message.getStringToInt32FieldMap().keySet()));
   }
 
   public void testGetMap() {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValues(builder);
     TestMap message = builder.build();
-    assertEquals(message.getStringToInt32Field(), message.getStringToInt32FieldMap());
-    assertEquals(message.getInt32ToBytesField(), message.getInt32ToBytesFieldMap());
-    assertEquals(message.getInt32ToEnumField(), message.getInt32ToEnumFieldMap());
-    assertEquals(message.getInt32ToEnumFieldValue(), message.getInt32ToEnumFieldValueMap());
-    assertEquals(message.getInt32ToMessageField(), message.getInt32ToMessageFieldMap());
+    assertEquals(message.getStringToInt32FieldMap(), message.getStringToInt32FieldMap());
+    assertEquals(message.getInt32ToBytesFieldMap(), message.getInt32ToBytesFieldMap());
+    assertEquals(message.getInt32ToEnumFieldMap(), message.getInt32ToEnumFieldMap());
+    assertEquals(message.getInt32ToEnumFieldValueMap(), message.getInt32ToEnumFieldValueMap());
+    assertEquals(message.getInt32ToMessageFieldMap(), message.getInt32ToMessageFieldMap());
   }
 
   public void testContains() {

+ 96 - 94
java/core/src/test/java/com/google/protobuf/MapTest.java

@@ -122,44 +122,44 @@ public class MapTest extends TestCase {
 
   private void copyMapValues(TestMap source, TestMap.Builder destination) {
     destination
-        .putAllInt32ToInt32Field(source.getInt32ToInt32Field())
-        .putAllInt32ToStringField(source.getInt32ToStringField())
-        .putAllInt32ToBytesField(source.getInt32ToBytesField())
-        .putAllInt32ToEnumField(source.getInt32ToEnumField())
-        .putAllInt32ToMessageField(source.getInt32ToMessageField())
-        .putAllStringToInt32Field(source.getStringToInt32Field());
+        .putAllInt32ToInt32Field(source.getInt32ToInt32FieldMap())
+        .putAllInt32ToStringField(source.getInt32ToStringFieldMap())
+        .putAllInt32ToBytesField(source.getInt32ToBytesFieldMap())
+        .putAllInt32ToEnumField(source.getInt32ToEnumFieldMap())
+        .putAllInt32ToMessageField(source.getInt32ToMessageFieldMap())
+        .putAllStringToInt32Field(source.getStringToInt32FieldMap());
   }
 
   private void assertMapValuesSet(TestMap message) {
-    assertEquals(3, message.getInt32ToInt32Field().size());
-    assertEquals(11, message.getInt32ToInt32Field().get(1).intValue());
-    assertEquals(22, message.getInt32ToInt32Field().get(2).intValue());
-    assertEquals(33, message.getInt32ToInt32Field().get(3).intValue());
+    assertEquals(3, message.getInt32ToInt32FieldMap().size());
+    assertEquals(11, message.getInt32ToInt32FieldMap().get(1).intValue());
+    assertEquals(22, message.getInt32ToInt32FieldMap().get(2).intValue());
+    assertEquals(33, message.getInt32ToInt32FieldMap().get(3).intValue());
 
-    assertEquals(3, message.getInt32ToStringField().size());
-    assertEquals("11", message.getInt32ToStringField().get(1));
-    assertEquals("22", message.getInt32ToStringField().get(2));
-    assertEquals("33", message.getInt32ToStringField().get(3));
+    assertEquals(3, message.getInt32ToStringFieldMap().size());
+    assertEquals("11", message.getInt32ToStringFieldMap().get(1));
+    assertEquals("22", message.getInt32ToStringFieldMap().get(2));
+    assertEquals("33", message.getInt32ToStringFieldMap().get(3));
 
-    assertEquals(3, message.getInt32ToBytesField().size());
-    assertEquals(TestUtil.toBytes("11"), message.getInt32ToBytesField().get(1));
-    assertEquals(TestUtil.toBytes("22"), message.getInt32ToBytesField().get(2));
-    assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3));
+    assertEquals(3, message.getInt32ToBytesFieldMap().size());
+    assertEquals(TestUtil.toBytes("11"), message.getInt32ToBytesFieldMap().get(1));
+    assertEquals(TestUtil.toBytes("22"), message.getInt32ToBytesFieldMap().get(2));
+    assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesFieldMap().get(3));
 
-    assertEquals(3, message.getInt32ToEnumField().size());
-    assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumField().get(1));
-    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(2));
-    assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3));
+    assertEquals(3, message.getInt32ToEnumFieldMap().size());
+    assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumFieldMap().get(1));
+    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumFieldMap().get(2));
+    assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumFieldMap().get(3));
 
-    assertEquals(3, message.getInt32ToMessageField().size());
-    assertEquals(11, message.getInt32ToMessageField().get(1).getValue());
-    assertEquals(22, message.getInt32ToMessageField().get(2).getValue());
-    assertEquals(33, message.getInt32ToMessageField().get(3).getValue());
+    assertEquals(3, message.getInt32ToMessageFieldMap().size());
+    assertEquals(11, message.getInt32ToMessageFieldMap().get(1).getValue());
+    assertEquals(22, message.getInt32ToMessageFieldMap().get(2).getValue());
+    assertEquals(33, message.getInt32ToMessageFieldMap().get(3).getValue());
 
-    assertEquals(3, message.getStringToInt32Field().size());
-    assertEquals(11, message.getStringToInt32Field().get("1").intValue());
-    assertEquals(22, message.getStringToInt32Field().get("2").intValue());
-    assertEquals(33, message.getStringToInt32Field().get("3").intValue());
+    assertEquals(3, message.getStringToInt32FieldMap().size());
+    assertEquals(11, message.getStringToInt32FieldMap().get("1").intValue());
+    assertEquals(22, message.getStringToInt32FieldMap().get("2").intValue());
+    assertEquals(33, message.getStringToInt32FieldMap().get("3").intValue());
   }
 
   private void updateMapValuesUsingMutableMap(TestMap.Builder builder) {
@@ -239,35 +239,35 @@ public class MapTest extends TestCase {
   }
 
   private void assertMapValuesUpdated(TestMap message) {
-    assertEquals(3, message.getInt32ToInt32Field().size());
-    assertEquals(111, message.getInt32ToInt32Field().get(1).intValue());
-    assertEquals(33, message.getInt32ToInt32Field().get(3).intValue());
-    assertEquals(44, message.getInt32ToInt32Field().get(4).intValue());
+    assertEquals(3, message.getInt32ToInt32FieldMap().size());
+    assertEquals(111, message.getInt32ToInt32FieldMap().get(1).intValue());
+    assertEquals(33, message.getInt32ToInt32FieldMap().get(3).intValue());
+    assertEquals(44, message.getInt32ToInt32FieldMap().get(4).intValue());
 
-    assertEquals(3, message.getInt32ToStringField().size());
-    assertEquals("111", message.getInt32ToStringField().get(1));
-    assertEquals("33", message.getInt32ToStringField().get(3));
-    assertEquals("44", message.getInt32ToStringField().get(4));
+    assertEquals(3, message.getInt32ToStringFieldMap().size());
+    assertEquals("111", message.getInt32ToStringFieldMap().get(1));
+    assertEquals("33", message.getInt32ToStringFieldMap().get(3));
+    assertEquals("44", message.getInt32ToStringFieldMap().get(4));
 
-    assertEquals(3, message.getInt32ToBytesField().size());
-    assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesField().get(1));
-    assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3));
-    assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesField().get(4));
+    assertEquals(3, message.getInt32ToBytesFieldMap().size());
+    assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesFieldMap().get(1));
+    assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesFieldMap().get(3));
+    assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesFieldMap().get(4));
 
-    assertEquals(3, message.getInt32ToEnumField().size());
-    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1));
-    assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3));
-    assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumField().get(4));
+    assertEquals(3, message.getInt32ToEnumFieldMap().size());
+    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumFieldMap().get(1));
+    assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumFieldMap().get(3));
+    assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumFieldMap().get(4));
 
-    assertEquals(3, message.getInt32ToMessageField().size());
-    assertEquals(111, message.getInt32ToMessageField().get(1).getValue());
-    assertEquals(33, message.getInt32ToMessageField().get(3).getValue());
-    assertEquals(44, message.getInt32ToMessageField().get(4).getValue());
+    assertEquals(3, message.getInt32ToMessageFieldMap().size());
+    assertEquals(111, message.getInt32ToMessageFieldMap().get(1).getValue());
+    assertEquals(33, message.getInt32ToMessageFieldMap().get(3).getValue());
+    assertEquals(44, message.getInt32ToMessageFieldMap().get(4).getValue());
 
-    assertEquals(3, message.getStringToInt32Field().size());
-    assertEquals(111, message.getStringToInt32Field().get("1").intValue());
-    assertEquals(33, message.getStringToInt32Field().get("3").intValue());
-    assertEquals(44, message.getStringToInt32Field().get("4").intValue());
+    assertEquals(3, message.getStringToInt32FieldMap().size());
+    assertEquals(111, message.getStringToInt32FieldMap().get("1").intValue());
+    assertEquals(33, message.getStringToInt32FieldMap().get("3").intValue());
+    assertEquals(44, message.getStringToInt32FieldMap().get("4").intValue());
   }
 
   private void assertMapValuesCleared(TestMapOrBuilder testMapOrBuilder) {
@@ -468,11 +468,13 @@ public class MapTest extends TestCase {
             .build();
 
     TestMap destination =
-        TestMap.newBuilder().putAllInt32ToEnumFieldValue(source.getInt32ToEnumFieldValue()).build();
+        TestMap.newBuilder()
+            .putAllInt32ToEnumFieldValue(source.getInt32ToEnumFieldValueMap())
+            .build();
 
-    assertEquals(0, destination.getInt32ToEnumFieldValue().get(0).intValue());
-    assertEquals(1, destination.getInt32ToEnumFieldValue().get(1).intValue());
-    assertEquals(1000, destination.getInt32ToEnumFieldValue().get(2).intValue());
+    assertEquals(0, destination.getInt32ToEnumFieldValueMap().get(0).intValue());
+    assertEquals(1, destination.getInt32ToEnumFieldValueMap().get(1).intValue());
+    assertEquals(1000, destination.getInt32ToEnumFieldValueMap().get(2).intValue());
     assertEquals(3, destination.getInt32ToEnumFieldCount());
   }
 
@@ -583,7 +585,7 @@ public class MapTest extends TestCase {
     } catch (InvalidProtocolBufferException expected) {
       assertTrue(expected.getUnfinishedMessage() instanceof TestMap);
       map = (TestMap) expected.getUnfinishedMessage();
-      assertTrue(map.getInt32ToMessageField().isEmpty());
+      assertTrue(map.getInt32ToMessageFieldMap().isEmpty());
     }
 
     map =
@@ -644,14 +646,14 @@ public class MapTest extends TestCase {
     TestOnChangeEventPropagation.Builder parent = TestOnChangeEventPropagation.newBuilder();
     parent.getOptionalMessageBuilder().putInt32ToInt32Field(1, 2);
     TestOnChangeEventPropagation message = parent.build();
-    assertEquals(2, message.getOptionalMessage().getInt32ToInt32Field().get(1).intValue());
+    assertEquals(2, message.getOptionalMessage().getInt32ToInt32FieldMap().get(1).intValue());
 
     // Make a change using nested builder.
     parent.getOptionalMessageBuilder().putInt32ToInt32Field(1, 3);
 
     // Should be able to observe the change.
     message = parent.build();
-    assertEquals(3, message.getOptionalMessage().getInt32ToInt32Field().get(1).intValue());
+    assertEquals(3, message.getOptionalMessage().getInt32ToInt32FieldMap().get(1).intValue());
 
     // Make another change using mergeFrom()
     TestMap other = TestMap.newBuilder().putInt32ToInt32Field(1, 4).build();
@@ -659,14 +661,14 @@ public class MapTest extends TestCase {
 
     // Should be able to observe the change.
     message = parent.build();
-    assertEquals(4, message.getOptionalMessage().getInt32ToInt32Field().get(1).intValue());
+    assertEquals(4, message.getOptionalMessage().getInt32ToInt32FieldMap().get(1).intValue());
 
     // Make yet another change by clearing the nested builder.
     parent.getOptionalMessageBuilder().clear();
 
     // Should be able to observe the change.
     message = parent.build();
-    assertEquals(0, message.getOptionalMessage().getInt32ToInt32Field().size());
+    assertEquals(0, message.getOptionalMessage().getInt32ToInt32FieldMap().size());
   }
 
   public void testNestedBuilderOnChangeEventPropagationReflection() {
@@ -683,7 +685,7 @@ public class MapTest extends TestCase {
 
     // Should be able to observe the change.
     TestOnChangeEventPropagation message = parentBuilder.build();
-    assertEquals(1, message.getOptionalMessage().getInt32ToInt32Field().size());
+    assertEquals(1, message.getOptionalMessage().getInt32ToInt32FieldMap().size());
 
     // Change the entry value.
     entryBuilder.putInt32ToInt32Field(1, 4);
@@ -692,7 +694,7 @@ public class MapTest extends TestCase {
 
     // Should be able to observe the change.
     message = parentBuilder.build();
-    assertEquals(4, message.getOptionalMessage().getInt32ToInt32Field().get(1).intValue());
+    assertEquals(4, message.getOptionalMessage().getInt32ToInt32FieldMap().get(1).intValue());
 
     // Clear the nested builder.
     testMapBuilder = parentBuilder.getOptionalMessageBuilder();
@@ -700,7 +702,7 @@ public class MapTest extends TestCase {
 
     // Should be able to observe the change.
     message = parentBuilder.build();
-    assertEquals(0, message.getOptionalMessage().getInt32ToInt32Field().size());
+    assertEquals(0, message.getOptionalMessage().getInt32ToInt32FieldMap().size());
   }
 
   // The following methods are used to test reflection API.
@@ -789,8 +791,8 @@ public class MapTest extends TestCase {
     builder.clearField(f("int32_to_int32_field"));
     builder.clearField(f("int32_to_message_field"));
     message = builder.build();
-    assertEquals(0, message.getInt32ToInt32Field().size());
-    assertEquals(0, message.getInt32ToMessageField().size());
+    assertEquals(0, message.getInt32ToInt32FieldMap().size());
+    assertEquals(0, message.getInt32ToMessageFieldMap().size());
 
     // Test setField()
     setMapValues(builder, "int32_to_int32_field", mapForValues(11, 22, 33, 44));
@@ -801,10 +803,10 @@ public class MapTest extends TestCase {
             111, MessageValue.newBuilder().setValue(222).build(),
             333, MessageValue.newBuilder().setValue(444).build()));
     message = builder.build();
-    assertEquals(22, message.getInt32ToInt32Field().get(11).intValue());
-    assertEquals(44, message.getInt32ToInt32Field().get(33).intValue());
-    assertEquals(222, message.getInt32ToMessageField().get(111).getValue());
-    assertEquals(444, message.getInt32ToMessageField().get(333).getValue());
+    assertEquals(22, message.getInt32ToInt32FieldMap().get(11).intValue());
+    assertEquals(44, message.getInt32ToInt32FieldMap().get(33).intValue());
+    assertEquals(222, message.getInt32ToMessageFieldMap().get(111).getValue());
+    assertEquals(444, message.getInt32ToMessageFieldMap().get(333).getValue());
 
     // Test addRepeatedField
     builder.addRepeatedField(
@@ -817,8 +819,8 @@ public class MapTest extends TestCase {
             555,
             MessageValue.newBuilder().setValue(666).build()));
     message = builder.build();
-    assertEquals(66, message.getInt32ToInt32Field().get(55).intValue());
-    assertEquals(666, message.getInt32ToMessageField().get(555).getValue());
+    assertEquals(66, message.getInt32ToInt32FieldMap().get(55).intValue());
+    assertEquals(666, message.getInt32ToMessageFieldMap().get(555).getValue());
 
     // Test addRepeatedField (overriding existing values)
     builder.addRepeatedField(
@@ -831,8 +833,8 @@ public class MapTest extends TestCase {
             555,
             MessageValue.newBuilder().setValue(555).build()));
     message = builder.build();
-    assertEquals(55, message.getInt32ToInt32Field().get(55).intValue());
-    assertEquals(555, message.getInt32ToMessageField().get(555).getValue());
+    assertEquals(55, message.getInt32ToInt32FieldMap().get(55).intValue());
+    assertEquals(555, message.getInt32ToMessageFieldMap().get(555).getValue());
 
     // Test setRepeatedField
     for (int i = 0; i < builder.getRepeatedFieldCount(f("int32_to_int32_field")); i++) {
@@ -846,9 +848,9 @@ public class MapTest extends TestCase {
       builder.setRepeatedField(f("int32_to_int32_field"), i, mapEntryBuilder.build());
     }
     message = builder.build();
-    assertEquals(11, message.getInt32ToInt32Field().get(22).intValue());
-    assertEquals(33, message.getInt32ToInt32Field().get(44).intValue());
-    assertEquals(55, message.getInt32ToInt32Field().get(55).intValue());
+    assertEquals(11, message.getInt32ToInt32FieldMap().get(22).intValue());
+    assertEquals(33, message.getInt32ToInt32FieldMap().get(44).intValue());
+    assertEquals(55, message.getInt32ToInt32FieldMap().get(55).intValue());
   }
 
   // See additional coverage in TextFormatTest.java.
@@ -937,21 +939,21 @@ public class MapTest extends TestCase {
                     2, 1000)); // unknown value.
     TestMap message = builder.build();
 
-    assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumField().get(0));
-    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1));
-    assertEquals(TestMap.EnumValue.UNRECOGNIZED, message.getInt32ToEnumField().get(2));
-    assertEquals(1000, message.getInt32ToEnumFieldValue().get(2).intValue());
+    assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumFieldMap().get(0));
+    assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumFieldMap().get(1));
+    assertEquals(TestMap.EnumValue.UNRECOGNIZED, message.getInt32ToEnumFieldMap().get(2));
+    assertEquals(1000, message.getInt32ToEnumFieldValueMap().get(2).intValue());
 
     // Unknown enum values should be preserved after:
     //   1. Serialization and parsing.
     //   2. toBuild().
     //   3. mergeFrom().
     message = TestMap.parseFrom(message.toByteString());
-    assertEquals(1000, message.getInt32ToEnumFieldValue().get(2).intValue());
+    assertEquals(1000, message.getInt32ToEnumFieldValueMap().get(2).intValue());
     builder = message.toBuilder();
-    assertEquals(1000, builder.getInt32ToEnumFieldValue().get(2).intValue());
+    assertEquals(1000, builder.getInt32ToEnumFieldValueMap().get(2).intValue());
     builder = TestMap.newBuilder().mergeFrom(message);
-    assertEquals(1000, builder.getInt32ToEnumFieldValue().get(2).intValue());
+    assertEquals(1000, builder.getInt32ToEnumFieldValueMap().get(2).intValue());
 
     // hashCode()/equals() should take unknown enum values into account.
     builder.putAllInt32ToEnumFieldValue(newMap(2, 1001));
@@ -960,7 +962,7 @@ public class MapTest extends TestCase {
     assertFalse(message.equals(message2));
     // Unknown values will be converted to UNRECOGNIZED so the resulted enum map
     // should be the same.
-    assertEquals(message2.getInt32ToEnumField(), message.getInt32ToEnumField());
+    assertEquals(message2.getInt32ToEnumFieldMap(), message.getInt32ToEnumFieldMap());
   }
 
   public void testUnknownEnumValuesInReflectionApi() throws Exception {
@@ -991,7 +993,7 @@ public class MapTest extends TestCase {
 
     // Verify that enum values have been successfully updated.
     TestMap message = builder.build();
-    for (Map.Entry<Integer, Integer> entry : message.getInt32ToEnumFieldValue().entrySet()) {
+    for (Map.Entry<Integer, Integer> entry : message.getInt32ToEnumFieldValueMap().entrySet()) {
       assertEquals(data.get(entry.getKey()) + 1, entry.getValue().intValue());
     }
   }
@@ -1002,18 +1004,18 @@ public class MapTest extends TestCase {
     TestMap message = builder.build();
 
     assertEquals(
-        Arrays.asList("1", "2", "3"), new ArrayList<>(message.getStringToInt32Field().keySet()));
+        Arrays.asList("1", "2", "3"), new ArrayList<>(message.getStringToInt32FieldMap().keySet()));
   }
 
   public void testGetMap() {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
-    assertEquals(message.getStringToInt32Field(), message.getStringToInt32FieldMap());
-    assertEquals(message.getInt32ToBytesField(), message.getInt32ToBytesFieldMap());
-    assertEquals(message.getInt32ToEnumField(), message.getInt32ToEnumFieldMap());
-    assertEquals(message.getInt32ToEnumFieldValue(), message.getInt32ToEnumFieldValueMap());
-    assertEquals(message.getInt32ToMessageField(), message.getInt32ToMessageFieldMap());
+    assertEquals(message.getStringToInt32FieldMap(), message.getStringToInt32FieldMap());
+    assertEquals(message.getInt32ToBytesFieldMap(), message.getInt32ToBytesFieldMap());
+    assertEquals(message.getInt32ToEnumFieldMap(), message.getInt32ToEnumFieldMap());
+    assertEquals(message.getInt32ToEnumFieldValueMap(), message.getInt32ToEnumFieldValueMap());
+    assertEquals(message.getInt32ToMessageFieldMap(), message.getInt32ToMessageFieldMap());
   }
 
   public void testContains() {

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

@@ -30,6 +30,7 @@
 
 package com.google.protobuf;
 
+import static com.google.common.truth.Truth.assertThat;
 import static com.google.protobuf.TestUtil.TEST_REQUIRED_INITIALIZED;
 import static com.google.protobuf.TestUtil.TEST_REQUIRED_UNINITIALIZED;
 
@@ -866,6 +867,12 @@ public class TextFormatTest extends TestCase {
     assertEquals(bytes(0xe1, 0x88, 0xb4), TextFormat.unescapeBytes("\\341\\210\\264"));
     assertEquals("\u1234", TextFormat.unescapeText("\\xe1\\x88\\xb4"));
     assertEquals(bytes(0xe1, 0x88, 0xb4), TextFormat.unescapeBytes("\\xe1\\x88\\xb4"));
+    assertEquals("\u1234", TextFormat.unescapeText("\\u1234"));
+    assertEquals(bytes(0xe1, 0x88, 0xb4), TextFormat.unescapeBytes("\\u1234"));
+    assertEquals(bytes(0xe1, 0x88, 0xb4), TextFormat.unescapeBytes("\\U00001234"));
+    assertEquals(
+        new String(new int[] {0x10437}, 0, 1), TextFormat.unescapeText("\\xf0\\x90\\x90\\xb7"));
+    assertEquals(bytes(0xf0, 0x90, 0x90, 0xb7), TextFormat.unescapeBytes("\\U00010437"));
 
     // Handling of strings with unescaped Unicode characters > 255.
     final String zh = "\u9999\u6e2f\u4e0a\u6d77\ud84f\udf80\u8c50\u9280\u884c";
@@ -893,6 +900,87 @@ public class TextFormatTest extends TestCase {
     } catch (TextFormat.InvalidEscapeSequenceException e) {
       // success
     }
+
+    try {
+      TextFormat.unescapeText("\\u");
+      fail("Should have thrown an exception.");
+    } catch (TextFormat.InvalidEscapeSequenceException e) {
+      assertThat(e)
+          .hasMessageThat()
+          .isEqualTo("Invalid escape sequence: '\\u' with too few hex chars");
+    }
+
+    try {
+      TextFormat.unescapeText("\\ud800");
+      fail("Should have thrown an exception.");
+    } catch (TextFormat.InvalidEscapeSequenceException e) {
+      assertThat(e)
+          .hasMessageThat()
+          .isEqualTo("Invalid escape sequence: '\\u' refers to a surrogate");
+    }
+
+    try {
+      TextFormat.unescapeText("\\ud800\\u1234");
+      fail("Should have thrown an exception.");
+    } catch (TextFormat.InvalidEscapeSequenceException e) {
+      assertThat(e)
+          .hasMessageThat()
+          .isEqualTo("Invalid escape sequence: '\\u' refers to a surrogate");
+    }
+
+    try {
+      TextFormat.unescapeText("\\udc00");
+      fail("Should have thrown an exception.");
+    } catch (TextFormat.InvalidEscapeSequenceException e) {
+      assertThat(e)
+          .hasMessageThat()
+          .isEqualTo("Invalid escape sequence: '\\u' refers to a surrogate");
+    }
+
+    try {
+      TextFormat.unescapeText("\\ud801\\udc37");
+      fail("Should have thrown an exception.");
+    } catch (TextFormat.InvalidEscapeSequenceException e) {
+      assertThat(e)
+          .hasMessageThat()
+          .isEqualTo("Invalid escape sequence: '\\u' refers to a surrogate");
+    }
+
+    try {
+      TextFormat.unescapeText("\\U1234");
+      fail("Should have thrown an exception.");
+    } catch (TextFormat.InvalidEscapeSequenceException e) {
+      assertThat(e)
+          .hasMessageThat()
+          .isEqualTo("Invalid escape sequence: '\\U' with too few hex chars");
+    }
+
+    try {
+      TextFormat.unescapeText("\\U1234no more hex");
+      fail("Should have thrown an exception.");
+    } catch (TextFormat.InvalidEscapeSequenceException e) {
+      assertThat(e)
+          .hasMessageThat()
+          .isEqualTo("Invalid escape sequence: '\\U' with too few hex chars");
+    }
+
+    try {
+      TextFormat.unescapeText("\\U00110000");
+      fail("Should have thrown an exception.");
+    } catch (TextFormat.InvalidEscapeSequenceException e) {
+      assertThat(e)
+          .hasMessageThat()
+          .isEqualTo("Invalid escape sequence: '\\U00110000' is not a valid code point value");
+    }
+
+    try {
+      TextFormat.unescapeText("\\U0000d801\\U00000dc37");
+      fail("Should have thrown an exception.");
+    } catch (TextFormat.InvalidEscapeSequenceException e) {
+      assertThat(e)
+          .hasMessageThat()
+          .isEqualTo("Invalid escape sequence: '\\U0000d801' refers to a surrogate code unit");
+    }
   }
 
   public void testParseInteger() throws Exception {

+ 42 - 26
java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java

@@ -137,11 +137,19 @@ final class FieldMaskTree {
   }
 
   /**
-   * Remove {@code path} from the tree.
+   * Removes {@code path} from the tree.
    *
-   * <p>When removing a field path from the tree, all sub-paths will be removed. That is, after
-   * removing "foo.bar" from the tree, "foo.bar.baz" will be removed. Likewise, if the field path to
-   * remove is a non-exist sub-path, nothing will be changed.
+   * <ul>
+   *   When removing a field path from the tree:
+   *   <li>All sub-paths will be removed. That is, after removing "foo.bar" from the tree,
+   *       "foo.bar.baz" will be removed.
+   *   <li>If all children of a node has been removed, the node itself will be removed as well.
+   *       That is, if "foo" only has one child "bar" and "foo.bar" only has one child "baz",
+   *       removing "foo.bar.barz" would remove both "foo" and "foo.bar".
+   *       If "foo" has both "bar" and "qux" as children, removing "foo.bar" would leave the path
+   *       "foo.qux" intact.
+   *   <li>If the field path to remove is a non-exist sub-path, nothing will be changed.
+   * </ul>
    */
   @CanIgnoreReturnValue
   FieldMaskTree removeFieldPath(String path) {
@@ -149,23 +157,35 @@ final class FieldMaskTree {
     if (parts.isEmpty()) {
       return this;
     }
-    Node node = root;
-    for (int i = 0; i < parts.size(); i++) {
-      String key = parts.get(i);
-      if (!node.children.containsKey(key)) {
-        // Path does not exist.
-        return this;
-      }
-      if (i == parts.size() - 1) {
-        // Remove path.
-        node.children.remove(key);
-        return this;
-      }
-      node = node.children.get(key);
-    }
+    removeFieldPath(root, parts, 0);
     return this;
   }
 
+  /**
+   * Removes {@code parts} from {@code node} recursively.
+   *
+   * @return a boolean value indicating whether current {@code node} should be removed.
+   */
+  @CanIgnoreReturnValue
+  private static boolean removeFieldPath(Node node, List<String> parts, int index) {
+    String key = parts.get(index);
+
+    // Base case 1: path not match.
+    if (!node.children.containsKey(key)) {
+      return false;
+    }
+    // Base case 2: last element in parts.
+    if (index == parts.size() - 1) {
+      node.children.remove(key);
+      return node.children.isEmpty();
+    }
+    // Recursive remove sub-path.
+    if (removeFieldPath(node.children.get(key), parts, index + 1)) {
+      node.children.remove(key);
+    }
+    return node.children.isEmpty();
+  }
+
   /** Removes all field paths in {@code mask} from this tree. */
   @CanIgnoreReturnValue
   FieldMaskTree removeFromFieldMask(FieldMask mask) {
@@ -187,10 +207,8 @@ final class FieldMaskTree {
     return FieldMask.newBuilder().addAllPaths(paths).build();
   }
 
-  /**
-   * Gathers all field paths in a sub-tree.
-   */
-  private void getFieldPaths(Node node, String path, List<String> paths) {
+  /** Gathers all field paths in a sub-tree. */
+  private static void getFieldPaths(Node node, String path, List<String> paths) {
     if (node.children.isEmpty()) {
       paths.add(path);
       return;
@@ -247,10 +265,8 @@ final class FieldMaskTree {
     merge(root, "", source, destination, options);
   }
 
-  /**
-   * Merges all fields specified by a sub-tree from {@code source} to {@code destination}.
-   */
-  private void merge(
+  /** Merges all fields specified by a sub-tree from {@code source} to {@code destination}. */
+  private static void merge(
       Node node,
       String path,
       Message source,

+ 7 - 1
java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java

@@ -276,7 +276,13 @@ public final class FieldMaskUtil {
     return maskTree.toFieldMask();
   }
 
-  /** Subtracts {@code secondMask} and {@code otherMasks} from {@code firstMask}. */
+  /**
+   * Subtracts {@code secondMask} and {@code otherMasks} from {@code firstMask}.
+   *
+   * <p>This method disregards proto structure. That is, if {@code firstMask} is "foo" and {@code
+   * secondMask} is "foo.bar", the response will always be "foo" without considering the internal
+   * proto structure of message "foo".
+   */
   public static FieldMask subtract(
       FieldMask firstMask, FieldMask secondMask, FieldMask... otherMasks) {
     FieldMaskTree maskTree = new FieldMaskTree(firstMask).removeFromFieldMask(secondMask);

+ 0 - 1
java/util/src/main/java/com/google/protobuf/util/JsonFormat.java

@@ -525,7 +525,6 @@ public class JsonFormat {
       return types.get(name);
     }
 
-    /* @Nullable */
     Descriptor getDescriptorForTypeUrl(String typeUrl) throws InvalidProtocolBufferException {
       return find(getTypeName(typeUrl));
     }

+ 18 - 6
java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java

@@ -77,25 +77,37 @@ public class FieldMaskTreeTest extends TestCase {
 
   public void testRemoveFieldPath() throws Exception {
     String initialTreeString = "bar.baz,bar.quz.bar,foo";
-    FieldMaskTree tree = new FieldMaskTree(FieldMaskUtil.fromString(initialTreeString));
+    FieldMaskTree tree;
+
     // Empty path.
+    tree = new FieldMaskTree(FieldMaskUtil.fromString(initialTreeString));
     tree.removeFieldPath("");
     assertEquals(initialTreeString, tree.toString());
+
     // Non-exist sub-path of an existing leaf.
+    tree = new FieldMaskTree(FieldMaskUtil.fromString(initialTreeString));
     tree.removeFieldPath("foo.bar");
     assertEquals(initialTreeString, tree.toString());
+
     // Non-exist path.
+    tree = new FieldMaskTree(FieldMaskUtil.fromString(initialTreeString));
     tree.removeFieldPath("bar.foo");
     assertEquals(initialTreeString, tree.toString());
-    // Match an existing leaf node.
+
+    // Match an existing leaf node -> remove leaf node.
+    tree = new FieldMaskTree(FieldMaskUtil.fromString(initialTreeString));
     tree.removeFieldPath("foo");
     assertEquals("bar.baz,bar.quz.bar", tree.toString());
-    // Match sub-path of an existing leaf node.
+
+    // Match sub-path of an existing leaf node -> recursive removal.
+    tree = new FieldMaskTree(FieldMaskUtil.fromString(initialTreeString));
     tree.removeFieldPath("bar.quz.bar");
-    assertEquals("bar.baz,bar.quz", tree.toString());
-    // Match a non-leaf node.
+    assertEquals("bar.baz,foo", tree.toString());
+
+    // Match a non-leaf node -> remove all children.
+    tree = new FieldMaskTree(FieldMaskUtil.fromString(initialTreeString));
     tree.removeFieldPath("bar");
-    assertThat(tree.toString()).isEmpty();
+    assertEquals("foo", tree.toString());
   }
 
   public void testRemoveFromFieldMask() throws Exception {

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

@@ -239,7 +239,7 @@ public class FieldMaskUtilTest extends TestCase {
     FieldMask mask3 = FieldMaskUtil.fromString("bar.quz");
     FieldMask mask4 = FieldMaskUtil.fromString("foo,bar.baz");
     FieldMask result = FieldMaskUtil.subtract(mask1, mask2, mask3, mask4);
-    assertEquals("bar", FieldMaskUtil.toString(result));
+    assertThat(FieldMaskUtil.toString(result)).isEmpty();
   }
 
   public void testIntersection() throws Exception {

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

@@ -722,8 +722,8 @@ public class JsonFormatTest extends TestCase {
     mergeFromJson(
         "{\n" + "  int32ToInt32Map: {1: 2},\n" + "  stringToInt32Map: {hello: 3}\n" + "}", builder);
     TestMap message = builder.build();
-    assertEquals(2, message.getInt32ToInt32Map().get(1).intValue());
-    assertEquals(3, message.getStringToInt32Map().get("hello").intValue());
+    assertEquals(2, message.getInt32ToInt32MapMap().get(1).intValue());
+    assertEquals(3, message.getStringToInt32MapMap().get("hello").intValue());
   }
 
   public void testWrappers() throws Exception {

+ 9 - 1
kokoro/linux/dockerfile/test/python27/Dockerfile

@@ -20,4 +20,12 @@ RUN apt-get update && apt-get install -y \
   parallel \
   time \
   wget \
-  && apt-get clean
+  && apt-get clean \
+  && rm -rf /var/lib/apt/lists/*
+
+# Install Python libraries.
+RUN python -m pip install --no-cache-dir --upgrade \
+  pip \
+  setuptools \
+  tox \
+  wheel

+ 9 - 1
kokoro/linux/dockerfile/test/python35/Dockerfile

@@ -20,4 +20,12 @@ RUN apt-get update && apt-get install -y \
   parallel \
   time \
   wget \
-  && apt-get clean
+  && apt-get clean \
+  && rm -rf /var/lib/apt/lists/*
+
+# Install Python libraries.
+RUN python -m pip install --no-cache-dir --upgrade \
+  pip \
+  setuptools \
+  tox \
+  wheel

+ 9 - 1
kokoro/linux/dockerfile/test/python36/Dockerfile

@@ -20,4 +20,12 @@ RUN apt-get update && apt-get install -y \
   parallel \
   time \
   wget \
-  && apt-get clean
+  && apt-get clean \
+  && rm -rf /var/lib/apt/lists/*
+
+# Install Python libraries.
+RUN python -m pip install --no-cache-dir --upgrade \
+  pip \
+  setuptools \
+  tox \
+  wheel

+ 9 - 1
kokoro/linux/dockerfile/test/python37/Dockerfile

@@ -20,4 +20,12 @@ RUN apt-get update && apt-get install -y \
   parallel \
   time \
   wget \
-  && apt-get clean
+  && apt-get clean \
+  && rm -rf /var/lib/apt/lists/*
+
+# Install Python libraries.
+RUN python -m pip install --no-cache-dir --upgrade \
+  pip \
+  setuptools \
+  tox \
+  wheel

+ 9 - 1
kokoro/linux/dockerfile/test/python38/Dockerfile

@@ -20,4 +20,12 @@ RUN apt-get update && apt-get install -y \
   parallel \
   time \
   wget \
-  && apt-get clean
+  && apt-get clean \
+  && rm -rf /var/lib/apt/lists/*
+
+# Install Python libraries.
+RUN python -m pip install --no-cache-dir --upgrade \
+  pip \
+  setuptools \
+  tox \
+  wheel

+ 1 - 1
kokoro/linux/python27/continuous.cfg

@@ -1,7 +1,7 @@
 # Config file for running tests in Kokoro
 
 # Location of the build script in repository
-build_file: "protobuf/kokoro/linux/python/build.sh"
+build_file: "protobuf/kokoro/linux/python27/build.sh"
 timeout_mins: 120
 
 action {

+ 1 - 1
kokoro/linux/python27/presubmit.cfg

@@ -1,7 +1,7 @@
 # Config file for running tests in Kokoro
 
 # Location of the build script in repository
-build_file: "protobuf/kokoro/linux/python/build.sh"
+build_file: "protobuf/kokoro/linux/python27/build.sh"
 timeout_mins: 120
 
 action {

+ 1 - 1
kokoro/linux/python27_cpp/continuous.cfg

@@ -1,7 +1,7 @@
 # Config file for running tests in Kokoro
 
 # Location of the build script in repository
-build_file: "protobuf/kokoro/linux/python_cpp/build.sh"
+build_file: "protobuf/kokoro/linux/python27_cpp/build.sh"
 timeout_mins: 120
 
 action {

+ 1 - 1
kokoro/linux/python27_cpp/presubmit.cfg

@@ -1,7 +1,7 @@
 # Config file for running tests in Kokoro
 
 # Location of the build script in repository
-build_file: "protobuf/kokoro/linux/python_cpp/build.sh"
+build_file: "protobuf/kokoro/linux/python27_cpp/build.sh"
 timeout_mins: 120
 
 action {

+ 1 - 1
kokoro/linux/python35/continuous.cfg

@@ -1,7 +1,7 @@
 # Config file for running tests in Kokoro
 
 # Location of the build script in repository
-build_file: "protobuf/kokoro/linux/python/build.sh"
+build_file: "protobuf/kokoro/linux/python35/build.sh"
 timeout_mins: 120
 
 action {

+ 1 - 1
kokoro/linux/python35/presubmit.cfg

@@ -1,7 +1,7 @@
 # Config file for running tests in Kokoro
 
 # Location of the build script in repository
-build_file: "protobuf/kokoro/linux/python/build.sh"
+build_file: "protobuf/kokoro/linux/python35/build.sh"
 timeout_mins: 120
 
 action {

+ 1 - 1
kokoro/linux/python35_cpp/continuous.cfg

@@ -1,7 +1,7 @@
 # Config file for running tests in Kokoro
 
 # Location of the build script in repository
-build_file: "protobuf/kokoro/linux/python_cpp/build.sh"
+build_file: "protobuf/kokoro/linux/python35_cpp/build.sh"
 timeout_mins: 120
 
 action {

+ 1 - 1
kokoro/linux/python35_cpp/presubmit.cfg

@@ -1,7 +1,7 @@
 # Config file for running tests in Kokoro
 
 # Location of the build script in repository
-build_file: "protobuf/kokoro/linux/python_cpp/build.sh"
+build_file: "protobuf/kokoro/linux/python35_cpp/build.sh"
 timeout_mins: 120
 
 action {

+ 1 - 1
kokoro/linux/python36/continuous.cfg

@@ -1,7 +1,7 @@
 # Config file for running tests in Kokoro
 
 # Location of the build script in repository
-build_file: "protobuf/kokoro/linux/python/build.sh"
+build_file: "protobuf/kokoro/linux/python36/build.sh"
 timeout_mins: 120
 
 action {

+ 1 - 1
kokoro/linux/python36/presubmit.cfg

@@ -1,7 +1,7 @@
 # Config file for running tests in Kokoro
 
 # Location of the build script in repository
-build_file: "protobuf/kokoro/linux/python/build.sh"
+build_file: "protobuf/kokoro/linux/python36/build.sh"
 timeout_mins: 120
 
 action {

+ 1 - 1
kokoro/linux/python36_cpp/continuous.cfg

@@ -1,7 +1,7 @@
 # Config file for running tests in Kokoro
 
 # Location of the build script in repository
-build_file: "protobuf/kokoro/linux/python_cpp/build.sh"
+build_file: "protobuf/kokoro/linux/python36_cpp/build.sh"
 timeout_mins: 120
 
 action {

+ 1 - 1
kokoro/linux/python36_cpp/presubmit.cfg

@@ -1,7 +1,7 @@
 # Config file for running tests in Kokoro
 
 # Location of the build script in repository
-build_file: "protobuf/kokoro/linux/python_cpp/build.sh"
+build_file: "protobuf/kokoro/linux/python36_cpp/build.sh"
 timeout_mins: 120
 
 action {

+ 1 - 1
kokoro/linux/python37/continuous.cfg

@@ -1,7 +1,7 @@
 # Config file for running tests in Kokoro
 
 # Location of the build script in repository
-build_file: "protobuf/kokoro/linux/python/build.sh"
+build_file: "protobuf/kokoro/linux/python37/build.sh"
 timeout_mins: 120
 
 action {

+ 1 - 1
kokoro/linux/python37/presubmit.cfg

@@ -1,7 +1,7 @@
 # Config file for running tests in Kokoro
 
 # Location of the build script in repository
-build_file: "protobuf/kokoro/linux/python/build.sh"
+build_file: "protobuf/kokoro/linux/python37/build.sh"
 timeout_mins: 120
 
 action {

+ 1 - 1
kokoro/linux/python37_cpp/continuous.cfg

@@ -1,7 +1,7 @@
 # Config file for running tests in Kokoro
 
 # Location of the build script in repository
-build_file: "protobuf/kokoro/linux/python_cpp/build.sh"
+build_file: "protobuf/kokoro/linux/python37_cpp/build.sh"
 timeout_mins: 120
 
 action {

+ 1 - 1
kokoro/linux/python37_cpp/presubmit.cfg

@@ -1,7 +1,7 @@
 # Config file for running tests in Kokoro
 
 # Location of the build script in repository
-build_file: "protobuf/kokoro/linux/python_cpp/build.sh"
+build_file: "protobuf/kokoro/linux/python37_cpp/build.sh"
 timeout_mins: 120
 
 action {

+ 1 - 1
kokoro/linux/python38/continuous.cfg

@@ -1,7 +1,7 @@
 # Config file for running tests in Kokoro
 
 # Location of the build script in repository
-build_file: "protobuf/kokoro/linux/python/build.sh"
+build_file: "protobuf/kokoro/linux/python38/build.sh"
 timeout_mins: 120
 
 action {

+ 1 - 1
kokoro/linux/python38/presubmit.cfg

@@ -1,7 +1,7 @@
 # Config file for running tests in Kokoro
 
 # Location of the build script in repository
-build_file: "protobuf/kokoro/linux/python/build.sh"
+build_file: "protobuf/kokoro/linux/python38/build.sh"
 timeout_mins: 120
 
 action {

+ 1 - 1
kokoro/linux/python38_cpp/continuous.cfg

@@ -1,7 +1,7 @@
 # Config file for running tests in Kokoro
 
 # Location of the build script in repository
-build_file: "protobuf/kokoro/linux/python_cpp/build.sh"
+build_file: "protobuf/kokoro/linux/python38_cpp/build.sh"
 timeout_mins: 120
 
 action {

+ 1 - 1
kokoro/linux/python38_cpp/presubmit.cfg

@@ -1,7 +1,7 @@
 # Config file for running tests in Kokoro
 
 # Location of the build script in repository
-build_file: "protobuf/kokoro/linux/python_cpp/build.sh"
+build_file: "protobuf/kokoro/linux/python38_cpp/build.sh"
 timeout_mins: 120
 
 action {

+ 0 - 11
kokoro/macos/php5.6_mac/build.sh

@@ -1,11 +0,0 @@
-#!/bin/bash
-#
-# Build file to set up and run tests
-
-# Change to repo root
-cd $(dirname $0)/../../..
-
-# Prepare worker environment to run tests
-source kokoro/macos/prepare_build_macos_rc
-
-./tests.sh php5.6_mac

+ 0 - 5
kokoro/macos/php5.6_mac/continuous.cfg

@@ -1,5 +0,0 @@
-# Config file for running tests in Kokoro
-
-# Location of the build script in repository
-build_file: "protobuf/kokoro/macos/php5.6_mac/build.sh"
-timeout_mins: 1440

+ 0 - 5
kokoro/macos/php5.6_mac/presubmit.cfg

@@ -1,5 +0,0 @@
-# Config file for running tests in Kokoro
-
-# Location of the build script in repository
-build_file: "protobuf/kokoro/macos/php5.6_mac/build.sh"
-timeout_mins: 1440

+ 2 - 2
php/ext/google/protobuf/message.c

@@ -356,14 +356,14 @@ static PROTO_RETURN_VAL Message_write_property(
   }
 
   upb_msg_set(intern->msg, f, msgval, arena);
-#if PHP_VERSION_ID < 704000
+#if PHP_VERSION_ID < 70400
   return;
 #else
   return val;
 #endif
 
 error:
-#if PHP_VERSION_ID < 704000
+#if PHP_VERSION_ID < 70400
   return;
 #else
   return &EG(error_zval);

+ 17 - 3
php/ext/google/protobuf/package.xml

@@ -10,11 +10,11 @@
   <email>protobuf-opensource@google.com</email>
   <active>yes</active>
  </lead>
- <date>2020-08-14</date>
+ <date>2020-10-08</date>
  <time>14:07:59</time>
  <version>
-  <release>3.13.0</release>
-  <api>3.13.0</api>
+  <release>3.13.0.1</release>
+  <api>3.13.0.1</api>
  </version>
  <stability>
   <release>stable</release>
@@ -675,5 +675,19 @@ G  A release.
    <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
    <notes>GA release.</notes>
   </release>
+  <release>
+   <version>
+    <release>3.13.0.1</release>
+    <api>3.13.0.1</api>
+   </version>
+   <stability>
+    <release>stable</release>
+    <api>stable</api>
+   </stability>
+   <date>2020-10-08</date>
+   <time>14:07:59</time>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <notes>GA release.</notes>
+  </release>
  </changelog>
 </package>

+ 2 - 2
php/ext/google/protobuf/protobuf.h

@@ -56,7 +56,7 @@ const zval *get_generated_pool();
 // instead of zval* and zend_string* instead of zval* for property names.
 // https://github.com/php/php-src/blob/php-8.0.0beta1/UPGRADING.INTERNALS#L37-L39
 #if PHP_VERSION_ID < 80000
-#define PROTO_VAL zval 
+#define PROTO_VAL zval
 #define PROTO_STR zval
 #define PROTO_MSG_P(obj) (Message*)Z_OBJ_P(obj)
 #define PROTO_STRVAL_P(obj) Z_STRVAL_P(obj)
@@ -69,7 +69,7 @@ const zval *get_generated_pool();
 #define PROTO_STRLEN_P(obj) ZSTR_LEN(obj)
 #endif
 
-#define PHP_PROTOBUF_VERSION "3.13.0"
+#define PHP_PROTOBUF_VERSION "3.13.0.1"
 
 // ptr -> PHP object cache. This is a weak map that caches lazily-created
 // wrapper objects around upb types:

+ 2 - 2
php/release.sh

@@ -10,8 +10,8 @@ set -ex
 
 VERSION=$1
 
-git clone git@github.com:protocolbuffers/protobuf-php.git
-git clone git@github.com:protocolbuffers/protobuf.git
+git clone https://github.com/protocolbuffers/protobuf-php.git
+git clone https://github.com/protocolbuffers/protobuf.git
 
 # Clean old files
 pushd protobuf-php

+ 1 - 1
python/google/protobuf/pyext/message.cc

@@ -809,7 +809,7 @@ bool CheckAndSetString(
     return false;
   }
 
-  string value_string(value, value_len);
+  std::string value_string(value, value_len);
   if (append) {
     reflection->AddString(message, descriptor, std::move(value_string));
   } else if (index < 0) {

+ 2 - 1
python/google/protobuf/text_format.py

@@ -883,7 +883,8 @@ class _Parser(object):
                                                   (expanded_any_end_token,))
         self._MergeField(tokenizer, expanded_any_sub_message)
       message.Pack(expanded_any_sub_message,
-                   type_url_prefix=type_url_prefix)
+                   type_url_prefix=type_url_prefix,
+                   deterministic=True)
       return
 
     if tokenizer.TryConsume('['):

+ 16 - 1
python/protobuf_distutils/README.md

@@ -103,4 +103,19 @@ $ python -m pip install .
 
   By default, the protoc binary (the Protobuf compiler) is found by
   searching the environment path. To use a specific protoc binary, its
-  path can be specified.
+  path can be specified. Resolution of the `protoc` value is as follows:
+  1. If the `--protoc=VALUE` flag is passed to `generate_py_protobufs`,
+     then `VALUE` will be used.
+     For example:
+     ```shell
+     $ python setup.py generate_py_protobufs --protoc=/path/to/protoc
+     ```
+  2. Otherwise, if a value was set in the `options`, it will be used.
+     (See "Example setup.py configuration," above.)
+  3. Otherwise, if the `PROTOC` environment variable is set, it will be
+     used. For example:
+     For example:
+     ```shell
+     $ PROTOC=/path/to/protoc python setup.py generate_py_protobufs
+     ```
+  4. Otherwise, `$PATH` will be searched.

+ 4 - 1
python/tox.ini

@@ -14,7 +14,10 @@ setenv =
 commands =
     python setup.py -q build_py
     python: python setup.py -q build
-    cpp: python setup.py -q build --cpp_implementation --warnings_as_errors --compile_static_extension
+    # --warnings_as_errors disabled until we update the Python C extension. See:
+    # https://github.com/protocolbuffers/protobuf/issues/7930
+    # cpp: python setup.py -q build --cpp_implementation --warnings_as_errors --compile_static_extension
+    cpp: python setup.py -q build --cpp_implementation --compile_static_extension
     python: python setup.py -q test -q
     cpp: python setup.py -q test -q --cpp_implementation
     python: python setup.py -q test_conformance

+ 2 - 1
src/google/protobuf/any.h

@@ -60,7 +60,8 @@ class PROTOBUF_EXPORT AnyMetadata {
   typedef ArenaStringPtr ValueType;
  public:
   // AnyMetadata does not take ownership of "type_url" and "value".
-  AnyMetadata(UrlType* type_url, ValueType* value);
+  constexpr AnyMetadata(UrlType* type_url, ValueType* value)
+      : type_url_(type_url), value_(value) {}
 
   // Packs a message using the default type URL prefix: "type.googleapis.com".
   // The resulted type URL will be "type.googleapis.com/<message_full_name>".

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

@@ -53,9 +53,6 @@ const char kAnyFullTypeName[] = "google.protobuf.Any";
 const char kTypeGoogleApisComPrefix[] = "type.googleapis.com/";
 const char kTypeGoogleProdComPrefix[] = "type.googleprod.com/";
 
-AnyMetadata::AnyMetadata(UrlType* type_url, ValueType* value)
-    : type_url_(type_url), value_(value) {}
-
 void AnyMetadata::InternalPackFrom(const MessageLite& message,
                                    StringPiece type_url_prefix,
                                    StringPiece type_name) {

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

@@ -33,10 +33,18 @@
 #include <gtest/gtest.h>
 
 
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
 namespace google {
 namespace protobuf {
 namespace {
 
+TEST(AnyMetadataTest, ConstInit) {
+  PROTOBUF_CONSTINIT static internal::AnyMetadata metadata(nullptr, nullptr);
+  (void)metadata;
+}
+
 TEST(AnyTest, TestPackAndUnpack) {
   protobuf_unittest::TestAny submessage;
   submessage.set_int32_value(12345);

+ 28 - 6
src/google/protobuf/arena.cc

@@ -47,6 +47,10 @@ static const size_t kMaxCleanupListElements = 64;  // 1kB on 64-bit.
 
 namespace google {
 namespace protobuf {
+
+PROTOBUF_EXPORT /*static*/ void* (*const ArenaOptions::kDefaultBlockAlloc)(
+    size_t) = &::operator new;
+
 namespace internal {
 
 const size_t ArenaImpl::kBlockHeaderSize;
@@ -54,7 +58,7 @@ const size_t ArenaImpl::kSerialArenaSize;
 const size_t ArenaImpl::kOptionsSize;
 
 
-std::atomic<LifecycleId> ArenaImpl::lifecycle_id_generator_;
+ArenaImpl::CacheAlignedLifecycleIdGenerator ArenaImpl::lifecycle_id_generator_;
 #if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
 ArenaImpl::ThreadCache& ArenaImpl::thread_cache() {
   static internal::ThreadLocalStorage<ThreadCache>* thread_cache_ =
@@ -63,12 +67,13 @@ ArenaImpl::ThreadCache& ArenaImpl::thread_cache() {
 }
 #elif defined(PROTOBUF_USE_DLLS)
 ArenaImpl::ThreadCache& ArenaImpl::thread_cache() {
-  static PROTOBUF_THREAD_LOCAL ThreadCache thread_cache_ = {-1, NULL};
+  static PROTOBUF_THREAD_LOCAL ThreadCache thread_cache_ = {
+      0, static_cast<LifecycleIdAtomic>(-1), nullptr};
   return thread_cache_;
 }
 #else
-PROTOBUF_THREAD_LOCAL ArenaImpl::ThreadCache ArenaImpl::thread_cache_ = {-1,
-                                                                         NULL};
+PROTOBUF_THREAD_LOCAL ArenaImpl::ThreadCache ArenaImpl::thread_cache_ = {
+    0, static_cast<LifecycleIdAtomic>(-1), nullptr};
 #endif
 
 void ArenaFree(void* object, size_t size) {
@@ -122,9 +127,26 @@ ArenaImpl::ArenaImpl(const ArenaOptions& options) {
 }
 
 void ArenaImpl::Init(bool record_allocs) {
+  ThreadCache& tc = thread_cache();
+  auto id = tc.next_lifecycle_id;
+  constexpr uint64 kInc = ThreadCache::kPerThreadIds * 2;
+  if (PROTOBUF_PREDICT_FALSE((id & (kInc - 1)) == 0)) {
+    if (sizeof(lifecycle_id_generator_.id) == 4) {
+      // 2^32 is dangerous low to guarantee uniqueness. If we start dolling out
+      // unique id's in ranges of kInc it's unacceptably low. In this case
+      // we increment by 1. The additional range of kPerThreadIds that are used
+      // per thread effectively pushes the overflow time from weeks to years
+      // of continuous running.
+      id = lifecycle_id_generator_.id.fetch_add(1, std::memory_order_relaxed) *
+           kInc;
+    } else {
+      id =
+          lifecycle_id_generator_.id.fetch_add(kInc, std::memory_order_relaxed);
+    }
+  }
+  tc.next_lifecycle_id = id + 2;
   // We store "record_allocs" in the low bit of lifecycle_id_.
-  auto id = lifecycle_id_generator_.fetch_add(1, std::memory_order_relaxed);
-  lifecycle_id_ = (id << 1) | (record_allocs ? 1 : 0);
+  lifecycle_id_ = id | (record_allocs ? 1 : 0);
   hint_.store(nullptr, std::memory_order_relaxed);
   threads_.store(nullptr, std::memory_order_relaxed);
   space_allocated_.store(0, std::memory_order_relaxed);

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

@@ -142,10 +142,12 @@ struct ArenaOptions {
         max_block_size(kDefaultMaxBlockSize),
         initial_block(NULL),
         initial_block_size(0),
-        block_alloc(&::operator new),
+        block_alloc(kDefaultBlockAlloc),
         block_dealloc(&internal::ArenaFree),
         make_metrics_collector(nullptr) {}
 
+  PROTOBUF_EXPORT static void* (*const kDefaultBlockAlloc)(size_t);
+
  private:
   // If make_metrics_collector is not nullptr, it will be called at Arena init
   // time. It may return a pointer to a collector instance that will be notified

+ 29 - 6
src/google/protobuf/arena_impl.h

@@ -58,7 +58,7 @@ inline size_t AlignUpTo8(size_t n) {
   return (n + 7) & static_cast<size_t>(-8);
 }
 
-using LifecycleId = int64_t;
+using LifecycleIdAtomic = uint64_t;
 
 void PROTOBUF_EXPORT ArenaFree(void* object, size_t size);
 
@@ -328,20 +328,43 @@ class PROTOBUF_EXPORT ArenaImpl {
     ArenaMetricsCollector* metrics_collector;
   };
 
-  struct ThreadCache {
+#ifdef _MSC_VER
+#pragma warning(disable:4324)
+#endif
+  struct alignas(64) ThreadCache {
 #if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
     // If we are using the ThreadLocalStorage class to store the ThreadCache,
     // then the ThreadCache's default constructor has to be responsible for
     // initializing it.
-    ThreadCache() : last_lifecycle_id_seen(-1), last_serial_arena(NULL) {}
+    ThreadCache()
+        : next_lifecycle_id(0),
+          last_lifecycle_id_seen(-1),
+          last_serial_arena(NULL) {}
 #endif
 
+    // Number of per-thread lifecycle IDs to reserve. Must be power of two.
+    // To reduce contention on a global atomic, each thread reserves a batch of
+    // IDs.  The following number is caluculated based on a stress test with
+    // ~6500 threads all frequently allocating a new arena.
+    static constexpr size_t kPerThreadIds = 256;
+    // Next lifecycle ID available to this thread. We need to reserve a new
+    // batch, if `next_lifecycle_id & (kPerThreadIds - 1) == 0`.
+    uint64 next_lifecycle_id;
     // The ThreadCache is considered valid as long as this matches the
     // lifecycle_id of the arena being used.
-    LifecycleId last_lifecycle_id_seen;
+    uint64 last_lifecycle_id_seen;
     SerialArena* last_serial_arena;
   };
-  static std::atomic<LifecycleId> lifecycle_id_generator_;
+  // Lifecycle_id can be highly contended variable in a situation of lots of
+  // arena creation. Make sure that other global variables are not sharing the
+  // cacheline.
+#ifdef _MSC_VER
+#pragma warning(disable:4324)
+#endif
+  struct alignas(64) CacheAlignedLifecycleIdGenerator {
+    std::atomic<LifecycleIdAtomic> id;
+  };
+  static CacheAlignedLifecycleIdGenerator lifecycle_id_generator_;
 #if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
   // Android ndk does not support __thread keyword so we use a custom thread
   // local storage class we implemented.
@@ -430,7 +453,7 @@ class PROTOBUF_EXPORT ArenaImpl {
 
   // Unique for each arena. Changes on Reset().
   // Least-significant-bit is 1 iff allocations should be recorded.
-  LifecycleId lifecycle_id_;
+  uint64 lifecycle_id_;
 
   Options* options_ = nullptr;
 

+ 15 - 10
src/google/protobuf/arenastring.h

@@ -87,22 +87,27 @@ class PROTOBUF_EXPORT LazyString {
 template <typename T>
 class TaggedPtr {
  public:
+  TaggedPtr() = default;
+  explicit constexpr TaggedPtr(const std::string* ptr)
+      : ptr_(const_cast<std::string*>(ptr)) {}
+
   void SetTagged(T* p) {
     Set(p);
-    ptr_ |= 1;
+    ptr_ = reinterpret_cast<void*>(as_int() | 1);
   }
-  void Set(T* p) { ptr_ = reinterpret_cast<uintptr_t>(p); }
-  T* Get() const { return reinterpret_cast<T*>(ptr_ & -2); }
-  bool IsTagged() const { return ptr_ & 1; }
+  void Set(T* p) { ptr_ = p; }
+  T* Get() const { return reinterpret_cast<T*>(as_int() & -2); }
+  bool IsTagged() const { return as_int() & 1; }
 
   // Returned value is only safe to dereference if IsTagged() == false.
   // It is safe to compare.
-  T* UnsafeGet() const { return reinterpret_cast<T*>(ptr_); }
+  T* UnsafeGet() const { return static_cast<T*>(ptr_); }
 
-  bool IsNull() { return ptr_ == 0; }
+  bool IsNull() { return ptr_ == nullptr; }
 
  private:
-  uintptr_t ptr_;
+  uintptr_t as_int() const { return reinterpret_cast<uintptr_t>(ptr_); }
+  void* ptr_;
 };
 
 static_assert(std::is_trivial<TaggedPtr<std::string>>::value,
@@ -165,9 +170,9 @@ static_assert(std::is_trivial<TaggedPtr<std::string>>::value,
 // single "cmp %reg, GLOBAL" in the resulting machine code. (Note that this also
 // requires the String tag to be 0 so we can avoid the mask before comparing.)
 struct PROTOBUF_EXPORT ArenaStringPtr {
-  // No default constructor or destructor -- we have to be POD because we go
-  // into a union when used in a oneof. Message code calls UnsafeReset() to zero
-  // the pointer when necessary instead.
+  ArenaStringPtr() = default;
+  explicit constexpr ArenaStringPtr(const std::string* default_value)
+      : tagged_ptr_(default_value) {}
 
   // Some methods below are overloaded on a `default_value` and on tags.
   // The tagged overloads help reduce code size in the callers in generated

+ 3 - 0
src/google/protobuf/arenastring_unittest.cc

@@ -45,6 +45,9 @@
 #include <google/protobuf/stubs/strutil.h>
 
 
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
 namespace google {
 namespace protobuf {
 

+ 5 - 1
src/google/protobuf/compiler/command_line_interface_unittest.cc

@@ -47,6 +47,7 @@
 #include <google/protobuf/testing/file.h>
 #include <google/protobuf/testing/file.h>
 #include <google/protobuf/testing/file.h>
+#include <google/protobuf/any.pb.h>
 #include <google/protobuf/compiler/mock_code_generator.h>
 #include <google/protobuf/compiler/subprocess.h>
 #include <google/protobuf/compiler/code_generator.h>
@@ -123,7 +124,7 @@ class CommandLineInterfaceTest : public testing::Test {
   void SwitchToTempDirectory() {
     File::ChangeWorkingDirectory(temp_directory_);
   }
-#else   // !PROTOBUF_OPENSOURCE
+#else  // !PROTOBUF_OPENSOURCE
   // TODO(teboring): Figure out how to change and get working directory in
   // google3.
 #endif  // !PROTOBUF_OPENSOURCE
@@ -681,6 +682,9 @@ TEST_F(CommandLineInterfaceTest, MultipleInputs_UnusedImport_DescriptorSetIn) {
       FileDescriptorProto::descriptor()->file();
   descriptor_file->CopyTo(file_descriptor_set.add_file());
 
+  FileDescriptorProto& any_proto = *file_descriptor_set.add_file();
+  google::protobuf::Any::descriptor()->file()->CopyTo(&any_proto);
+
   const FileDescriptor* custom_file =
       protobuf_unittest::AggregateMessage::descriptor()->file();
   FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();

+ 0 - 4
src/google/protobuf/compiler/cpp/cpp_field.h

@@ -164,10 +164,6 @@ class FieldGenerator {
     return false;
   }
 
-  // Generate code that allocates the fields's default instance.
-  virtual void GenerateDefaultInstanceAllocator(
-      io::Printer* /*printer*/) const {}
-
   // Generate lines to serialize this field directly to the array "target",
   // which are placed within the message's SerializeWithCachedSizesToArray()
   // method. This must also advance "target" past the written bytes.

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

@@ -941,7 +941,6 @@ void FileGenerator::GenerateInitForSCC(const SCC* scc,
     if (scc_analyzer_.GetSCC(message_generators_[i]->descriptor_) != scc) {
       continue;
     }
-    message_generators_[i]->GenerateFieldDefaultInstances(printer);
     format(
         "{\n"
         "  void* ptr = &$1$;\n"

+ 0 - 7
src/google/protobuf/compiler/cpp/cpp_message.cc

@@ -1899,13 +1899,6 @@ int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) {
   return num_field_metadata;
 }
 
-void MessageGenerator::GenerateFieldDefaultInstances(io::Printer* printer) {
-  // Construct the default instances for all fields that need one.
-  for (auto field : FieldRange(descriptor_)) {
-    field_generators_.get(field).GenerateDefaultInstanceAllocator(printer);
-  }
-}
-
 void MessageGenerator::GenerateClassMethods(io::Printer* printer) {
   Formatter format(printer, variables_);
   if (IsMapEntryMessage(descriptor_)) {

+ 0 - 3
src/google/protobuf/compiler/cpp/cpp_message.h

@@ -82,9 +82,6 @@ class MessageGenerator {
 
   // Source file stuff.
 
-  // Generates code that creates default instances for fields.
-  void GenerateFieldDefaultInstances(io::Printer* printer);
-
   // Generate all non-inline methods for this class.
   void GenerateClassMethods(io::Printer* printer);
 

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

@@ -390,6 +390,7 @@ void FileGenerator::Generate(io::Printer* printer) {
   printer->Print("}\n");
 }
 
+
 void FileGenerator::GenerateDescriptorInitializationCodeForImmutable(
     io::Printer* printer) {
   printer->Print(

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

@@ -78,6 +78,7 @@ class FileGenerator {
 
   void Generate(io::Printer* printer);
 
+
   // If we aren't putting everything into one file, this will write all the
   // files other than the outer file (i.e. one for each message, enum, and
   // service type).

+ 58 - 12
src/google/protobuf/compiler/java/java_name_resolver.cc

@@ -160,7 +160,14 @@ std::string ClassNameResolver::GetFileImmutableClassName(
 
 std::string ClassNameResolver::GetFileClassName(const FileDescriptor* file,
                                                 bool immutable) {
-  if (immutable) {
+  return GetFileClassName(file, immutable, false);
+}
+
+std::string ClassNameResolver::GetFileClassName(const FileDescriptor* file,
+                                                bool immutable, bool kotlin) {
+  if (kotlin) {
+    return GetFileImmutableClassName(file) + "Kt";
+  } else if (immutable) {
     return GetFileImmutableClassName(file);
   } else {
     return "Mutable" + GetFileImmutableClassName(file);
@@ -200,9 +207,14 @@ std::string ClassNameResolver::GetDescriptorClassName(
 
 std::string ClassNameResolver::GetClassName(const FileDescriptor* descriptor,
                                             bool immutable) {
+  return GetClassName(descriptor, immutable, false);
+}
+
+std::string ClassNameResolver::GetClassName(const FileDescriptor* descriptor,
+                                            bool immutable, bool kotlin) {
   std::string result = FileJavaPackage(descriptor, immutable);
   if (!result.empty()) result += '.';
-  result += GetFileClassName(descriptor, immutable);
+  result += GetFileClassName(descriptor, immutable, kotlin);
   return result;
 }
 
@@ -211,50 +223,79 @@ std::string ClassNameResolver::GetClassName(const FileDescriptor* descriptor,
 std::string ClassNameResolver::GetClassFullName(
     const std::string& name_without_package, const FileDescriptor* file,
     bool immutable, bool is_own_file) {
+  return GetClassFullName(name_without_package, file, immutable, is_own_file,
+                          false);
+}
+
+std::string ClassNameResolver::GetClassFullName(
+    const std::string& name_without_package, const FileDescriptor* file,
+    bool immutable, bool is_own_file, bool kotlin) {
   std::string result;
   if (is_own_file) {
     result = FileJavaPackage(file, immutable);
   } else {
-    result = GetClassName(file, immutable);
+    result = GetClassName(file, immutable, kotlin);
   }
   if (!result.empty()) {
     result += '.';
   }
   result += name_without_package;
+  if (kotlin) result += "Kt";
   return result;
 }
 
 std::string ClassNameResolver::GetClassName(const Descriptor* descriptor,
                                             bool immutable) {
-  return GetClassFullName(ClassNameWithoutPackage(descriptor, immutable),
-                          descriptor->file(), immutable,
-                          MultipleJavaFiles(descriptor->file(), immutable));
+  return GetClassName(descriptor, immutable, false);
+}
+
+std::string ClassNameResolver::GetClassName(const Descriptor* descriptor,
+                                            bool immutable, bool kotlin) {
+  return GetClassFullName(
+      ClassNameWithoutPackage(descriptor, immutable), descriptor->file(),
+      immutable, MultipleJavaFiles(descriptor->file(), immutable), kotlin);
 }
 
 std::string ClassNameResolver::GetClassName(const EnumDescriptor* descriptor,
                                             bool immutable) {
-  return GetClassFullName(ClassNameWithoutPackage(descriptor, immutable),
-                          descriptor->file(), immutable,
-                          MultipleJavaFiles(descriptor->file(), immutable));
+  return GetClassName(descriptor, immutable, false);
+}
+
+std::string ClassNameResolver::GetClassName(const EnumDescriptor* descriptor,
+                                            bool immutable, bool kotlin) {
+  return GetClassFullName(
+      ClassNameWithoutPackage(descriptor, immutable), descriptor->file(),
+      immutable, MultipleJavaFiles(descriptor->file(), immutable), kotlin);
 }
 
 std::string ClassNameResolver::GetClassName(const ServiceDescriptor* descriptor,
                                             bool immutable) {
+  return GetClassName(descriptor, immutable, false);
+}
+
+std::string ClassNameResolver::GetClassName(const ServiceDescriptor* descriptor,
+                                            bool immutable, bool kotlin) {
   return GetClassFullName(ClassNameWithoutPackage(descriptor, immutable),
                           descriptor->file(), immutable,
-                          IsOwnFile(descriptor, immutable));
+                          IsOwnFile(descriptor, immutable), kotlin);
 }
 
 // Get the Java Class style full name of a message.
 std::string ClassNameResolver::GetJavaClassFullName(
     const std::string& name_without_package, const FileDescriptor* file,
     bool immutable) {
+  return GetJavaClassFullName(name_without_package, file, immutable, false);
+}
+
+std::string ClassNameResolver::GetJavaClassFullName(
+    const std::string& name_without_package, const FileDescriptor* file,
+    bool immutable, bool kotlin) {
   std::string result;
   if (MultipleJavaFiles(file, immutable)) {
     result = FileJavaPackage(file, immutable);
     if (!result.empty()) result += '.';
   } else {
-    result = GetClassName(file, immutable);
+    result = GetClassName(file, immutable, kotlin);
     if (!result.empty()) result += '$';
   }
   result += StringReplace(name_without_package, ".", "$", true);
@@ -263,7 +304,12 @@ std::string ClassNameResolver::GetJavaClassFullName(
 
 std::string ClassNameResolver::GetExtensionIdentifierName(
     const FieldDescriptor* descriptor, bool immutable) {
-  return GetClassName(descriptor->containing_type(), immutable) + "." +
+  return GetExtensionIdentifierName(descriptor, immutable, false);
+}
+
+std::string ClassNameResolver::GetExtensionIdentifierName(
+    const FieldDescriptor* descriptor, bool immutable, bool kotlin) {
+  return GetClassName(descriptor->containing_type(), immutable, kotlin) + "." +
          descriptor->name();
 }
 

+ 18 - 0
src/google/protobuf/compiler/java/java_name_resolver.h

@@ -60,6 +60,8 @@ class ClassNameResolver {
 
   // Gets the unqualified outer class name for the file.
   std::string GetFileClassName(const FileDescriptor* file, bool immutable);
+  std::string GetFileClassName(const FileDescriptor* file, bool immutable,
+                               bool kotlin);
   // Gets the unqualified immutable outer class name of a file.
   std::string GetFileImmutableClassName(const FileDescriptor* file);
   // Gets the unqualified default immutable outer class name of a file
@@ -80,9 +82,17 @@ class ClassNameResolver {
 
   // Gets the fully-qualified class name corresponding to the given descriptor.
   std::string GetClassName(const Descriptor* descriptor, bool immutable);
+  std::string GetClassName(const Descriptor* descriptor, bool immutable,
+                           bool kotlin);
   std::string GetClassName(const EnumDescriptor* descriptor, bool immutable);
+  std::string GetClassName(const EnumDescriptor* descriptor, bool immutable,
+                           bool kotlin);
   std::string GetClassName(const ServiceDescriptor* descriptor, bool immutable);
+  std::string GetClassName(const ServiceDescriptor* descriptor, bool immutable,
+                           bool kotlin);
   std::string GetClassName(const FileDescriptor* descriptor, bool immutable);
+  std::string GetClassName(const FileDescriptor* descriptor, bool immutable,
+                           bool kotlin);
 
   template <class DescriptorType>
   std::string GetImmutableClassName(const DescriptorType* descriptor) {
@@ -96,6 +106,8 @@ class ClassNameResolver {
   // Gets the fully qualified name of an extension identifier.
   std::string GetExtensionIdentifierName(const FieldDescriptor* descriptor,
                                          bool immutable);
+  std::string GetExtensionIdentifierName(const FieldDescriptor* descriptor,
+                                         bool immutable, bool kotlin);
 
   // Gets the fully qualified name for generated classes in Java convention.
   // Nested classes will be separated using '$' instead of '.'
@@ -109,9 +121,15 @@ class ClassNameResolver {
   std::string GetClassFullName(const std::string& name_without_package,
                                const FileDescriptor* file, bool immutable,
                                bool is_own_file);
+  std::string GetClassFullName(const std::string& name_without_package,
+                               const FileDescriptor* file, bool immutable,
+                               bool is_own_file, bool kotlin);
   // Get the Java Class style full name of a message.
   std::string GetJavaClassFullName(const std::string& name_without_package,
                                    const FileDescriptor* file, bool immutable);
+  std::string GetJavaClassFullName(const std::string& name_without_package,
+                                   const FileDescriptor* file, bool immutable,
+                                   bool kotlin);
   // Caches the result to provide better performance.
   std::map<const FileDescriptor*, std::string>
       file_immutable_outer_class_names_;

+ 1 - 0
src/google/protobuf/compiler/main.cc

@@ -65,6 +65,7 @@ int ProtobufMain(int argc, char* argv[]) {
                         "Generate Java source file.");
 
 
+
   // Proto2 Python
   python::Generator py_generator;
   cli.RegisterGenerator("--python_out", "--python_opt", &py_generator,

+ 6 - 0
src/google/protobuf/compiler/parser_unittest.cc

@@ -41,6 +41,7 @@
 
 #include <google/protobuf/test_util2.h>
 #include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/any.pb.h>
 #include <google/protobuf/unittest_custom_options.pb.h>
 #include <google/protobuf/io/tokenizer.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
@@ -2276,6 +2277,11 @@ TEST_F(ParseDescriptorDebugTest, TestCustomOptions) {
   FileDescriptorProto import_proto;
   import->CopyTo(&import_proto);
   ASSERT_TRUE(pool_.BuildFile(import_proto) != NULL);
+
+  FileDescriptorProto any_import;
+  google::protobuf::Any::descriptor()->file()->CopyTo(&any_import);
+  ASSERT_TRUE(pool_.BuildFile(any_import) != nullptr);
+
   const FileDescriptor* actual = pool_.BuildFile(parsed);
   ASSERT_TRUE(actual != NULL);
   parsed.Clear();

+ 62 - 52
src/google/protobuf/descriptor.cc

@@ -49,6 +49,7 @@
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/stringprintf.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/any.h>
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/tokenizer.h>
@@ -254,14 +255,14 @@ std::string ToCamelCase(const std::string& input, bool lower_first) {
   std::string result;
   result.reserve(input.size());
 
-  for (int i = 0; i < input.size(); i++) {
-    if (input[i] == '_') {
+  for (char character : input) {
+    if (character == '_') {
       capitalize_next = true;
     } else if (capitalize_next) {
-      result.push_back(ToUpper(input[i]));
+      result.push_back(ToUpper(character));
       capitalize_next = false;
     } else {
-      result.push_back(input[i]);
+      result.push_back(character);
     }
   }
 
@@ -278,14 +279,14 @@ std::string ToJsonName(const std::string& input) {
   std::string result;
   result.reserve(input.size());
 
-  for (int i = 0; i < input.size(); i++) {
-    if (input[i] == '_') {
+  for (char character : input) {
+    if (character == '_') {
       capitalize_next = true;
     } else if (capitalize_next) {
-      result.push_back(ToUpper(input[i]));
+      result.push_back(ToUpper(character));
       capitalize_next = false;
     } else {
-      result.push_back(input[i]);
+      result.push_back(character);
     }
   }
 
@@ -297,14 +298,14 @@ std::string EnumValueToPascalCase(const std::string& input) {
   std::string result;
   result.reserve(input.size());
 
-  for (int i = 0; i < input.size(); i++) {
-    if (input[i] == '_') {
+  for (char character : input) {
+    if (character == '_') {
       next_upper = true;
     } else {
       if (next_upper) {
-        result.push_back(ToUpper(input[i]));
+        result.push_back(ToUpper(character));
       } else {
-        result.push_back(ToLower(input[i]));
+        result.push_back(ToLower(character));
       }
       next_upper = false;
     }
@@ -318,9 +319,9 @@ class PrefixRemover {
  public:
   PrefixRemover(StringPiece prefix) {
     // Strip underscores and lower-case the prefix.
-    for (int i = 0; i < prefix.size(); i++) {
-      if (prefix[i] != '_') {
-        prefix_ += ascii_tolower(prefix[i]);
+    for (char character : prefix) {
+      if (character != '_') {
+        prefix_ += ascii_tolower(character);
       }
     }
   }
@@ -471,16 +472,15 @@ std::set<std::string>* NewAllowedProto3Extendee() {
   const char* kOptionNames[] = {
       "FileOptions",      "MessageOptions", "FieldOptions",  "EnumOptions",
       "EnumValueOptions", "ServiceOptions", "MethodOptions", "OneofOptions"};
-  for (int i = 0; i < GOOGLE_ARRAYSIZE(kOptionNames); ++i) {
+  for (const char* option_name : kOptionNames) {
     // descriptor.proto has a different package name in opensource. We allow
     // both so the opensource protocol compiler can also compile internal
     // proto3 files with custom options. See: b/27567912
     allowed_proto3_extendees->insert(std::string("google.protobuf.") +
-                                     kOptionNames[i]);
+                                     option_name);
     // Split the word to trick the opensource processing scripts so they
     // will keep the original package name.
-    allowed_proto3_extendees->insert(std::string("proto") + "2." +
-                                     kOptionNames[i]);
+    allowed_proto3_extendees->insert(std::string("proto") + "2." + option_name);
   }
   return allowed_proto3_extendees;
 }
@@ -1571,8 +1571,7 @@ void DescriptorPool::FindAllExtensions(
     std::vector<int> numbers;
     if (fallback_database_->FindAllExtensionNumbers(extendee->full_name(),
                                                     &numbers)) {
-      for (int i = 0; i < numbers.size(); ++i) {
-        int number = numbers[i];
+      for (int number : numbers) {
         if (tables_->FindExtension(extendee, number) == nullptr) {
           TryFindExtensionInFallbackDatabase(extendee, number);
         }
@@ -2279,34 +2278,34 @@ bool RetrieveOptionsAssumingRightPool(
   const Reflection* reflection = options.GetReflection();
   std::vector<const FieldDescriptor*> fields;
   reflection->ListFields(options, &fields);
-  for (int i = 0; i < fields.size(); i++) {
+  for (const FieldDescriptor* field : fields) {
     int count = 1;
     bool repeated = false;
-    if (fields[i]->is_repeated()) {
-      count = reflection->FieldSize(options, fields[i]);
+    if (field->is_repeated()) {
+      count = reflection->FieldSize(options, field);
       repeated = true;
     }
     for (int j = 0; j < count; j++) {
       std::string fieldval;
-      if (fields[i]->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
         std::string tmp;
         TextFormat::Printer printer;
         printer.SetInitialIndentLevel(depth + 1);
-        printer.PrintFieldValueToString(options, fields[i], repeated ? j : -1,
+        printer.PrintFieldValueToString(options, field, repeated ? j : -1,
                                         &tmp);
         fieldval.append("{\n");
         fieldval.append(tmp);
         fieldval.append(depth * 2, ' ');
         fieldval.append("}");
       } else {
-        TextFormat::PrintFieldValueToString(options, fields[i],
-                                            repeated ? j : -1, &fieldval);
+        TextFormat::PrintFieldValueToString(options, field, repeated ? j : -1,
+                                            &fieldval);
       }
       std::string name;
-      if (fields[i]->is_extension()) {
-        name = "(." + fields[i]->full_name() + ")";
+      if (field->is_extension()) {
+        name = "(." + field->full_name() + ")";
       } else {
-        name = fields[i]->name();
+        name = field->name();
       }
       option_entries->push_back(name + " = " + fieldval);
     }
@@ -2363,9 +2362,8 @@ bool FormatLineOptions(int depth, const Message& options,
   std::string prefix(depth * 2, ' ');
   std::vector<std::string> all_options;
   if (RetrieveOptions(depth, options, pool, &all_options)) {
-    for (int i = 0; i < all_options.size(); i++) {
-      strings::SubstituteAndAppend(output, "$0option $1;\n", prefix,
-                                all_options[i]);
+    for (const std::string& option : all_options) {
+      strings::SubstituteAndAppend(output, "$0option $1;\n", prefix, option);
     }
   }
   return !all_options.empty();
@@ -2395,8 +2393,9 @@ class SourceLocationCommentPrinter {
   void AddPreComment(std::string* output) {
     if (have_source_loc_) {
       // Detached leading comments.
-      for (int i = 0; i < source_loc_.leading_detached_comments.size(); ++i) {
-        *output += FormatComment(source_loc_.leading_detached_comments[i]);
+      for (const std::string& leading_detached_comment :
+           source_loc_.leading_detached_comments) {
+        *output += FormatComment(leading_detached_comment);
         *output += "\n";
       }
       // Attached leading comments.
@@ -2418,8 +2417,7 @@ class SourceLocationCommentPrinter {
     StripWhitespace(&stripped_comment);
     std::vector<std::string> lines = Split(stripped_comment, "\n");
     std::string output;
-    for (int i = 0; i < lines.size(); ++i) {
-      const std::string& line = lines[i];
+    for (const std::string& line : lines) {
       strings::SubstituteAndAppend(&output, "$0// $1\n", prefix_, line);
     }
     return output;
@@ -3866,13 +3864,13 @@ Symbol DescriptorBuilder::LookupSymbol(
 static bool ValidateQualifiedName(StringPiece name) {
   bool last_was_period = false;
 
-  for (int i = 0; i < name.size(); i++) {
+  for (char character : name) {
     // I don't trust isalnum() due to locales.  :(
-    if (('a' <= name[i] && name[i] <= 'z') ||
-        ('A' <= name[i] && name[i] <= 'Z') ||
-        ('0' <= name[i] && name[i] <= '9') || (name[i] == '_')) {
+    if (('a' <= character && character <= 'z') ||
+        ('A' <= character && character <= 'Z') ||
+        ('0' <= character && character <= '9') || (character == '_')) {
       last_was_period = false;
-    } else if (name[i] == '.') {
+    } else if (character == '.') {
       if (last_was_period) return false;
       last_was_period = true;
     } else {
@@ -4096,11 +4094,11 @@ void DescriptorBuilder::ValidateSymbolName(const std::string& name,
     AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME,
              "Missing name.");
   } else {
-    for (int i = 0; i < name.size(); i++) {
+    for (char character : name) {
       // I don't trust isalnum() due to locales.  :(
-      if ((name[i] < 'a' || 'z' < name[i]) &&
-          (name[i] < 'A' || 'Z' < name[i]) &&
-          (name[i] < '0' || '9' < name[i]) && (name[i] != '_')) {
+      if ((character < 'a' || 'z' < character) &&
+          (character < 'A' || 'Z' < character) &&
+          (character < '0' || '9' < character) && (character != '_')) {
         AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME,
                  "\"" + name + "\" is not a valid identifier.");
       }
@@ -5945,12 +5943,12 @@ void DescriptorBuilder::ValidateProto3(FileDescriptor* file,
 
 static std::string ToLowercaseWithoutUnderscores(const std::string& name) {
   std::string result;
-  for (int i = 0; i < name.size(); ++i) {
-    if (name[i] != '_') {
-      if (name[i] >= 'A' && name[i] <= 'Z') {
-        result.push_back(name[i] - 'A' + 'a');
+  for (char character : name) {
+    if (character != '_') {
+      if (character >= 'A' && character <= 'Z') {
+        result.push_back(character - 'A' + 'a');
       } else {
-        result.push_back(name[i]);
+        result.push_back(character);
       }
     }
   }
@@ -7067,6 +7065,18 @@ class DescriptorBuilder::OptionInterpreter::AggregateOptionFinder
  public:
   DescriptorBuilder* builder_;
 
+  const Descriptor* FindAnyType(const Message& message,
+                                const std::string& prefix,
+                                const std::string& name) const override {
+    if (prefix != internal::kTypeGoogleApisComPrefix &&
+        prefix != internal::kTypeGoogleProdComPrefix) {
+      return nullptr;
+    }
+    assert_mutex_held(builder_->pool_);
+    Symbol result = builder_->FindSymbol(name);
+    return result.type == Symbol::MESSAGE ? result.descriptor : nullptr;
+  }
+
   const FieldDescriptor* FindExtension(Message* message,
                                        const std::string& name) const override {
     assert_mutex_held(builder_->pool_);

+ 9 - 11
src/google/protobuf/descriptor_database.cc

@@ -552,11 +552,9 @@ class EncodedDescriptorDatabase::DescriptorIndex {
 
 bool EncodedDescriptorDatabase::Add(const void* encoded_file_descriptor,
                                     int size) {
-  google::protobuf::Arena arena;
-  auto* file = google::protobuf::Arena::CreateMessage<FileDescriptorProto>(&arena);
-  if (file->ParseFromArray(encoded_file_descriptor, size)) {
-    return index_->AddFile(*file,
-                           std::make_pair(encoded_file_descriptor, size));
+  FileDescriptorProto file;
+  if (file.ParseFromArray(encoded_file_descriptor, size)) {
+    return index_->AddFile(file, std::make_pair(encoded_file_descriptor, size));
   } else {
     GOOGLE_LOG(ERROR) << "Invalid file descriptor data passed to "
                   "EncodedDescriptorDatabase::Add().";
@@ -933,8 +931,8 @@ bool DescriptorPoolDatabase::FindAllExtensionNumbers(
   std::vector<const FieldDescriptor*> extensions;
   pool_.FindAllExtensions(extendee, &extensions);
 
-  for (int i = 0; i < extensions.size(); ++i) {
-    output->push_back(extensions[i]->number());
+  for (const FieldDescriptor* extension : extensions) {
+    output->push_back(extension->number());
   }
 
   return true;
@@ -954,8 +952,8 @@ MergedDescriptorDatabase::~MergedDescriptorDatabase() {}
 
 bool MergedDescriptorDatabase::FindFileByName(const std::string& filename,
                                               FileDescriptorProto* output) {
-  for (int i = 0; i < sources_.size(); i++) {
-    if (sources_[i]->FindFileByName(filename, output)) {
+  for (DescriptorDatabase* source : sources_) {
+    if (source->FindFileByName(filename, output)) {
       return true;
     }
   }
@@ -1012,8 +1010,8 @@ bool MergedDescriptorDatabase::FindAllExtensionNumbers(
   std::vector<int> results;
   bool success = false;
 
-  for (int i = 0; i < sources_.size(); i++) {
-    if (sources_[i]->FindAllExtensionNumbers(extendee_type, &results)) {
+  for (DescriptorDatabase* source : sources_) {
+    if (source->FindAllExtensionNumbers(extendee_type, &results)) {
       std::copy(results.begin(), results.end(),
                 std::insert_iterator<std::set<int> >(merged_results,
                                                      merged_results.begin()));

+ 30 - 5
src/google/protobuf/descriptor_unittest.cc

@@ -38,6 +38,7 @@
 #include <memory>
 #include <vector>
 
+#include <google/protobuf/any.pb.h>
 #include <google/protobuf/compiler/importer.h>
 #include <google/protobuf/compiler/parser.h>
 #include <google/protobuf/unittest.pb.h>
@@ -287,9 +288,8 @@ class MockErrorCollector : public DescriptorPool::ErrorCollector {
         break;
     }
 
-    strings::SubstituteAndAppend(&warning_text_, "$0: $1: $2: $3\n",
-                                       filename, element_name, location_name,
-                                       message);
+    strings::SubstituteAndAppend(&warning_text_, "$0: $1: $2: $3\n", filename,
+                              element_name, location_name, message);
   }
 };
 
@@ -3148,6 +3148,11 @@ TEST(CustomOptions, OptionsFromOtherFile) {
   FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
   ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
 
+  // We have to import the Any dependency.
+  FileDescriptorProto any_proto;
+  google::protobuf::Any::descriptor()->file()->CopyTo(&any_proto);
+  ASSERT_TRUE(pool.BuildFile(any_proto) != nullptr);
+
   protobuf_unittest::TestMessageWithCustomOptions::descriptor()->file()->CopyTo(
       &file_proto);
   ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
@@ -3206,6 +3211,10 @@ TEST(CustomOptions, MessageOptionThreeFieldsSet) {
   FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
   ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
 
+  FileDescriptorProto any_proto;
+  google::protobuf::Any::descriptor()->file()->CopyTo(&any_proto);
+  ASSERT_TRUE(pool.BuildFile(any_proto) != nullptr);
+
   protobuf_unittest::TestMessageWithCustomOptions::descriptor()->file()->CopyTo(
       &file_proto);
   ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
@@ -3283,6 +3292,10 @@ TEST(CustomOptions, MessageOptionRepeatedLeafFieldSet) {
   FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
   ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
 
+  FileDescriptorProto any_proto;
+  google::protobuf::Any::descriptor()->file()->CopyTo(&any_proto);
+  ASSERT_TRUE(pool.BuildFile(any_proto) != nullptr);
+
   protobuf_unittest::TestMessageWithCustomOptions::descriptor()->file()->CopyTo(
       &file_proto);
   ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
@@ -3363,6 +3376,10 @@ TEST(CustomOptions, MessageOptionRepeatedMsgFieldSet) {
   FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
   ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
 
+  FileDescriptorProto any_proto;
+  google::protobuf::Any::descriptor()->file()->CopyTo(&any_proto);
+  ASSERT_TRUE(pool.BuildFile(any_proto) != nullptr);
+
   protobuf_unittest::TestMessageWithCustomOptions::descriptor()->file()->CopyTo(
       &file_proto);
   ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
@@ -3463,6 +3480,10 @@ TEST(CustomOptions, AggregateOptions) {
                                   message_set_extension)
                 .s());
 
+  protobuf_unittest::AggregateMessageSetElement any_payload;
+  ASSERT_TRUE(file_options.any().UnpackTo(&any_payload));
+  EXPECT_EQ("EmbeddedMessageSetElement", any_payload.s());
+
   // Simple tests for all the other types of annotations
   EXPECT_EQ("MessageAnnotation",
             msg->options().GetExtension(protobuf_unittest::msgopt).s());
@@ -3485,6 +3506,10 @@ TEST(CustomOptions, UnusedImportError) {
   FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
   ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
 
+  FileDescriptorProto any_proto;
+  google::protobuf::Any::descriptor()->file()->CopyTo(&any_proto);
+  ASSERT_TRUE(pool.BuildFile(any_proto) != nullptr);
+
   protobuf_unittest::TestMessageWithCustomOptions::descriptor()->file()->CopyTo(
       &file_proto);
   ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
@@ -7182,8 +7207,8 @@ class SourceLocationTest : public testing::Test {
 
   static std::string PrintSourceLocation(const SourceLocation& loc) {
     return strings::Substitute("$0:$1-$2:$3", 1 + loc.start_line,
-                                     1 + loc.start_column, 1 + loc.end_line,
-                                     1 + loc.end_column);
+                            1 + loc.start_column, 1 + loc.end_line,
+                            1 + loc.end_column);
   }
 
  private:

+ 0 - 8
src/google/protobuf/extension_set.cc

@@ -192,14 +192,6 @@ ExtensionSet::ExtensionSet(Arena* arena)
                ? NULL
                : Arena::CreateArray<KeyValue>(arena_, flat_capacity_)} {}
 
-ExtensionSet::ExtensionSet()
-    : arena_(NULL),
-      flat_capacity_(0),
-      flat_size_(0),
-      map_{flat_capacity_ == 0
-               ? NULL
-               : Arena::CreateArray<KeyValue>(arena_, flat_capacity_)} {}
-
 ExtensionSet::~ExtensionSet() {
   // Deletes all allocated extensions.
   if (arena_ == NULL) {

+ 4 - 1
src/google/protobuf/extension_set.h

@@ -173,7 +173,7 @@ class MessageSetFieldSkipper;
 // off to the ExtensionSet for parsing.  Etc.
 class PROTOBUF_EXPORT ExtensionSet {
  public:
-  ExtensionSet();
+  constexpr ExtensionSet();
   explicit ExtensionSet(Arena* arena);
   ~ExtensionSet();
 
@@ -850,6 +850,9 @@ class PROTOBUF_EXPORT ExtensionSet {
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionSet);
 };
 
+constexpr ExtensionSet::ExtensionSet()
+    : arena_(nullptr), flat_capacity_(0), flat_size_(0), map_{nullptr} {}
+
 // These are just for convenience...
 inline void ExtensionSet::SetString(int number, FieldType type,
                                     std::string value,

+ 8 - 1
src/google/protobuf/extension_set_unittest.cc

@@ -46,13 +46,15 @@
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/wire_format.h>
-
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
 #include <google/protobuf/stubs/stl_util.h>
 
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
 
 namespace google {
 namespace protobuf {
@@ -1324,6 +1326,11 @@ TEST(ExtensionSetTest, BoolExtension) {
   EXPECT_TRUE(msg.GetExtension(protobuf_unittest::optional_bool_extension));
 }
 
+TEST(ExtensionSetTest, ConstInit) {
+  PROTOBUF_CONSTINIT static ExtensionSet set{};
+  EXPECT_EQ(set.NumExtensions(), 0);
+}
+
 }  // namespace
 }  // namespace internal
 }  // namespace protobuf

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

@@ -1065,6 +1065,7 @@ void Reflection::ListFieldsMayFailOnStripped(
           output->push_back(field);
         }
       } else if (has_bits && has_bits_indices[i] != -1) {
+        CheckInvalidAccess(schema_, field);
         // Equivalent to: HasBit(message, field)
         if (IsIndexInHasBitSet(has_bits, has_bits_indices[i])) {
           output->push_back(field);

+ 13 - 4
src/google/protobuf/generated_message_util.cc

@@ -68,16 +68,25 @@ void DestroyString(const void* s) {
   static_cast<const std::string*>(s)->~basic_string();
 }
 
-ExplicitlyConstructed<std::string> fixed_address_empty_string;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT EmptyString
+    fixed_address_empty_string;  // NOLINT
 
 
+PROTOBUF_CONSTINIT std::atomic<bool> init_protobuf_defaults_state{false};
 static bool InitProtobufDefaultsImpl() {
-  fixed_address_empty_string.DefaultConstruct();
-  OnShutdownDestroyString(fixed_address_empty_string.get_mutable());
+  ::new (static_cast<void*>(&fixed_address_empty_string.value)) std::string();
+  OnShutdownDestroyString(&fixed_address_empty_string.value);
+
+  // Verify that we can indeed get the address during constant evaluation.
+  PROTOBUF_CONSTINIT static const std::string& fixed_address_empty_string_test =
+      GetEmptyStringAlreadyInited();
+  (void)fixed_address_empty_string_test;
+
+  init_protobuf_defaults_state.store(true, std::memory_order_release);
   return true;
 }
 
-void InitProtobufDefaults() {
+void InitProtobufDefaultsSlow() {
   static bool is_inited = InitProtobufDefaultsImpl();
   (void)is_inited;
 }

+ 11 - 1
src/google/protobuf/generated_message_util.h

@@ -85,7 +85,17 @@ inline To DownCast(From& f) {
 }
 
 
-PROTOBUF_EXPORT void InitProtobufDefaults();
+// This fastpath inlines a single branch instead of having to make the
+// InitProtobufDefaults function call.
+// It also generates less inlined code than a function-scope static initializer.
+PROTOBUF_EXPORT extern std::atomic<bool> init_protobuf_defaults_state;
+PROTOBUF_EXPORT void InitProtobufDefaultsSlow();
+PROTOBUF_EXPORT inline void InitProtobufDefaults() {
+  if (PROTOBUF_PREDICT_FALSE(
+          !init_protobuf_defaults_state.load(std::memory_order_acquire))) {
+    InitProtobufDefaultsSlow();
+  }
+}
 
 // This used by proto1
 PROTOBUF_EXPORT inline const std::string& GetEmptyString() {

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

@@ -47,7 +47,7 @@ namespace internal {
 template <size_t doublewords>
 class HasBits {
  public:
-  HasBits() PROTOBUF_ALWAYS_INLINE { Clear(); }
+  constexpr HasBits() PROTOBUF_ALWAYS_INLINE : has_bits_{} {}
 
   void Clear() PROTOBUF_ALWAYS_INLINE {
     memset(has_bits_, 0, sizeof(has_bits_));

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

@@ -129,7 +129,7 @@ class ImplicitWeakTypeHandler {
 template <typename T>
 struct WeakRepeatedPtrField {
   using TypeHandler = internal::ImplicitWeakTypeHandler<T>;
-  WeakRepeatedPtrField() : weak() {}
+  constexpr WeakRepeatedPtrField() : weak() {}
   explicit WeakRepeatedPtrField(Arena* arena) : weak(arena) {}
   ~WeakRepeatedPtrField() { weak.template Destroy<TypeHandler>(); }
 

+ 6 - 5
src/google/protobuf/map.h

@@ -105,8 +105,8 @@ class MapAllocator {
   using size_type = size_t;
   using difference_type = ptrdiff_t;
 
-  MapAllocator() : arena_(nullptr) {}
-  explicit MapAllocator(Arena* arena) : arena_(arena) {}
+  constexpr MapAllocator() : arena_(nullptr) {}
+  explicit constexpr MapAllocator(Arena* arena) : arena_(arena) {}
   template <typename X>
   MapAllocator(const MapAllocator<X>& allocator)  // NOLINT(runtime/explicit)
       : arena_(allocator.arena()) {}
@@ -382,7 +382,7 @@ class Map {
   using size_type = size_t;
   using hasher = typename internal::TransparentSupport<Key>::hash;
 
-  Map() : elements_(nullptr) {}
+  constexpr Map() : elements_(nullptr) {}
   explicit Map(Arena* arena) : elements_(arena) {}
 
   Map(const Map& other) : Map() { insert(other.begin(), other.end()); }
@@ -450,11 +450,11 @@ class Map {
   //    otherwise. This avoids unnecessary copies of string keys, for example.
   class InnerMap : private hasher {
    public:
-    explicit InnerMap(Arena* arena)
+    explicit constexpr InnerMap(Arena* arena)
         : hasher(),
           num_elements_(0),
           num_buckets_(internal::kGlobalEmptyTableSize),
-          seed_(Seed()),
+          seed_(0),
           index_of_first_non_null_(num_buckets_),
           table_(const_cast<void**>(internal::kGlobalEmptyTable)),
           alloc_(arena) {}
@@ -920,6 +920,7 @@ class Map {
         // Just overwrite with a new one. No need to transfer or free anything.
         num_buckets_ = index_of_first_non_null_ = kMinTableSize;
         table_ = CreateEmptyTable(num_buckets_);
+        seed_ = Seed();
         return;
       }
 

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

@@ -93,7 +93,7 @@ template <typename Derived, typename Key, typename Value,
 class MapEntry : public MapEntryImpl<Derived, Message, Key, Value,
                                      kKeyFieldType, kValueFieldType> {
  public:
-  MapEntry() : _internal_metadata_(NULL) {}
+  constexpr MapEntry() : _internal_metadata_() {}
   explicit MapEntry(Arena* arena)
       : MapEntryImpl<Derived, Message, Key, Value, kKeyFieldType,
                      kValueFieldType>(arena),

+ 10 - 11
src/google/protobuf/map_entry_lite.h

@@ -182,17 +182,16 @@ class MapEntryImpl : public Base {
   static const WireFormatLite::FieldType kEntryKeyFieldType = kKeyFieldType;
   static const WireFormatLite::FieldType kEntryValueFieldType = kValueFieldType;
 
-  MapEntryImpl() {
-    KeyTypeHandler::Initialize(&key_, NULL);
-    ValueTypeHandler::Initialize(&value_, NULL);
-    _has_bits_[0] = 0;
-  }
+  constexpr MapEntryImpl()
+      : key_(KeyTypeHandler::Constinit()),
+        value_(ValueTypeHandler::Constinit()),
+        _has_bits_{} {}
 
-  explicit MapEntryImpl(Arena* arena) : Base(arena) {
-    KeyTypeHandler::Initialize(&key_, arena);
-    ValueTypeHandler::Initialize(&value_, arena);
-    _has_bits_[0] = 0;
-  }
+  explicit MapEntryImpl(Arena* arena)
+      : Base(arena),
+        key_(KeyTypeHandler::Constinit()),
+        value_(ValueTypeHandler::Constinit()),
+        _has_bits_{} {}
 
   ~MapEntryImpl() {
     if (Base::GetArena() != NULL) return;
@@ -523,7 +522,7 @@ class MapEntryLite : public MapEntryImpl<T, MessageLite, Key, Value,
   typedef MapEntryImpl<T, MessageLite, Key, Value, kKeyFieldType,
                        kValueFieldType>
       SuperType;
-  MapEntryLite() {}
+  constexpr MapEntryLite() {}
   explicit MapEntryLite(Arena* arena) : SuperType(arena) {}
   ~MapEntryLite() { MessageLite::_internal_metadata_.Delete<std::string>(); }
   void MergeFrom(const MapEntryLite& other) { MergeFromInternal(other); }

+ 22 - 0
src/google/protobuf/map_field.h

@@ -324,6 +324,16 @@ class PROTOBUF_EXPORT MapFieldBase {
  public:
   MapFieldBase()
       : arena_(NULL), repeated_field_(NULL), state_(STATE_MODIFIED_MAP) {}
+
+  // This constructor is for constant initialized global instances.
+  // It uses a linker initialized mutex, so it is not compatible with regular
+  // runtime instances.
+  // Except in MSVC, where we can't have a constinit mutex.
+  explicit PROTOBUF_MAYBE_CONSTEXPR MapFieldBase(ConstantInitialized)
+      : arena_(nullptr),
+        repeated_field_(nullptr),
+        mutex_(GOOGLE_PROTOBUF_LINKER_INITIALIZED),
+        state_(STATE_MODIFIED_MAP) {}
   explicit MapFieldBase(Arena* arena)
       : arena_(arena), repeated_field_(NULL), state_(STATE_MODIFIED_MAP) {
     // Mutex's destructor needs to be called explicitly to release resources
@@ -466,6 +476,12 @@ template <typename Key, typename T>
 class TypeDefinedMapFieldBase : public MapFieldBase {
  public:
   TypeDefinedMapFieldBase() {}
+
+  // This constructor is for constant initialized global instances.
+  // It uses a linker initialized mutex, so it is not compatible with regular
+  // runtime instances.
+  explicit constexpr TypeDefinedMapFieldBase(ConstantInitialized tag)
+      : MapFieldBase(tag) {}
   explicit TypeDefinedMapFieldBase(Arena* arena) : MapFieldBase(arena) {}
   ~TypeDefinedMapFieldBase() override {}
   void MapBegin(MapIterator* map_iter) const override;
@@ -521,6 +537,12 @@ class MapField : public TypeDefinedMapFieldBase<Key, T> {
   typedef Map<Key, T> MapType;
 
   MapField() {}
+
+  // This constructor is for constant initialized global instances.
+  // It uses a linker initialized mutex, so it is not compatible with regular
+  // runtime instances.
+  explicit constexpr MapField(ConstantInitialized tag)
+      : TypeDefinedMapFieldBase<Key, T>(tag), impl_() {}
   explicit MapField(Arena* arena)
       : TypeDefinedMapFieldBase<Key, T>(arena), impl_(arena) {}
 

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

@@ -63,7 +63,7 @@ class MapFieldLite {
   typedef Map<Key, T> MapType;
   typedef EntryType EntryTypeTrait;
 
-  MapFieldLite() {}
+  constexpr MapFieldLite() {}
 
   explicit MapFieldLite(Arena* arena) : map_(arena) {}
 

+ 19 - 0
src/google/protobuf/map_field_test.cc

@@ -45,6 +45,9 @@
 #include <google/protobuf/repeated_field.h>
 #include <gtest/gtest.h>
 
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
 namespace google {
 namespace protobuf {
 
@@ -478,6 +481,22 @@ TEST_P(MapFieldStateTest, MutableMapField) {
   }
 }
 
+class MyMapField
+    : public MapField<unittest::TestMap_MapInt32Int32Entry_DoNotUse, int32,
+                      int32, internal::WireFormatLite::TYPE_INT32,
+                      internal::WireFormatLite::TYPE_INT32> {
+ public:
+  constexpr MyMapField()
+      : MyMapField::MapField(internal::ConstantInitialized{}) {}
+};
+
+TEST(MapFieldTest, ConstInit) {
+  // This tests that `MapField` and all its base classes can be constant
+  // initialized.
+  PROTOBUF_CONSTINIT static MyMapField field;  // NOLINT
+  EXPECT_EQ(field.size(), 0);
+}
+
 
 }  // namespace internal
 }  // namespace protobuf

+ 39 - 0
src/google/protobuf/map_test.cc

@@ -80,6 +80,7 @@
 #include <google/protobuf/stubs/substitute.h>
 
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -1180,6 +1181,11 @@ TEST_F(MapImplTest, TransparentLookupForString) {
   TestTransparent(std::cref(abc), std::cref(lkj));
 }
 
+TEST_F(MapImplTest, ConstInit) {
+  PROTOBUF_CONSTINIT static Map<int, int> map;  // NOLINT
+  EXPECT_TRUE(map.empty());
+}
+
 // Map Field Reflection Test ========================================
 
 static int Func(int i, int j) { return i * j; }
@@ -2047,6 +2053,39 @@ TEST_F(MapFieldReflectionTest, UninitializedEntry) {
   EXPECT_FALSE(message.IsInitialized());
 }
 
+class MyMapEntry
+    : public internal::MapEntry<MyMapEntry, ::google::protobuf::int32, ::google::protobuf::int32,
+                                internal::WireFormatLite::TYPE_INT32,
+                                internal::WireFormatLite::TYPE_INT32> {
+ public:
+  constexpr MyMapEntry() {}
+  MyMapEntry(Arena*) { std::abort(); }
+  Metadata GetMetadata() const override { std::abort(); }
+  static bool ValidateKey(void*) { return true; }
+  static bool ValidateValue(void*) { return true; }
+};
+
+class MyMapEntryLite
+    : public internal::MapEntryLite<MyMapEntryLite, ::google::protobuf::int32, ::google::protobuf::int32,
+                                    internal::WireFormatLite::TYPE_INT32,
+                                    internal::WireFormatLite::TYPE_INT32> {
+ public:
+  constexpr MyMapEntryLite() {}
+  explicit MyMapEntryLite(Arena*) { std::abort(); }
+  static bool ValidateKey(void*) { return true; }
+  static bool ValidateValue(void*) { return true; }
+};
+
+TEST(MapEntryTest, ConstInit) {
+  // This verifies that `MapEntry`, `MapEntryLite` and `MapEntryImpl` can be
+  // constant initialized.
+  PROTOBUF_CONSTINIT static MyMapEntry entry{};
+  EXPECT_NE(entry.SpaceUsed(), 0);
+
+  PROTOBUF_CONSTINIT static MyMapEntryLite entry_lite{};  // NOLINT
+  EXPECT_TRUE(entry_lite.IsInitialized());
+}
+
 // Generated Message Test ===========================================
 
 TEST(GeneratedMapFieldTest, Accessors) {

+ 13 - 13
src/google/protobuf/map_type_handler.h

@@ -157,7 +157,7 @@ class MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type> {
   static inline void DeleteNoArena(const Type* x);
   static inline void Merge(const Type& from, Type** to, Arena* arena);
   static inline void Clear(Type** value, Arena* arena);
-  static inline void Initialize(Type** x, Arena* arena);
+  static constexpr TypeOnMemory Constinit();
 
   static inline Type* EnsureMutable(Type** value, Arena* arena);
   // SpaceUsedInMapEntry: Return bytes used by value in MapEntry, excluding
@@ -207,7 +207,7 @@ class MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type> {
         const TypeOnMemory& value);                                           \
     static inline bool IsInitialized(const TypeOnMemory& value);              \
     static void DeleteNoArena(TypeOnMemory& value);                           \
-    static inline void Initialize(TypeOnMemory* value, Arena* arena);         \
+    static constexpr TypeOnMemory Constinit();                                \
     static inline MapEntryAccessorType* EnsureMutable(TypeOnMemory* value,    \
                                                       Arena* arena);          \
   };
@@ -522,9 +522,9 @@ void MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::DeleteNoArena(
 }
 
 template <typename Type>
-inline void MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Initialize(
-    Type** x, Arena* /* arena */) {
-  *x = NULL;
+constexpr auto MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Constinit()
+    -> TypeOnMemory {
+  return nullptr;
 }
 
 template <typename Type>
@@ -583,10 +583,10 @@ inline bool MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::IsInitialized(
     value.DestroyNoArena(&internal::GetEmptyStringAlreadyInited());           \
   }                                                                           \
   template <typename Type>                                                    \
-  inline void                                                                 \
-  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Initialize(         \
-      TypeOnMemory* value, Arena* /* arena */) {                              \
-    value->UnsafeSetDefault(&internal::GetEmptyStringAlreadyInited());        \
+  constexpr auto                                                              \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Constinit()         \
+      ->TypeOnMemory {                                                        \
+    return TypeOnMemory(&internal::GetEmptyStringAlreadyInited());            \
   }                                                                           \
   template <typename Type>                                                    \
   inline typename MapTypeHandler<WireFormatLite::TYPE_##FieldType,            \
@@ -640,10 +640,10 @@ STRING_OR_BYTES_HANDLER_FUNCTIONS(BYTES)
   inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType,               \
                              Type>::DeleteNoArena(TypeOnMemory& /* x */) {}  \
   template <typename Type>                                                   \
-  inline void                                                                \
-  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Initialize(        \
-      TypeOnMemory* value, Arena* /* arena */) {                             \
-    *value = 0;                                                              \
+  constexpr auto                                                             \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Constinit()        \
+      ->TypeOnMemory {                                                       \
+    return 0;                                                                \
   }                                                                          \
   template <typename Type>                                                   \
   inline typename MapTypeHandler<WireFormatLite::TYPE_##FieldType,           \

+ 1 - 1
src/google/protobuf/message.cc

@@ -162,7 +162,7 @@ size_t Message::SpaceUsedLong() const {
   return GetReflection()->SpaceUsedLong(*this);
 }
 
-size_t Message::GetInvariantPerBuild(size_t salt) {
+uint64 Message::GetInvariantPerBuild(uint64 salt) {
   return salt;
 }
 

部分文件因为文件数量过多而无法显示