Quellcode durchsuchen

Down Integrate to GitHub (#6414)

* Down integrate to GitHub

* Fix broken tests
Paul Yang vor 6 Jahren
Ursprung
Commit
7bff8393ca
100 geänderte Dateien mit 3653 neuen und 1332 gelöschten Zeilen
  1. 2 0
      Makefile.am
  2. BIN
      csharp/src/Google.Protobuf.Test/testprotos.pb
  3. 1 1
      csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs
  4. 480 91
      java/core/src/main/java/com/google/protobuf/FieldSet.java
  5. 90 20
      java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
  6. 2 1
      java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java
  7. 181 15
      java/core/src/main/java/com/google/protobuf/TextFormat.java
  8. 160 0
      java/core/src/main/java/com/google/protobuf/TypeRegistry.java
  9. 154 0
      java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
  10. 5 1
      java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java
  11. 191 0
      java/core/src/test/java/com/google/protobuf/TextFormatTest.java
  12. 70 0
      java/core/src/test/java/com/google/protobuf/TypeRegistryTest.java
  13. 0 2
      java/core/src/test/proto/com/google/protobuf/test_extra_interfaces.proto
  14. 1 0
      java/lite/pom.xml
  15. 113 27
      java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
  16. 50 1
      java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
  17. 54 54
      js/binary/decoder.js
  18. 52 27
      js/binary/decoder_test.js
  19. 34 0
      js/binary/reader.js
  20. 20 0
      js/binary/reader_test.js
  21. 43 24
      js/binary/utils.js
  22. 106 110
      js/binary/utils_test.js
  23. 98 0
      js/binary/writer.js
  24. 71 0
      js/binary/writer_test.js
  25. 72 26
      js/message.js
  26. 1 0
      js/message_test.js
  27. 9 0
      js/test.proto
  28. 1 1
      objectivec/google/protobuf/Duration.pbobjc.h
  29. 7 0
      python/google/protobuf/internal/message_test.py
  30. 1 1
      python/google/protobuf/internal/python_message.py
  31. 2 3
      python/google/protobuf/pyext/map_container.cc
  32. 4 2
      python/google/protobuf/pyext/message.cc
  33. 0 1
      src/Makefile.am
  34. 13 13
      src/google/protobuf/any.pb.cc
  35. 36 8
      src/google/protobuf/any.pb.h
  36. 0 1
      src/google/protobuf/any_lite.cc
  37. 0 1
      src/google/protobuf/any_test.cc
  38. 84 100
      src/google/protobuf/api.pb.cc
  39. 129 28
      src/google/protobuf/api.pb.h
  40. 1 1
      src/google/protobuf/arena.h
  41. 1 3
      src/google/protobuf/compiler/command_line_interface.cc
  42. 2 3
      src/google/protobuf/compiler/command_line_interface_unittest.cc
  43. 0 2
      src/google/protobuf/compiler/cpp/cpp_extension.cc
  44. 0 1
      src/google/protobuf/compiler/cpp/cpp_field.cc
  45. 79 20
      src/google/protobuf/compiler/cpp/cpp_file.cc
  46. 2 1
      src/google/protobuf/compiler/cpp/cpp_file.h
  47. 0 2
      src/google/protobuf/compiler/cpp/cpp_generator.cc
  48. 22 12
      src/google/protobuf/compiler/cpp/cpp_helpers.cc
  49. 14 1
      src/google/protobuf/compiler/cpp/cpp_helpers.h
  50. 51 16
      src/google/protobuf/compiler/cpp/cpp_message.cc
  51. 53 95
      src/google/protobuf/compiler/cpp/cpp_message_field.cc
  52. 0 1
      src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
  53. 103 70
      src/google/protobuf/compiler/cpp/cpp_string_field.cc
  54. 1 1
      src/google/protobuf/compiler/csharp/csharp_doc_comment.cc
  55. 1 1
      src/google/protobuf/compiler/csharp/csharp_helpers.h
  56. 1 1
      src/google/protobuf/compiler/csharp/csharp_names.h
  57. 5 5
      src/google/protobuf/compiler/csharp/csharp_reflection_class.cc
  58. 1 4
      src/google/protobuf/compiler/importer.cc
  59. 0 1
      src/google/protobuf/compiler/java/java_context.cc
  60. 47 33
      src/google/protobuf/compiler/java/java_doc_comment.cc
  61. 20 22
      src/google/protobuf/compiler/java/java_doc_comment.h
  62. 8 3
      src/google/protobuf/compiler/java/java_enum.cc
  63. 1 2
      src/google/protobuf/compiler/java/java_enum_field.cc
  64. 0 1
      src/google/protobuf/compiler/java/java_enum_field_lite.cc
  65. 0 1
      src/google/protobuf/compiler/java/java_enum_lite.cc
  66. 0 1
      src/google/protobuf/compiler/java/java_extension.cc
  67. 0 1
      src/google/protobuf/compiler/java/java_field.cc
  68. 0 1
      src/google/protobuf/compiler/java/java_file.cc
  69. 0 3
      src/google/protobuf/compiler/java/java_helpers.cc
  70. 0 2
      src/google/protobuf/compiler/java/java_message.cc
  71. 0 2
      src/google/protobuf/compiler/java/java_message_builder.cc
  72. 0 1
      src/google/protobuf/compiler/java/java_message_builder_lite.cc
  73. 0 1
      src/google/protobuf/compiler/java/java_message_field_lite.cc
  74. 0 2
      src/google/protobuf/compiler/java/java_message_lite.cc
  75. 0 2
      src/google/protobuf/compiler/java/java_name_resolver.cc
  76. 0 1
      src/google/protobuf/compiler/java/java_primitive_field.cc
  77. 0 1
      src/google/protobuf/compiler/java/java_primitive_field_lite.cc
  78. 0 1
      src/google/protobuf/compiler/java/java_service.cc
  79. 0 1
      src/google/protobuf/compiler/java/java_string_field.cc
  80. 2 3
      src/google/protobuf/compiler/java/java_string_field_lite.cc
  81. 64 74
      src/google/protobuf/compiler/js/js_generator.cc
  82. 0 1
      src/google/protobuf/compiler/mock_code_generator.cc
  83. 2 2
      src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
  84. 0 1
      src/google/protobuf/compiler/parser.cc
  85. 0 1
      src/google/protobuf/compiler/parser_unittest.cc
  86. 1 1
      src/google/protobuf/compiler/php/php_generator.cc
  87. 1 1
      src/google/protobuf/compiler/plugin.cc
  88. 73 81
      src/google/protobuf/compiler/plugin.pb.cc
  89. 186 36
      src/google/protobuf/compiler/plugin.pb.h
  90. 0 2
      src/google/protobuf/compiler/python/python_generator.cc
  91. 4 6
      src/google/protobuf/descriptor.cc
  92. 173 221
      src/google/protobuf/descriptor.pb.cc
  93. 386 0
      src/google/protobuf/descriptor.pb.h
  94. 0 1
      src/google/protobuf/descriptor_database.cc
  95. 1 2
      src/google/protobuf/descriptor_unittest.cc
  96. 1 1
      src/google/protobuf/duration.pb.cc
  97. 1 1
      src/google/protobuf/duration.proto
  98. 1 1
      src/google/protobuf/empty.pb.cc
  99. 1 1
      src/google/protobuf/extension_set.h
  100. 6 13
      src/google/protobuf/extension_set_inl.h

+ 2 - 0
Makefile.am

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

+ 1 - 0
java/lite/pom.xml

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

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

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

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

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

+ 54 - 54
js/binary/decoder.js

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

+ 52 - 27
js/binary/decoder_test.js

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

+ 34 - 0
js/binary/reader.js

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

+ 20 - 0
js/binary/reader_test.js

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

+ 43 - 24
js/binary/utils.js

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

+ 106 - 110
js/binary/utils_test.js

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

+ 98 - 0
js/binary/writer.js

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

+ 71 - 0
js/binary/writer_test.js

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

+ 72 - 26
js/message.js

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

+ 1 - 0
js/message_test.js

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

+ 9 - 0
js/test.proto

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

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

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

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

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

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

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

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

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

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

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

+ 0 - 1
src/Makefile.am

@@ -213,7 +213,6 @@ libprotobuf_lite_la_SOURCES =                                  \
   google/protobuf/repeated_field.cc                            \
   google/protobuf/wire_format_lite.cc                          \
   google/protobuf/io/coded_stream.cc                           \
-  google/protobuf/io/coded_stream_inl.h                        \
   google/protobuf/io/strtod.cc                                 \
   google/protobuf/io/zero_copy_stream.cc                       \
   google/protobuf/io/zero_copy_stream_impl.cc                  \

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@@ -33,11 +33,9 @@
 #include <map>
 #include <string>
 
-
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/stubs/substitute.h>
 
-
 namespace google {
 namespace protobuf {
 namespace compiler {

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

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

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

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

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

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

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

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

+ 2 - 3
src/google/protobuf/compiler/java/java_string_field_lite.cc

@@ -47,7 +47,6 @@
 #include <google/protobuf/wire_format.h>
 #include <google/protobuf/stubs/strutil.h>
 
-
 namespace google {
 namespace protobuf {
 namespace compiler {
@@ -295,7 +294,7 @@ void ImmutableStringFieldLiteGenerator::GenerateBuilderMembers(
   printer->Annotate("{", "}", descriptor_);
 
   WriteFieldStringBytesAccessorDocComment(printer, descriptor_, SETTER,
-                               /* builder */ true);
+                                          /* builder */ true);
   printer->Print(
       variables_,
       "$deprecation$public Builder ${$set$capitalized_name$Bytes$}$(\n"
@@ -476,7 +475,7 @@ void ImmutableStringOneofFieldLiteGenerator::GenerateBuilderMembers(
   printer->Annotate("{", "}", descriptor_);
 
   WriteFieldStringBytesAccessorDocComment(printer, descriptor_, SETTER,
-                               /* builder */ true);
+                                          /* builder */ true);
   printer->Print(
       variables_,
       "$deprecation$public Builder ${$set$capitalized_name$Bytes$}$(\n"

+ 64 - 74
src/google/protobuf/compiler/js/js_generator.cc

@@ -43,7 +43,6 @@
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/stringprintf.h>
 #include <google/protobuf/stubs/strutil.h>
-
 #include <google/protobuf/compiler/scc.h>
 #include <google/protobuf/compiler/js/well_known_types_embed.h>
 #include <google/protobuf/io/printer.h>
@@ -51,7 +50,6 @@
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/descriptor.h>
 
-
 namespace google {
 namespace protobuf {
 namespace compiler {
@@ -1118,9 +1116,6 @@ std::string JSBinaryWriterMethodName(const GeneratorOptions& options,
          JSBinaryReadWriteMethodName(field, /* is_writer = */ true);
 }
 
-std::string JSReturnClause(const FieldDescriptor* desc) {
-  return "";
-}
 
 std::string JSTypeTag(const FieldDescriptor* desc) {
   switch (desc->type()) {
@@ -1156,10 +1151,6 @@ std::string JSTypeTag(const FieldDescriptor* desc) {
   return "";
 }
 
-std::string JSReturnDoc(const GeneratorOptions& options,
-                        const FieldDescriptor* desc) {
-  return "";
-}
 
 bool HasRepeatedFields(const GeneratorOptions& options,
                        const Descriptor* desc) {
@@ -1426,11 +1417,6 @@ bool HasFieldPresence(const GeneratorOptions& options,
     return false;
   }
 
-  if (UseBrokenPresenceSemantics(options, field)) {
-    // Proto3 files with broken presence semantics have field presence.
-    return true;
-  }
-
   return field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ||
          field->containing_oneof() != NULL ||
          field->file()->syntax() == FileDescriptor::SYNTAX_PROTO2;
@@ -2393,7 +2379,7 @@ void Generator::GenerateClassFieldToObject(const GeneratorOptions& options,
     if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 &&
         // Repeated fields get initialized to their default in the constructor
         // (why?), so we emit a plain getField() call for them.
-        !field->is_repeated() && !UseBrokenPresenceSemantics(options, field)) {
+        !field->is_repeated()) {
       // Proto3 puts all defaults (including implicit defaults) in toObject().
       // But for proto2 we leave the existing semantics unchanged: unset fields
       // without default are unset.
@@ -2677,30 +2663,31 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
         (field->label() == FieldDescriptor::LABEL_REQUIRED ? ", 1" : ""));
     printer->Annotate("gettername", field);
     printer->Print(
-        "/** @param {$optionaltype$} value$returndoc$ */\n"
+        "/**\n"
+        " * @param {$optionaltype$} value\n"
+        " * @return {!$class$} returns this\n"
+        "*/\n"
         "$class$.prototype.$settername$ = function(value) {\n"
-        "  jspb.Message.set$oneoftag$$repeatedtag$WrapperField(",
+        "  return jspb.Message.set$oneoftag$$repeatedtag$WrapperField(",
         "optionaltype",
         JSFieldTypeAnnotation(options, field,
                               /* is_setter_argument = */ true,
                               /* force_present = */ false,
                               /* singular_if_not_packed = */ false),
-        "returndoc", JSReturnDoc(options, field), "class",
-        GetMessagePath(options, field->containing_type()), "settername",
-        "set" + JSGetterName(options, field), "oneoftag",
+        "class", GetMessagePath(options, field->containing_type()),
+        "settername", "set" + JSGetterName(options, field), "oneoftag",
         (field->containing_oneof() ? "Oneof" : ""), "repeatedtag",
         (field->is_repeated() ? "Repeated" : ""));
     printer->Annotate("settername", field);
 
     printer->Print(
-        "this, $index$$oneofgroup$, value);$returnvalue$\n"
+        "this, $index$$oneofgroup$, value);\n"
         "};\n"
         "\n"
         "\n",
         "index", JSFieldIndex(field), "oneofgroup",
         (field->containing_oneof() ? (", " + JSOneofArray(options, field))
-                                   : ""),
-        "returnvalue", JSReturnClause(field));
+                                   : ""));
 
     if (field->is_repeated()) {
       GenerateRepeatedMessageHelperMethods(options, printer, field);
@@ -2787,21 +2774,18 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
       GenerateBytesWrapper(options, printer, field, BYTES_U8);
     }
 
-    if (untyped) {
-      printer->Print(
-          "/**\n"
-          " * @param {*} value$returndoc$\n"
-          " */\n",
-          "returndoc", JSReturnDoc(options, field));
-    } else {
-      printer->Print(
-          "/** @param {$optionaltype$} value$returndoc$ */\n", "optionaltype",
-          JSFieldTypeAnnotation(options, field,
-                                /* is_setter_argument = */ true,
-                                /* force_present = */ false,
-                                /* singular_if_not_packed = */ false),
-          "returndoc", JSReturnDoc(options, field));
-    }
+    printer->Print(
+        "/**\n"
+        " * @param {$optionaltype$} value\n"
+        " * @return {!$class$} returns this\n"
+        " */\n",
+        "class", GetMessagePath(options, field->containing_type()),
+        "optionaltype",
+        untyped ? "*"
+                : JSFieldTypeAnnotation(options, field,
+                                        /* is_setter_argument = */ true,
+                                        /* force_present = */ false,
+                                        /* singular_if_not_packed = */ false));
 
     if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 &&
         !field->is_repeated() && !field->is_map() &&
@@ -2810,28 +2794,28 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
       // setProto3*Field function.
       printer->Print(
           "$class$.prototype.$settername$ = function(value) {\n"
-          "  jspb.Message.setProto3$typetag$Field(this, $index$, "
-          "value);$returnvalue$\n"
+          "  return jspb.Message.setProto3$typetag$Field(this, $index$, "
+          "value);"
+          "\n"
           "};\n"
           "\n"
           "\n",
           "class", GetMessagePath(options, field->containing_type()),
           "settername", "set" + JSGetterName(options, field), "typetag",
-          JSTypeTag(field), "index", JSFieldIndex(field), "returnvalue",
-          JSReturnClause(field));
+          JSTypeTag(field), "index", JSFieldIndex(field));
       printer->Annotate("settername", field);
     } else {
       // Otherwise, use the regular setField function.
       printer->Print(
           "$class$.prototype.$settername$ = function(value) {\n"
-          "  jspb.Message.set$oneoftag$Field(this, $index$",
+          "  return jspb.Message.set$oneoftag$Field(this, $index$",
           "class", GetMessagePath(options, field->containing_type()),
           "settername", "set" + JSGetterName(options, field), "oneoftag",
           (field->containing_oneof() ? "Oneof" : ""), "index",
           JSFieldIndex(field));
       printer->Annotate("settername", field);
       printer->Print(
-          "$oneofgroup$, $type$value$rptvalueinit$$typeclose$);$returnvalue$\n"
+          "$oneofgroup$, $type$value$rptvalueinit$$typeclose$);\n"
           "};\n"
           "\n"
           "\n",
@@ -2840,16 +2824,16 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
           "typeclose", untyped ? ")" : "", "oneofgroup",
           (field->containing_oneof() ? (", " + JSOneofArray(options, field))
                                      : ""),
-          "returnvalue", JSReturnClause(field), "rptvalueinit",
-          (field->is_repeated() ? " || []" : ""));
+          "rptvalueinit", (field->is_repeated() ? " || []" : ""));
     }
 
     if (untyped) {
       printer->Print(
           "/**\n"
-          " * Clears the value.$returndoc$\n"
+          " * Clears the value.\n"
+          " * @return {!$class$} returns this\n"
           " */\n",
-          "returndoc", JSReturnDoc(options, field));
+          "class", GetMessagePath(options, field->containing_type()));
     }
 
     if (field->is_repeated()) {
@@ -2863,19 +2847,18 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
     // clang-format off
     printer->Print(
         "/**\n"
-        " * Clears values from the map. The map will be non-null."
-        "$returndoc$\n"
+        " * Clears values from the map. The map will be non-null.\n"
+        " * @return {!$class$} returns this\n"
         " */\n"
         "$class$.prototype.$clearername$ = function() {\n"
-        "  this.$gettername$().clear();$returnvalue$\n"
+        "  this.$gettername$().clear();\n"
+        "  return this;"
         "};\n"
         "\n"
         "\n",
-        "returndoc", JSReturnDoc(options, field),
         "class", GetMessagePath(options, field->containing_type()),
         "clearername", "clear" + JSGetterName(options, field),
-        "gettername", "get" + JSGetterName(options, field),
-        "returnvalue", JSReturnClause(field));
+        "gettername", "get" + JSGetterName(options, field));
     // clang-format on
     printer->Annotate("clearername", field);
   } else if (field->is_repeated() ||
@@ -2885,22 +2868,21 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
     // clang-format off
     printer->Print(
         "/**\n"
-        " * $jsdoc$$returndoc$\n"
+        " * $jsdoc$\n"
+        " * @return {!$class$} returns this\n"
         " */\n"
         "$class$.prototype.$clearername$ = function() {\n"
-        "  this.$settername$($clearedvalue$);$returnvalue$\n"
+        "  return this.$settername$($clearedvalue$);\n"
         "};\n"
         "\n"
         "\n",
        "jsdoc", field->is_repeated()
            ? "Clears the list making it empty but non-null."
            : "Clears the message field making it undefined.",
-        "returndoc", JSReturnDoc(options, field),
         "class", GetMessagePath(options, field->containing_type()),
         "clearername", "clear" + JSGetterName(options, field),
         "settername", "set" + JSGetterName(options, field),
-        "clearedvalue", (field->is_repeated() ? "[]" : "undefined"),
-        "returnvalue", JSReturnClause(field));
+        "clearedvalue", (field->is_repeated() ? "[]" : "undefined"));
     // clang-format on
     printer->Annotate("clearername", field);
   } else if (HasFieldPresence(options, field)) {
@@ -2909,12 +2891,12 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
     // clang-format off
     printer->Print(
         "/**\n"
-        " * Clears the field making it undefined.$returndoc$\n"
+        " * Clears the field making it undefined.\n"
+        " * @return {!$class$} returns this\n"
         " */\n"
         "$class$.prototype.$clearername$ = function() {\n"
-        "  jspb.Message.set$maybeoneof$Field(this, "
-        "$index$$maybeoneofgroup$, ",
-        "returndoc", JSReturnDoc(options, field),
+        "  return jspb.Message.set$maybeoneof$Field(this, "
+            "$index$$maybeoneofgroup$, ",
         "class", GetMessagePath(options, field->containing_type()),
         "clearername", "clear" + JSGetterName(options, field),
         "maybeoneof", (field->containing_oneof() ? "Oneof" : ""),
@@ -2925,12 +2907,11 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
     // clang-format on
     printer->Annotate("clearername", field);
     printer->Print(
-        "$clearedvalue$);$returnvalue$\n"
+        "$clearedvalue$);\n"
         "};\n"
         "\n"
         "\n",
-        "clearedvalue", (field->is_repeated() ? "[]" : "undefined"),
-        "returnvalue", JSReturnClause(field));
+        "clearedvalue", (field->is_repeated() ? "[]" : "undefined"));
   }
 
   if (HasFieldPresence(options, field)) {
@@ -2957,10 +2938,12 @@ void Generator::GenerateRepeatedPrimitiveHelperMethods(
   printer->Print(
       "/**\n"
       " * @param {$optionaltype$} value\n"
-      " * @param {number=} opt_index$returndoc$\n"
+      " * @param {number=} opt_index\n"
+      " * @return {!$class$} returns this\n"
       " */\n"
       "$class$.prototype.$addername$ = function(value, opt_index) {\n"
-      "  jspb.Message.addToRepeatedField(this, $index$",
+      "  return jspb.Message.addToRepeatedField(this, "
+      "$index$",
       "class", GetMessagePath(options, field->containing_type()), "addername",
       "add" + JSGetterName(options, field, BYTES_DEFAULT,
                            /* drop_list = */ true),
@@ -2972,20 +2955,18 @@ void Generator::GenerateRepeatedPrimitiveHelperMethods(
                                 /* singular_if_not_packed = */ false,
                                 BYTES_DEFAULT,
                                 /* force_singular = */ true),
-      "index", JSFieldIndex(field),
-      "returndoc", JSReturnDoc(options, field));
+      "index", JSFieldIndex(field));
   printer->Annotate("addername", field);
   printer->Print(
       "$oneofgroup$, $type$value$rptvalueinit$$typeclose$, "
-      "opt_index);$returnvalue$\n"
+      "opt_index);\n"
       "};\n"
       "\n"
       "\n",
       "type", untyped ? "/** @type{string|number|boolean|!Uint8Array} */(" : "",
       "typeclose", untyped ? ")" : "", "oneofgroup",
       (field->containing_oneof() ? (", " + JSOneofArray(options, field)) : ""),
-      "rptvalueinit", "",
-      "returnvalue", JSReturnClause(field));
+      "rptvalueinit", "");
   // clang-format on
 }
 
@@ -3374,12 +3355,21 @@ void Generator::GenerateEnum(const GeneratorOptions& options,
       enumdesc->name());
   printer->Annotate("name", enumdesc);
 
+  std::set<string> used_name;
+  std::vector<int> valid_index;
   for (int i = 0; i < enumdesc->value_count(); i++) {
+    if (enumdesc->options().allow_alias() &&
+        !used_name.insert(ToEnumCase(enumdesc->value(i)->name())).second) {
+      continue;
+    }
+    valid_index.push_back(i);
+  }
+  for (auto i : valid_index) {
     const EnumValueDescriptor* value = enumdesc->value(i);
     printer->Print("  $name$: $value$$comma$\n", "name",
                    ToEnumCase(value->name()), "value",
                    StrCat(value->number()), "comma",
-                   (i == enumdesc->value_count() - 1) ? "" : ",");
+                   (i == valid_index.back()) ? "" : ",");
     printer->Annotate("name", value);
   }
 

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

@@ -39,7 +39,6 @@
 #include <google/protobuf/stubs/strutil.h>
 
 
-
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/testing/file.h>

+ 2 - 2
src/google/protobuf/compiler/objectivec/objectivec_helpers.cc

@@ -48,7 +48,7 @@
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 #include <google/protobuf/io/io_win32.h>
-#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/strutil.h>
 
 // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
@@ -931,7 +931,7 @@ string BuildCommentsString(const SourceLocation& location,
                                ? location.trailing_comments
                                : location.leading_comments;
   std::vector<string> lines;
-  SplitStringAllowEmpty(comments, "\n", &lines);
+  lines = Split(comments, "\n", false);
   while (!lines.empty() && lines.back().empty()) {
     lines.pop_back();
   }

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

@@ -38,7 +38,6 @@
 #include <limits>
 #include <unordered_map>
 
-
 #include <google/protobuf/stubs/hash.h>
 
 #include <google/protobuf/stubs/casts.h>

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

@@ -48,7 +48,6 @@
 #include <google/protobuf/text_format.h>
 #include <google/protobuf/wire_format.h>
 #include <google/protobuf/stubs/substitute.h>
-
 #include <google/protobuf/stubs/map_util.h>
 
 #include <google/protobuf/testing/googletest.h>

+ 1 - 1
src/google/protobuf/compiler/php/php_generator.cc

@@ -1463,7 +1463,7 @@ static void GenerateDocCommentBodyForLocation(
     // HTML-escape them so that they don't accidentally close the doc comment.
     comments = EscapePhpdoc(comments);
 
-    std::vector<string> lines = Split(comments, "\n");
+    std::vector<string> lines = Split(comments, "\n", true);
     while (!lines.empty() && lines.back().empty()) {
       lines.pop_back();
     }

+ 1 - 1
src/google/protobuf/compiler/plugin.cc

@@ -45,9 +45,9 @@
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/compiler/plugin.pb.h>
 #include <google/protobuf/compiler/code_generator.h>
-#include <google/protobuf/io/io_win32.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 #include <google/protobuf/descriptor.h>
+#include <google/protobuf/io/io_win32.h>
 
 
 namespace google {

+ 73 - 81
src/google/protobuf/compiler/plugin.pb.cc

@@ -49,7 +49,7 @@ static void InitDefaultsscc_info_CodeGeneratorRequest_google_2fprotobuf_2fcompil
 }
 
 PROTOC_EXPORT ::PROTOBUF_NAMESPACE_ID::internal::SCCInfo<2> scc_info_CodeGeneratorRequest_google_2fprotobuf_2fcompiler_2fplugin_2eproto =
-    {{ATOMIC_VAR_INIT(::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase::kUninitialized), 2, InitDefaultsscc_info_CodeGeneratorRequest_google_2fprotobuf_2fcompiler_2fplugin_2eproto}, {
+    {{ATOMIC_VAR_INIT(::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase::kUninitialized), 2, 0, InitDefaultsscc_info_CodeGeneratorRequest_google_2fprotobuf_2fcompiler_2fplugin_2eproto}, {
       &scc_info_FileDescriptorProto_google_2fprotobuf_2fdescriptor_2eproto.base,
       &scc_info_Version_google_2fprotobuf_2fcompiler_2fplugin_2eproto.base,}};
 
@@ -65,7 +65,7 @@ static void InitDefaultsscc_info_CodeGeneratorResponse_google_2fprotobuf_2fcompi
 }
 
 PROTOC_EXPORT ::PROTOBUF_NAMESPACE_ID::internal::SCCInfo<1> scc_info_CodeGeneratorResponse_google_2fprotobuf_2fcompiler_2fplugin_2eproto =
-    {{ATOMIC_VAR_INIT(::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase::kUninitialized), 1, InitDefaultsscc_info_CodeGeneratorResponse_google_2fprotobuf_2fcompiler_2fplugin_2eproto}, {
+    {{ATOMIC_VAR_INIT(::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase::kUninitialized), 1, 0, InitDefaultsscc_info_CodeGeneratorResponse_google_2fprotobuf_2fcompiler_2fplugin_2eproto}, {
       &scc_info_CodeGeneratorResponse_File_google_2fprotobuf_2fcompiler_2fplugin_2eproto.base,}};
 
 static void InitDefaultsscc_info_CodeGeneratorResponse_File_google_2fprotobuf_2fcompiler_2fplugin_2eproto() {
@@ -80,7 +80,7 @@ static void InitDefaultsscc_info_CodeGeneratorResponse_File_google_2fprotobuf_2f
 }
 
 PROTOC_EXPORT ::PROTOBUF_NAMESPACE_ID::internal::SCCInfo<0> scc_info_CodeGeneratorResponse_File_google_2fprotobuf_2fcompiler_2fplugin_2eproto =
-    {{ATOMIC_VAR_INIT(::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase::kUninitialized), 0, InitDefaultsscc_info_CodeGeneratorResponse_File_google_2fprotobuf_2fcompiler_2fplugin_2eproto}, {}};
+    {{ATOMIC_VAR_INIT(::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase::kUninitialized), 0, 0, InitDefaultsscc_info_CodeGeneratorResponse_File_google_2fprotobuf_2fcompiler_2fplugin_2eproto}, {}};
 
 static void InitDefaultsscc_info_Version_google_2fprotobuf_2fcompiler_2fplugin_2eproto() {
   GOOGLE_PROTOBUF_VERIFY_VERSION;
@@ -94,7 +94,7 @@ static void InitDefaultsscc_info_Version_google_2fprotobuf_2fcompiler_2fplugin_2
 }
 
 PROTOC_EXPORT ::PROTOBUF_NAMESPACE_ID::internal::SCCInfo<0> scc_info_Version_google_2fprotobuf_2fcompiler_2fplugin_2eproto =
-    {{ATOMIC_VAR_INIT(::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase::kUninitialized), 0, InitDefaultsscc_info_Version_google_2fprotobuf_2fcompiler_2fplugin_2eproto}, {}};
+    {{ATOMIC_VAR_INIT(::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase::kUninitialized), 0, 0, InitDefaultsscc_info_Version_google_2fprotobuf_2fcompiler_2fplugin_2eproto}, {}};
 
 static ::PROTOBUF_NAMESPACE_ID::Metadata file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[4];
 static constexpr ::PROTOBUF_NAMESPACE_ID::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto = nullptr;
@@ -235,7 +235,7 @@ Version::Version(const Version& from)
       _has_bits_(from._has_bits_) {
   _internal_metadata_.MergeFrom(from._internal_metadata_);
   suffix_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
-  if (from.has_suffix()) {
+  if (from._internal_has_suffix()) {
     suffix_.AssignWithDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from.suffix_);
   }
   ::memcpy(&major_, &from.major_,
@@ -325,7 +325,7 @@ const char* Version::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::in
       // optional string suffix = 4;
       case 4:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 34)) {
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8Verify(mutable_suffix(), ptr, ctx, "google.protobuf.compiler.Version.suffix");
+          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8Verify(_internal_mutable_suffix(), ptr, ctx, "google.protobuf.compiler.Version.suffix");
           CHK_(ptr);
         } else goto handle_unusual;
         continue;
@@ -403,9 +403,9 @@ bool Version::MergePartialFromCodedStream(
       case 4: {
         if (static_cast< ::PROTOBUF_NAMESPACE_ID::uint8>(tag) == (34 & 0xFF)) {
           DO_(::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::ReadString(
-                input, this->mutable_suffix()));
+                input, this->_internal_mutable_suffix()));
           ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-            this->suffix().data(), static_cast<int>(this->suffix().length()),
+            this->_internal_suffix().data(), static_cast<int>(this->_internal_suffix().length()),
             ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::PARSE,
             "google.protobuf.compiler.Version.suffix");
         } else {
@@ -463,11 +463,11 @@ failure:
   // optional string suffix = 4;
   if (cached_has_bits & 0x00000001u) {
     ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->suffix().data(), static_cast<int>(this->suffix().length()),
+      this->_internal_suffix().data(), static_cast<int>(this->_internal_suffix().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.compiler.Version.suffix");
     target = stream->WriteStringMaybeAliased(
-        4, this->suffix(), target);
+        4, this->_internal_suffix(), target);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
@@ -492,7 +492,7 @@ size_t Version::ByteSizeLong() const {
     if (cached_has_bits & 0x00000001u) {
       total_size += 1 +
         ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
-          this->suffix());
+          this->_internal_suffix());
     }
 
     // optional int32 major = 1;
@@ -639,7 +639,7 @@ CodeGeneratorRequest::CodeGeneratorRequest(const CodeGeneratorRequest& from)
       proto_file_(from.proto_file_) {
   _internal_metadata_.MergeFrom(from._internal_metadata_);
   parameter_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
-  if (from.has_parameter()) {
+  if (from._internal_has_parameter()) {
     parameter_.AssignWithDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from.parameter_);
   }
   if (from.has_compiler_version()) {
@@ -712,16 +712,16 @@ const char* CodeGeneratorRequest::_InternalParse(const char* ptr, ::PROTOBUF_NAM
           ptr -= 1;
           do {
             ptr += 1;
-            ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8Verify(add_file_to_generate(), ptr, ctx, "google.protobuf.compiler.CodeGeneratorRequest.file_to_generate");
+            ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8Verify(_internal_add_file_to_generate(), ptr, ctx, "google.protobuf.compiler.CodeGeneratorRequest.file_to_generate");
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
-          } while (::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad<::PROTOBUF_NAMESPACE_ID::uint8>(ptr) == 10);
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<10>(ptr));
         } else goto handle_unusual;
         continue;
       // optional string parameter = 2;
       case 2:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 18)) {
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8Verify(mutable_parameter(), ptr, ctx, "google.protobuf.compiler.CodeGeneratorRequest.parameter");
+          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8Verify(_internal_mutable_parameter(), ptr, ctx, "google.protobuf.compiler.CodeGeneratorRequest.parameter");
           CHK_(ptr);
         } else goto handle_unusual;
         continue;
@@ -741,7 +741,7 @@ const char* CodeGeneratorRequest::_InternalParse(const char* ptr, ::PROTOBUF_NAM
             ptr = ctx->ParseMessage(add_proto_file(), ptr);
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
-          } while (::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad<::PROTOBUF_NAMESPACE_ID::uint8>(ptr) == 122);
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<122>(ptr));
         } else goto handle_unusual;
         continue;
       default: {
@@ -779,10 +779,10 @@ bool CodeGeneratorRequest::MergePartialFromCodedStream(
       case 1: {
         if (static_cast< ::PROTOBUF_NAMESPACE_ID::uint8>(tag) == (10 & 0xFF)) {
           DO_(::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::ReadString(
-                input, this->add_file_to_generate()));
+                input, this->_internal_add_file_to_generate()));
           ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-            this->file_to_generate(this->file_to_generate_size() - 1).data(),
-            static_cast<int>(this->file_to_generate(this->file_to_generate_size() - 1).length()),
+            file_to_generate_.Get(file_to_generate_.size() - 1).data(),
+            static_cast<int>(file_to_generate_.Get(file_to_generate_.size() - 1).length()),
             ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::PARSE,
             "google.protobuf.compiler.CodeGeneratorRequest.file_to_generate");
         } else {
@@ -795,9 +795,9 @@ bool CodeGeneratorRequest::MergePartialFromCodedStream(
       case 2: {
         if (static_cast< ::PROTOBUF_NAMESPACE_ID::uint8>(tag) == (18 & 0xFF)) {
           DO_(::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::ReadString(
-                input, this->mutable_parameter()));
+                input, this->_internal_mutable_parameter()));
           ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-            this->parameter().data(), static_cast<int>(this->parameter().length()),
+            this->_internal_parameter().data(), static_cast<int>(this->_internal_parameter().length()),
             ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::PARSE,
             "google.protobuf.compiler.CodeGeneratorRequest.parameter");
         } else {
@@ -856,8 +856,8 @@ failure:
   (void) cached_has_bits;
 
   // repeated string file_to_generate = 1;
-  for (auto it = this->file_to_generate().pointer_begin(),
-            end = this->file_to_generate().pointer_end(); it < end; ++it) {
+  for (auto it = file_to_generate_.pointer_begin(),
+            end = file_to_generate_.pointer_end(); it < end; ++it) {
     const auto& s = **it;
     ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
       s.data(), static_cast<int>(s.length()),
@@ -870,11 +870,11 @@ failure:
   // optional string parameter = 2;
   if (cached_has_bits & 0x00000001u) {
     ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->parameter().data(), static_cast<int>(this->parameter().length()),
+      this->_internal_parameter().data(), static_cast<int>(this->_internal_parameter().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.compiler.CodeGeneratorRequest.parameter");
     target = stream->WriteStringMaybeAliased(
-        2, this->parameter(), target);
+        2, this->_internal_parameter(), target);
   }
 
   // optional .google.protobuf.compiler.Version compiler_version = 3;
@@ -886,8 +886,8 @@ failure:
   }
 
   // repeated .google.protobuf.FileDescriptorProto proto_file = 15;
-  for (auto it = this->proto_file().pointer_begin(),
-            end = this->proto_file().pointer_end(); it < end; ++it) {
+  for (auto it = this->proto_file_.pointer_begin(),
+            end = this->proto_file_.pointer_end(); it < end; ++it) {
     stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
       InternalWriteMessageToArray(15, **it, target, stream);
@@ -911,21 +911,17 @@ size_t CodeGeneratorRequest::ByteSizeLong() const {
 
   // repeated string file_to_generate = 1;
   total_size += 1 *
-      ::PROTOBUF_NAMESPACE_ID::internal::FromIntSize(this->file_to_generate_size());
-  for (int i = 0, n = this->file_to_generate_size(); i < n; i++) {
+      ::PROTOBUF_NAMESPACE_ID::internal::FromIntSize(file_to_generate_.size());
+  for (int i = 0, n = file_to_generate_.size(); i < n; i++) {
     total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
-      this->file_to_generate(i));
+      file_to_generate_.Get(i));
   }
 
   // repeated .google.protobuf.FileDescriptorProto proto_file = 15;
-  {
-    unsigned int count = static_cast<unsigned int>(this->proto_file_size());
-    total_size += 1UL * count;
-    for (unsigned int i = 0; i < count; i++) {
-      total_size +=
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
-          this->proto_file(static_cast<int>(i)));
-    }
+  total_size += 1UL * this->proto_file_size();
+  for (const auto& msg : this->proto_file_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
   }
 
   cached_has_bits = _has_bits_[0];
@@ -934,7 +930,7 @@ size_t CodeGeneratorRequest::ByteSizeLong() const {
     if (cached_has_bits & 0x00000001u) {
       total_size += 1 +
         ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
-          this->parameter());
+          this->_internal_parameter());
     }
 
     // optional .google.protobuf.compiler.Version compiler_version = 3;
@@ -1013,8 +1009,8 @@ void CodeGeneratorRequest::InternalSwap(CodeGeneratorRequest* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);
   swap(_has_bits_[0], other->_has_bits_[0]);
-  file_to_generate_.InternalSwap(CastToBase(&other->file_to_generate_));
-  CastToBase(&proto_file_)->InternalSwap(CastToBase(&other->proto_file_));
+  file_to_generate_.InternalSwap(&other->file_to_generate_);
+  proto_file_.InternalSwap(&other->proto_file_);
   parameter_.Swap(&other->parameter_, &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
     GetArenaNoVirtual());
   swap(compiler_version_, other->compiler_version_);
@@ -1054,15 +1050,15 @@ CodeGeneratorResponse_File::CodeGeneratorResponse_File(const CodeGeneratorRespon
       _has_bits_(from._has_bits_) {
   _internal_metadata_.MergeFrom(from._internal_metadata_);
   name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
-  if (from.has_name()) {
+  if (from._internal_has_name()) {
     name_.AssignWithDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from.name_);
   }
   insertion_point_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
-  if (from.has_insertion_point()) {
+  if (from._internal_has_insertion_point()) {
     insertion_point_.AssignWithDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from.insertion_point_);
   }
   content_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
-  if (from.has_content()) {
+  if (from._internal_has_content()) {
     content_.AssignWithDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from.content_);
   }
   // @@protoc_insertion_point(copy_constructor:google.protobuf.compiler.CodeGeneratorResponse.File)
@@ -1129,21 +1125,21 @@ const char* CodeGeneratorResponse_File::_InternalParse(const char* ptr, ::PROTOB
       // optional string name = 1;
       case 1:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 10)) {
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8Verify(mutable_name(), ptr, ctx, "google.protobuf.compiler.CodeGeneratorResponse.File.name");
+          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8Verify(_internal_mutable_name(), ptr, ctx, "google.protobuf.compiler.CodeGeneratorResponse.File.name");
           CHK_(ptr);
         } else goto handle_unusual;
         continue;
       // optional string insertion_point = 2;
       case 2:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 18)) {
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8Verify(mutable_insertion_point(), ptr, ctx, "google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point");
+          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8Verify(_internal_mutable_insertion_point(), ptr, ctx, "google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point");
           CHK_(ptr);
         } else goto handle_unusual;
         continue;
       // optional string content = 15;
       case 15:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 122)) {
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8Verify(mutable_content(), ptr, ctx, "google.protobuf.compiler.CodeGeneratorResponse.File.content");
+          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8Verify(_internal_mutable_content(), ptr, ctx, "google.protobuf.compiler.CodeGeneratorResponse.File.content");
           CHK_(ptr);
         } else goto handle_unusual;
         continue;
@@ -1182,9 +1178,9 @@ bool CodeGeneratorResponse_File::MergePartialFromCodedStream(
       case 1: {
         if (static_cast< ::PROTOBUF_NAMESPACE_ID::uint8>(tag) == (10 & 0xFF)) {
           DO_(::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::ReadString(
-                input, this->mutable_name()));
+                input, this->_internal_mutable_name()));
           ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-            this->name().data(), static_cast<int>(this->name().length()),
+            this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
             ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::PARSE,
             "google.protobuf.compiler.CodeGeneratorResponse.File.name");
         } else {
@@ -1197,9 +1193,9 @@ bool CodeGeneratorResponse_File::MergePartialFromCodedStream(
       case 2: {
         if (static_cast< ::PROTOBUF_NAMESPACE_ID::uint8>(tag) == (18 & 0xFF)) {
           DO_(::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::ReadString(
-                input, this->mutable_insertion_point()));
+                input, this->_internal_mutable_insertion_point()));
           ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-            this->insertion_point().data(), static_cast<int>(this->insertion_point().length()),
+            this->_internal_insertion_point().data(), static_cast<int>(this->_internal_insertion_point().length()),
             ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::PARSE,
             "google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point");
         } else {
@@ -1212,9 +1208,9 @@ bool CodeGeneratorResponse_File::MergePartialFromCodedStream(
       case 15: {
         if (static_cast< ::PROTOBUF_NAMESPACE_ID::uint8>(tag) == (122 & 0xFF)) {
           DO_(::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::ReadString(
-                input, this->mutable_content()));
+                input, this->_internal_mutable_content()));
           ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-            this->content().data(), static_cast<int>(this->content().length()),
+            this->_internal_content().data(), static_cast<int>(this->_internal_content().length()),
             ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::PARSE,
             "google.protobuf.compiler.CodeGeneratorResponse.File.content");
         } else {
@@ -1254,31 +1250,31 @@ failure:
   // optional string name = 1;
   if (cached_has_bits & 0x00000001u) {
     ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->name().data(), static_cast<int>(this->name().length()),
+      this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.compiler.CodeGeneratorResponse.File.name");
     target = stream->WriteStringMaybeAliased(
-        1, this->name(), target);
+        1, this->_internal_name(), target);
   }
 
   // optional string insertion_point = 2;
   if (cached_has_bits & 0x00000002u) {
     ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->insertion_point().data(), static_cast<int>(this->insertion_point().length()),
+      this->_internal_insertion_point().data(), static_cast<int>(this->_internal_insertion_point().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point");
     target = stream->WriteStringMaybeAliased(
-        2, this->insertion_point(), target);
+        2, this->_internal_insertion_point(), target);
   }
 
   // optional string content = 15;
   if (cached_has_bits & 0x00000004u) {
     ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->content().data(), static_cast<int>(this->content().length()),
+      this->_internal_content().data(), static_cast<int>(this->_internal_content().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.compiler.CodeGeneratorResponse.File.content");
     target = stream->WriteStringMaybeAliased(
-        15, this->content(), target);
+        15, this->_internal_content(), target);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
@@ -1303,21 +1299,21 @@ size_t CodeGeneratorResponse_File::ByteSizeLong() const {
     if (cached_has_bits & 0x00000001u) {
       total_size += 1 +
         ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
-          this->name());
+          this->_internal_name());
     }
 
     // optional string insertion_point = 2;
     if (cached_has_bits & 0x00000002u) {
       total_size += 1 +
         ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
-          this->insertion_point());
+          this->_internal_insertion_point());
     }
 
     // optional string content = 15;
     if (cached_has_bits & 0x00000004u) {
       total_size += 1 +
         ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
-          this->content());
+          this->_internal_content());
     }
 
   }
@@ -1428,7 +1424,7 @@ CodeGeneratorResponse::CodeGeneratorResponse(const CodeGeneratorResponse& from)
       file_(from.file_) {
   _internal_metadata_.MergeFrom(from._internal_metadata_);
   error_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
-  if (from.has_error()) {
+  if (from._internal_has_error()) {
     error_.AssignWithDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from.error_);
   }
   // @@protoc_insertion_point(copy_constructor:google.protobuf.compiler.CodeGeneratorResponse)
@@ -1484,7 +1480,7 @@ const char* CodeGeneratorResponse::_InternalParse(const char* ptr, ::PROTOBUF_NA
       // optional string error = 1;
       case 1:
         if (PROTOBUF_PREDICT_TRUE(static_cast<::PROTOBUF_NAMESPACE_ID::uint8>(tag) == 10)) {
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8Verify(mutable_error(), ptr, ctx, "google.protobuf.compiler.CodeGeneratorResponse.error");
+          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParserUTF8Verify(_internal_mutable_error(), ptr, ctx, "google.protobuf.compiler.CodeGeneratorResponse.error");
           CHK_(ptr);
         } else goto handle_unusual;
         continue;
@@ -1497,7 +1493,7 @@ const char* CodeGeneratorResponse::_InternalParse(const char* ptr, ::PROTOBUF_NA
             ptr = ctx->ParseMessage(add_file(), ptr);
             CHK_(ptr);
             if (!ctx->DataAvailable(ptr)) break;
-          } while (::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad<::PROTOBUF_NAMESPACE_ID::uint8>(ptr) == 122);
+          } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<122>(ptr));
         } else goto handle_unusual;
         continue;
       default: {
@@ -1535,9 +1531,9 @@ bool CodeGeneratorResponse::MergePartialFromCodedStream(
       case 1: {
         if (static_cast< ::PROTOBUF_NAMESPACE_ID::uint8>(tag) == (10 & 0xFF)) {
           DO_(::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::ReadString(
-                input, this->mutable_error()));
+                input, this->_internal_mutable_error()));
           ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-            this->error().data(), static_cast<int>(this->error().length()),
+            this->_internal_error().data(), static_cast<int>(this->_internal_error().length()),
             ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::PARSE,
             "google.protobuf.compiler.CodeGeneratorResponse.error");
         } else {
@@ -1588,16 +1584,16 @@ failure:
   // optional string error = 1;
   if (cached_has_bits & 0x00000001u) {
     ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->error().data(), static_cast<int>(this->error().length()),
+      this->_internal_error().data(), static_cast<int>(this->_internal_error().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.compiler.CodeGeneratorResponse.error");
     target = stream->WriteStringMaybeAliased(
-        1, this->error(), target);
+        1, this->_internal_error(), target);
   }
 
   // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
-  for (auto it = this->file().pointer_begin(),
-            end = this->file().pointer_end(); it < end; ++it) {
+  for (auto it = this->file_.pointer_begin(),
+            end = this->file_.pointer_end(); it < end; ++it) {
     stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
       InternalWriteMessageToArray(15, **it, target, stream);
@@ -1620,14 +1616,10 @@ size_t CodeGeneratorResponse::ByteSizeLong() const {
   (void) cached_has_bits;
 
   // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
-  {
-    unsigned int count = static_cast<unsigned int>(this->file_size());
-    total_size += 1UL * count;
-    for (unsigned int i = 0; i < count; i++) {
-      total_size +=
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
-          this->file(static_cast<int>(i)));
-    }
+  total_size += 1UL * this->file_size();
+  for (const auto& msg : this->file_) {
+    total_size +=
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
   }
 
   // optional string error = 1;
@@ -1635,7 +1627,7 @@ size_t CodeGeneratorResponse::ByteSizeLong() const {
   if (cached_has_bits & 0x00000001u) {
     total_size += 1 +
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
-        this->error());
+        this->_internal_error());
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
@@ -1698,7 +1690,7 @@ void CodeGeneratorResponse::InternalSwap(CodeGeneratorResponse* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);
   swap(_has_bits_[0], other->_has_bits_[0]);
-  CastToBase(&file_)->InternalSwap(CastToBase(&other->file_));
+  file_.InternalSwap(&other->file_);
   error_.Swap(&other->error_, &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
     GetArenaNoVirtual());
 }

+ 186 - 36
src/google/protobuf/compiler/plugin.pb.h

@@ -213,6 +213,9 @@ class PROTOC_EXPORT Version :
   };
   // optional string suffix = 4;
   bool has_suffix() const;
+  private:
+  bool _internal_has_suffix() const;
+  public:
   void clear_suffix();
   const std::string& suffix() const;
   void set_suffix(const std::string& value);
@@ -222,21 +225,35 @@ class PROTOC_EXPORT Version :
   std::string* mutable_suffix();
   std::string* release_suffix();
   void set_allocated_suffix(std::string* suffix);
+  private:
+  const std::string& _internal_suffix() const;
+  void _internal_set_suffix(const std::string& value);
+  std::string* _internal_mutable_suffix();
+  public:
 
   // optional int32 major = 1;
   bool has_major() const;
+  private:
+  bool _internal_has_major() const;
+  public:
   void clear_major();
   ::PROTOBUF_NAMESPACE_ID::int32 major() const;
   void set_major(::PROTOBUF_NAMESPACE_ID::int32 value);
 
   // optional int32 minor = 2;
   bool has_minor() const;
+  private:
+  bool _internal_has_minor() const;
+  public:
   void clear_minor();
   ::PROTOBUF_NAMESPACE_ID::int32 minor() const;
   void set_minor(::PROTOBUF_NAMESPACE_ID::int32 value);
 
   // optional int32 patch = 3;
   bool has_patch() const;
+  private:
+  bool _internal_has_patch() const;
+  public:
   void clear_patch();
   ::PROTOBUF_NAMESPACE_ID::int32 patch() const;
   void set_patch(::PROTOBUF_NAMESPACE_ID::int32 value);
@@ -395,6 +412,9 @@ class PROTOC_EXPORT CodeGeneratorRequest :
   void add_file_to_generate(const char* value, size_t size);
   const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>& file_to_generate() const;
   ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>* mutable_file_to_generate();
+  private:
+  std::string* _internal_add_file_to_generate();
+  public:
 
   // repeated .google.protobuf.FileDescriptorProto proto_file = 15;
   int proto_file_size() const;
@@ -409,6 +429,9 @@ class PROTOC_EXPORT CodeGeneratorRequest :
 
   // optional string parameter = 2;
   bool has_parameter() const;
+  private:
+  bool _internal_has_parameter() const;
+  public:
   void clear_parameter();
   const std::string& parameter() const;
   void set_parameter(const std::string& value);
@@ -418,9 +441,17 @@ class PROTOC_EXPORT CodeGeneratorRequest :
   std::string* mutable_parameter();
   std::string* release_parameter();
   void set_allocated_parameter(std::string* parameter);
+  private:
+  const std::string& _internal_parameter() const;
+  void _internal_set_parameter(const std::string& value);
+  std::string* _internal_mutable_parameter();
+  public:
 
   // optional .google.protobuf.compiler.Version compiler_version = 3;
   bool has_compiler_version() const;
+  private:
+  bool _internal_has_compiler_version() const;
+  public:
   void clear_compiler_version();
   const PROTOBUF_NAMESPACE_ID::compiler::Version& compiler_version() const;
   PROTOBUF_NAMESPACE_ID::compiler::Version* release_compiler_version();
@@ -566,6 +597,9 @@ class PROTOC_EXPORT CodeGeneratorResponse_File :
   };
   // optional string name = 1;
   bool has_name() const;
+  private:
+  bool _internal_has_name() const;
+  public:
   void clear_name();
   const std::string& name() const;
   void set_name(const std::string& value);
@@ -575,9 +609,17 @@ class PROTOC_EXPORT CodeGeneratorResponse_File :
   std::string* mutable_name();
   std::string* release_name();
   void set_allocated_name(std::string* name);
+  private:
+  const std::string& _internal_name() const;
+  void _internal_set_name(const std::string& value);
+  std::string* _internal_mutable_name();
+  public:
 
   // optional string insertion_point = 2;
   bool has_insertion_point() const;
+  private:
+  bool _internal_has_insertion_point() const;
+  public:
   void clear_insertion_point();
   const std::string& insertion_point() const;
   void set_insertion_point(const std::string& value);
@@ -587,9 +629,17 @@ class PROTOC_EXPORT CodeGeneratorResponse_File :
   std::string* mutable_insertion_point();
   std::string* release_insertion_point();
   void set_allocated_insertion_point(std::string* insertion_point);
+  private:
+  const std::string& _internal_insertion_point() const;
+  void _internal_set_insertion_point(const std::string& value);
+  std::string* _internal_mutable_insertion_point();
+  public:
 
   // optional string content = 15;
   bool has_content() const;
+  private:
+  bool _internal_has_content() const;
+  public:
   void clear_content();
   const std::string& content() const;
   void set_content(const std::string& value);
@@ -599,6 +649,11 @@ class PROTOC_EXPORT CodeGeneratorResponse_File :
   std::string* mutable_content();
   std::string* release_content();
   void set_allocated_content(std::string* content);
+  private:
+  const std::string& _internal_content() const;
+  void _internal_set_content(const std::string& value);
+  std::string* _internal_mutable_content();
+  public:
 
   // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse.File)
  private:
@@ -750,6 +805,9 @@ class PROTOC_EXPORT CodeGeneratorResponse :
 
   // optional string error = 1;
   bool has_error() const;
+  private:
+  bool _internal_has_error() const;
+  public:
   void clear_error();
   const std::string& error() const;
   void set_error(const std::string& value);
@@ -759,6 +817,11 @@ class PROTOC_EXPORT CodeGeneratorResponse :
   std::string* mutable_error();
   std::string* release_error();
   void set_allocated_error(std::string* error);
+  private:
+  const std::string& _internal_error() const;
+  void _internal_set_error(const std::string& value);
+  std::string* _internal_mutable_error();
+  public:
 
   // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse)
  private:
@@ -783,9 +846,12 @@ class PROTOC_EXPORT CodeGeneratorResponse :
 // Version
 
 // optional int32 major = 1;
-inline bool Version::has_major() const {
+inline bool Version::_internal_has_major() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
 }
+inline bool Version::has_major() const {
+  return _internal_has_major();
+}
 inline void Version::clear_major() {
   major_ = 0;
   _has_bits_[0] &= ~0x00000002u;
@@ -801,9 +867,12 @@ inline void Version::set_major(::PROTOBUF_NAMESPACE_ID::int32 value) {
 }
 
 // optional int32 minor = 2;
-inline bool Version::has_minor() const {
+inline bool Version::_internal_has_minor() const {
   return (_has_bits_[0] & 0x00000004u) != 0;
 }
+inline bool Version::has_minor() const {
+  return _internal_has_minor();
+}
 inline void Version::clear_minor() {
   minor_ = 0;
   _has_bits_[0] &= ~0x00000004u;
@@ -819,9 +888,12 @@ inline void Version::set_minor(::PROTOBUF_NAMESPACE_ID::int32 value) {
 }
 
 // optional int32 patch = 3;
-inline bool Version::has_patch() const {
+inline bool Version::_internal_has_patch() const {
   return (_has_bits_[0] & 0x00000008u) != 0;
 }
+inline bool Version::has_patch() const {
+  return _internal_has_patch();
+}
 inline void Version::clear_patch() {
   patch_ = 0;
   _has_bits_[0] &= ~0x00000008u;
@@ -837,21 +909,34 @@ inline void Version::set_patch(::PROTOBUF_NAMESPACE_ID::int32 value) {
 }
 
 // optional string suffix = 4;
-inline bool Version::has_suffix() const {
+inline bool Version::_internal_has_suffix() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
+inline bool Version::has_suffix() const {
+  return _internal_has_suffix();
+}
 inline void Version::clear_suffix() {
   suffix_.ClearToEmptyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
   _has_bits_[0] &= ~0x00000001u;
 }
 inline const std::string& Version::suffix() const {
   // @@protoc_insertion_point(field_get:google.protobuf.compiler.Version.suffix)
-  return suffix_.GetNoArena();
+  return _internal_suffix();
 }
 inline void Version::set_suffix(const std::string& value) {
+  _internal_set_suffix(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.Version.suffix)
+}
+inline std::string* Version::mutable_suffix() {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.Version.suffix)
+  return _internal_mutable_suffix();
+}
+inline const std::string& Version::_internal_suffix() const {
+  return suffix_.GetNoArena();
+}
+inline void Version::_internal_set_suffix(const std::string& value) {
   _has_bits_[0] |= 0x00000001u;
   suffix_.SetNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value);
-  // @@protoc_insertion_point(field_set:google.protobuf.compiler.Version.suffix)
 }
 inline void Version::set_suffix(std::string&& value) {
   _has_bits_[0] |= 0x00000001u;
@@ -871,9 +956,8 @@ inline void Version::set_suffix(const char* value, size_t size) {
       ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.Version.suffix)
 }
-inline std::string* Version::mutable_suffix() {
+inline std::string* Version::_internal_mutable_suffix() {
   _has_bits_[0] |= 0x00000001u;
-  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.Version.suffix)
   return suffix_.MutableNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 inline std::string* Version::release_suffix() {
@@ -905,6 +989,10 @@ inline int CodeGeneratorRequest::file_to_generate_size() const {
 inline void CodeGeneratorRequest::clear_file_to_generate() {
   file_to_generate_.Clear();
 }
+inline std::string* CodeGeneratorRequest::add_file_to_generate() {
+  // @@protoc_insertion_point(field_add_mutable:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+  return _internal_add_file_to_generate();
+}
 inline const std::string& CodeGeneratorRequest::file_to_generate(int index) const {
   // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
   return file_to_generate_.Get(index);
@@ -931,8 +1019,7 @@ inline void CodeGeneratorRequest::set_file_to_generate(int index, const char* va
     reinterpret_cast<const char*>(value), size);
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
 }
-inline std::string* CodeGeneratorRequest::add_file_to_generate() {
-  // @@protoc_insertion_point(field_add_mutable:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+inline std::string* CodeGeneratorRequest::_internal_add_file_to_generate() {
   return file_to_generate_.Add();
 }
 inline void CodeGeneratorRequest::add_file_to_generate(const std::string& value) {
@@ -964,21 +1051,34 @@ CodeGeneratorRequest::mutable_file_to_generate() {
 }
 
 // optional string parameter = 2;
-inline bool CodeGeneratorRequest::has_parameter() const {
+inline bool CodeGeneratorRequest::_internal_has_parameter() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
+inline bool CodeGeneratorRequest::has_parameter() const {
+  return _internal_has_parameter();
+}
 inline void CodeGeneratorRequest::clear_parameter() {
   parameter_.ClearToEmptyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
   _has_bits_[0] &= ~0x00000001u;
 }
 inline const std::string& CodeGeneratorRequest::parameter() const {
   // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.parameter)
-  return parameter_.GetNoArena();
+  return _internal_parameter();
 }
 inline void CodeGeneratorRequest::set_parameter(const std::string& value) {
+  _internal_set_parameter(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+}
+inline std::string* CodeGeneratorRequest::mutable_parameter() {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+  return _internal_mutable_parameter();
+}
+inline const std::string& CodeGeneratorRequest::_internal_parameter() const {
+  return parameter_.GetNoArena();
+}
+inline void CodeGeneratorRequest::_internal_set_parameter(const std::string& value) {
   _has_bits_[0] |= 0x00000001u;
   parameter_.SetNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value);
-  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorRequest.parameter)
 }
 inline void CodeGeneratorRequest::set_parameter(std::string&& value) {
   _has_bits_[0] |= 0x00000001u;
@@ -998,9 +1098,8 @@ inline void CodeGeneratorRequest::set_parameter(const char* value, size_t size)
       ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorRequest.parameter)
 }
-inline std::string* CodeGeneratorRequest::mutable_parameter() {
+inline std::string* CodeGeneratorRequest::_internal_mutable_parameter() {
   _has_bits_[0] |= 0x00000001u;
-  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.parameter)
   return parameter_.MutableNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 inline std::string* CodeGeneratorRequest::release_parameter() {
@@ -1049,9 +1148,12 @@ CodeGeneratorRequest::proto_file() const {
 }
 
 // optional .google.protobuf.compiler.Version compiler_version = 3;
-inline bool CodeGeneratorRequest::has_compiler_version() const {
+inline bool CodeGeneratorRequest::_internal_has_compiler_version() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
 }
+inline bool CodeGeneratorRequest::has_compiler_version() const {
+  return _internal_has_compiler_version();
+}
 inline void CodeGeneratorRequest::clear_compiler_version() {
   if (compiler_version_ != nullptr) compiler_version_->Clear();
   _has_bits_[0] &= ~0x00000002u;
@@ -1102,21 +1204,34 @@ inline void CodeGeneratorRequest::set_allocated_compiler_version(PROTOBUF_NAMESP
 // CodeGeneratorResponse_File
 
 // optional string name = 1;
-inline bool CodeGeneratorResponse_File::has_name() const {
+inline bool CodeGeneratorResponse_File::_internal_has_name() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
+inline bool CodeGeneratorResponse_File::has_name() const {
+  return _internal_has_name();
+}
 inline void CodeGeneratorResponse_File::clear_name() {
   name_.ClearToEmptyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
   _has_bits_[0] &= ~0x00000001u;
 }
 inline const std::string& CodeGeneratorResponse_File::name() const {
   // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.name)
-  return name_.GetNoArena();
+  return _internal_name();
 }
 inline void CodeGeneratorResponse_File::set_name(const std::string& value) {
+  _internal_set_name(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+}
+inline std::string* CodeGeneratorResponse_File::mutable_name() {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+  return _internal_mutable_name();
+}
+inline const std::string& CodeGeneratorResponse_File::_internal_name() const {
+  return name_.GetNoArena();
+}
+inline void CodeGeneratorResponse_File::_internal_set_name(const std::string& value) {
   _has_bits_[0] |= 0x00000001u;
   name_.SetNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value);
-  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.name)
 }
 inline void CodeGeneratorResponse_File::set_name(std::string&& value) {
   _has_bits_[0] |= 0x00000001u;
@@ -1136,9 +1251,8 @@ inline void CodeGeneratorResponse_File::set_name(const char* value, size_t size)
       ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.name)
 }
-inline std::string* CodeGeneratorResponse_File::mutable_name() {
+inline std::string* CodeGeneratorResponse_File::_internal_mutable_name() {
   _has_bits_[0] |= 0x00000001u;
-  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.name)
   return name_.MutableNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 inline std::string* CodeGeneratorResponse_File::release_name() {
@@ -1160,21 +1274,34 @@ inline void CodeGeneratorResponse_File::set_allocated_name(std::string* name) {
 }
 
 // optional string insertion_point = 2;
-inline bool CodeGeneratorResponse_File::has_insertion_point() const {
+inline bool CodeGeneratorResponse_File::_internal_has_insertion_point() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
 }
+inline bool CodeGeneratorResponse_File::has_insertion_point() const {
+  return _internal_has_insertion_point();
+}
 inline void CodeGeneratorResponse_File::clear_insertion_point() {
   insertion_point_.ClearToEmptyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
   _has_bits_[0] &= ~0x00000002u;
 }
 inline const std::string& CodeGeneratorResponse_File::insertion_point() const {
   // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
-  return insertion_point_.GetNoArena();
+  return _internal_insertion_point();
 }
 inline void CodeGeneratorResponse_File::set_insertion_point(const std::string& value) {
+  _internal_set_insertion_point(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+}
+inline std::string* CodeGeneratorResponse_File::mutable_insertion_point() {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+  return _internal_mutable_insertion_point();
+}
+inline const std::string& CodeGeneratorResponse_File::_internal_insertion_point() const {
+  return insertion_point_.GetNoArena();
+}
+inline void CodeGeneratorResponse_File::_internal_set_insertion_point(const std::string& value) {
   _has_bits_[0] |= 0x00000002u;
   insertion_point_.SetNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value);
-  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
 }
 inline void CodeGeneratorResponse_File::set_insertion_point(std::string&& value) {
   _has_bits_[0] |= 0x00000002u;
@@ -1194,9 +1321,8 @@ inline void CodeGeneratorResponse_File::set_insertion_point(const char* value, s
       ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
 }
-inline std::string* CodeGeneratorResponse_File::mutable_insertion_point() {
+inline std::string* CodeGeneratorResponse_File::_internal_mutable_insertion_point() {
   _has_bits_[0] |= 0x00000002u;
-  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
   return insertion_point_.MutableNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 inline std::string* CodeGeneratorResponse_File::release_insertion_point() {
@@ -1218,21 +1344,34 @@ inline void CodeGeneratorResponse_File::set_allocated_insertion_point(std::strin
 }
 
 // optional string content = 15;
-inline bool CodeGeneratorResponse_File::has_content() const {
+inline bool CodeGeneratorResponse_File::_internal_has_content() const {
   return (_has_bits_[0] & 0x00000004u) != 0;
 }
+inline bool CodeGeneratorResponse_File::has_content() const {
+  return _internal_has_content();
+}
 inline void CodeGeneratorResponse_File::clear_content() {
   content_.ClearToEmptyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
   _has_bits_[0] &= ~0x00000004u;
 }
 inline const std::string& CodeGeneratorResponse_File::content() const {
   // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.content)
-  return content_.GetNoArena();
+  return _internal_content();
 }
 inline void CodeGeneratorResponse_File::set_content(const std::string& value) {
+  _internal_set_content(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+}
+inline std::string* CodeGeneratorResponse_File::mutable_content() {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+  return _internal_mutable_content();
+}
+inline const std::string& CodeGeneratorResponse_File::_internal_content() const {
+  return content_.GetNoArena();
+}
+inline void CodeGeneratorResponse_File::_internal_set_content(const std::string& value) {
   _has_bits_[0] |= 0x00000004u;
   content_.SetNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value);
-  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.content)
 }
 inline void CodeGeneratorResponse_File::set_content(std::string&& value) {
   _has_bits_[0] |= 0x00000004u;
@@ -1252,9 +1391,8 @@ inline void CodeGeneratorResponse_File::set_content(const char* value, size_t si
       ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.content)
 }
-inline std::string* CodeGeneratorResponse_File::mutable_content() {
+inline std::string* CodeGeneratorResponse_File::_internal_mutable_content() {
   _has_bits_[0] |= 0x00000004u;
-  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.content)
   return content_.MutableNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 inline std::string* CodeGeneratorResponse_File::release_content() {
@@ -1280,21 +1418,34 @@ inline void CodeGeneratorResponse_File::set_allocated_content(std::string* conte
 // CodeGeneratorResponse
 
 // optional string error = 1;
-inline bool CodeGeneratorResponse::has_error() const {
+inline bool CodeGeneratorResponse::_internal_has_error() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
+inline bool CodeGeneratorResponse::has_error() const {
+  return _internal_has_error();
+}
 inline void CodeGeneratorResponse::clear_error() {
   error_.ClearToEmptyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
   _has_bits_[0] &= ~0x00000001u;
 }
 inline const std::string& CodeGeneratorResponse::error() const {
   // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.error)
-  return error_.GetNoArena();
+  return _internal_error();
 }
 inline void CodeGeneratorResponse::set_error(const std::string& value) {
+  _internal_set_error(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.error)
+}
+inline std::string* CodeGeneratorResponse::mutable_error() {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.error)
+  return _internal_mutable_error();
+}
+inline const std::string& CodeGeneratorResponse::_internal_error() const {
+  return error_.GetNoArena();
+}
+inline void CodeGeneratorResponse::_internal_set_error(const std::string& value) {
   _has_bits_[0] |= 0x00000001u;
   error_.SetNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value);
-  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.error)
 }
 inline void CodeGeneratorResponse::set_error(std::string&& value) {
   _has_bits_[0] |= 0x00000001u;
@@ -1314,9 +1465,8 @@ inline void CodeGeneratorResponse::set_error(const char* value, size_t size) {
       ::std::string(reinterpret_cast<const char*>(value), size));
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.error)
 }
-inline std::string* CodeGeneratorResponse::mutable_error() {
+inline std::string* CodeGeneratorResponse::_internal_mutable_error() {
   _has_bits_[0] |= 0x00000001u;
-  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.error)
   return error_.MutableNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 inline std::string* CodeGeneratorResponse::release_error() {

+ 0 - 2
src/google/protobuf/compiler/python/python_generator.cc

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

+ 4 - 6
src/google/protobuf/descriptor.cc

@@ -32,6 +32,8 @@
 //  Based on original Protocol Buffers design by
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
+#include <google/protobuf/descriptor.h>
+
 #include <algorithm>
 #include <functional>
 #include <limits>
@@ -48,11 +50,9 @@
 #include <google/protobuf/stubs/stringprintf.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/io/strtod.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/tokenizer.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
-#include <google/protobuf/descriptor.h>
 #include <google/protobuf/descriptor_database.h>
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/generated_message_util.h>
@@ -61,9 +61,7 @@
 #include <google/protobuf/wire_format.h>
 #include <google/protobuf/stubs/substitute.h>
 #include <google/protobuf/stubs/casts.h>
-
-
-
+#include <google/protobuf/io/strtod.h>
 #include <google/protobuf/stubs/map_util.h>
 #include <google/protobuf/stubs/stl_util.h>
 #include <google/protobuf/stubs/hash.h>
@@ -4696,7 +4694,7 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
              // `ErrorCollector` interface to extend them to handle the new
              // error location type properly.
              DescriptorPool::ErrorCollector::TYPE,
-             "Message extensions cannot have required fields.");
+             "The extension " + result->full_name() + " cannot be required.");
   }
 
   // Some of these may be filled in when cross-linking.

Datei-Diff unterdrückt, da er zu groß ist
+ 173 - 221
src/google/protobuf/descriptor.pb.cc


Datei-Diff unterdrückt, da er zu groß ist
+ 386 - 0
src/google/protobuf/descriptor.pb.h


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

@@ -38,7 +38,6 @@
 
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/stubs/strutil.h>
-
 #include <google/protobuf/stubs/map_util.h>
 #include <google/protobuf/stubs/stl_util.h>
 

+ 1 - 2
src/google/protobuf/descriptor_unittest.cc

@@ -4535,8 +4535,7 @@ TEST_F(ValidationErrorTest, RequiredExtension) {
       "  }"
       "}",
 
-      "foo.proto: Foo.foo: TYPE: Message extensions cannot have required "
-      "fields.\n");
+      "foo.proto: Foo.foo: TYPE: The extension Foo.foo cannot be required.\n");
 }
 
 TEST_F(ValidationErrorTest, UndefinedFieldType) {

+ 1 - 1
src/google/protobuf/duration.pb.cc

@@ -32,7 +32,7 @@ static void InitDefaultsscc_info_Duration_google_2fprotobuf_2fduration_2eproto()
 }
 
 PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::internal::SCCInfo<0> scc_info_Duration_google_2fprotobuf_2fduration_2eproto =
-    {{ATOMIC_VAR_INIT(::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase::kUninitialized), 0, InitDefaultsscc_info_Duration_google_2fprotobuf_2fduration_2eproto}, {}};
+    {{ATOMIC_VAR_INIT(::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase::kUninitialized), 0, 0, InitDefaultsscc_info_Duration_google_2fprotobuf_2fduration_2eproto}, {}};
 
 static ::PROTOBUF_NAMESPACE_ID::Metadata file_level_metadata_google_2fprotobuf_2fduration_2eproto[1];
 static constexpr ::PROTOBUF_NAMESPACE_ID::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fduration_2eproto = nullptr;

+ 1 - 1
src/google/protobuf/duration.proto

@@ -61,7 +61,7 @@ option objc_class_prefix = "GPB";
 //     if (duration.seconds < 0 && duration.nanos > 0) {
 //       duration.seconds += 1;
 //       duration.nanos -= 1000000000;
-//     } else if (durations.seconds > 0 && duration.nanos < 0) {
+//     } else if (duration.seconds > 0 && duration.nanos < 0) {
 //       duration.seconds -= 1;
 //       duration.nanos += 1000000000;
 //     }

+ 1 - 1
src/google/protobuf/empty.pb.cc

@@ -32,7 +32,7 @@ static void InitDefaultsscc_info_Empty_google_2fprotobuf_2fempty_2eproto() {
 }
 
 PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::internal::SCCInfo<0> scc_info_Empty_google_2fprotobuf_2fempty_2eproto =
-    {{ATOMIC_VAR_INIT(::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase::kUninitialized), 0, InitDefaultsscc_info_Empty_google_2fprotobuf_2fempty_2eproto}, {}};
+    {{ATOMIC_VAR_INIT(::PROTOBUF_NAMESPACE_ID::internal::SCCInfoBase::kUninitialized), 0, 0, InitDefaultsscc_info_Empty_google_2fprotobuf_2fempty_2eproto}, {}};
 
 static ::PROTOBUF_NAMESPACE_ID::Metadata file_level_metadata_google_2fprotobuf_2fempty_2eproto[1];
 static constexpr ::PROTOBUF_NAMESPACE_ID::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fempty_2eproto = nullptr;

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

@@ -1334,7 +1334,7 @@ RepeatedMessageTypeTraits<Type>::GetDefaultRepeatedField() {
 // This is the type of actual extension objects.  E.g. if you have:
 //   extends Foo with optional int32 bar = 1234;
 // then "bar" will be defined in C++ as:
-//   ExtensionIdentifier<Foo, PrimitiveTypeTraits<int32>, 1, false> bar(1234);
+//   ExtensionIdentifier<Foo, PrimitiveTypeTraits<int32>, 5, false> bar(1234);
 //
 // Note that we could, in theory, supply the field number as a template
 // parameter, and thus make an instance of ExtensionIdentifier have no

+ 6 - 13
src/google/protobuf/extension_set_inl.h

@@ -84,7 +84,7 @@ const char* ExtensionSet::ParseFieldWithExtensionInfo(
 #define HANDLE_VARINT_TYPE(UPPERCASE, CPP_CAMELCASE)                        \
   case WireFormatLite::TYPE_##UPPERCASE: {                                  \
     uint64 value;                                                           \
-    ptr = ParseVarint64(ptr, &value);                                       \
+    ptr = VarintParse(ptr, &value);                                         \
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);                                    \
     if (extension.is_repeated) {                                            \
       Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE,          \
@@ -103,7 +103,7 @@ const char* ExtensionSet::ParseFieldWithExtensionInfo(
 #define HANDLE_SVARINT_TYPE(UPPERCASE, CPP_CAMELCASE, SIZE)                 \
   case WireFormatLite::TYPE_##UPPERCASE: {                                  \
     uint64 val;                                                             \
-    ptr = ParseVarint64(ptr, &val);                                         \
+    ptr = VarintParse(ptr, &val);                                           \
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);                                    \
     auto value = WireFormatLite::ZigZagDecode##SIZE(val);                   \
     if (extension.is_repeated) {                                            \
@@ -120,8 +120,7 @@ const char* ExtensionSet::ParseFieldWithExtensionInfo(
 #undef HANDLE_SVARINT_TYPE
 #define HANDLE_FIXED_TYPE(UPPERCASE, CPP_CAMELCASE, CPPTYPE)                \
   case WireFormatLite::TYPE_##UPPERCASE: {                                  \
-    CPPTYPE value;                                                          \
-    std::memcpy(&value, ptr, sizeof(CPPTYPE));                              \
+    auto value = UnalignedLoad<CPPTYPE>(ptr);                               \
     ptr += sizeof(CPPTYPE);                                                 \
     if (extension.is_repeated) {                                            \
       Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE,          \
@@ -143,7 +142,7 @@ const char* ExtensionSet::ParseFieldWithExtensionInfo(
 
       case WireFormatLite::TYPE_ENUM: {
         uint64 val;
-        ptr = ParseVarint64(ptr, &val);
+        ptr = VarintParse(ptr, &val);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         int value = val;
 
@@ -213,7 +212,7 @@ const char* ExtensionSet::ParseMessageSetItemTmpl(const char* ptr,
     uint32 tag = static_cast<uint8>(*ptr++);
     if (tag == WireFormatLite::kMessageSetTypeIdTag) {
       uint64 tmp;
-      ptr = ParseVarint64Inline(ptr, &tmp);
+      ptr = ParseBigVarint(ptr, &tmp);
       GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
       type_id = tmp;
       if (!payload.empty()) {
@@ -257,13 +256,7 @@ const char* ExtensionSet::ParseMessageSetItemTmpl(const char* ptr,
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
       }
     } else {
-      if (tag >= 128) {
-        // Parse remainder of tag varint
-        uint32 tmp;
-        ptr = VarintParse<4>(ptr, &tmp);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        tag += (tmp - 1) << 7;
-      }
+      ptr = ReadTag(ptr - 1, &tag);
       if (tag == 0 || (tag & 7) == 4) {
         ctx->SetLastTag(tag);
         return ptr;

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.