Browse Source

Merge pull request #2403 from google/down-integrate-with-msvc-fix

Integrated internal changes from Google
Adam Cozzette 8 years ago
parent
commit
39f9b43219
100 changed files with 3003 additions and 1553 deletions
  1. 3 0
      Makefile.am
  2. 1 0
      cmake/libprotoc.cmake
  3. 176 4
      conformance/ConformanceJava.java
  4. 12 14
      conformance/conformance_test.cc
  5. 0 7
      conformance/failure_list_cpp.txt
  6. 0 6
      conformance/failure_list_csharp.txt
  7. 2 6
      conformance/failure_list_java.txt
  8. 0 6
      conformance/failure_list_python.txt
  9. 0 6
      conformance/failure_list_python_cpp.txt
  10. 0 6
      conformance/failure_list_ruby.txt
  11. 60 7
      csharp/src/Google.Protobuf/Reflection/Descriptor.cs
  12. 3 2
      csharp/src/Google.Protobuf/WellKnownTypes/Api.cs
  13. 5 3
      csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs
  14. 4 3
      csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs
  15. 4 3
      csharp/src/Google.Protobuf/WellKnownTypes/Type.cs
  16. 1 1
      java/core/src/main/java/com/google/protobuf/AbstractParser.java
  17. 9 9
      java/core/src/main/java/com/google/protobuf/ByteString.java
  18. 1 1
      java/core/src/main/java/com/google/protobuf/Descriptors.java
  19. 1 1
      java/core/src/main/java/com/google/protobuf/DynamicMessage.java
  20. 0 1
      java/core/src/main/java/com/google/protobuf/ExtensionRegistry.java
  21. 4 3
      java/core/src/main/java/com/google/protobuf/ExtensionRegistryLite.java
  22. 151 12
      java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
  23. 12 14
      java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
  24. 2 23
      java/core/src/main/java/com/google/protobuf/LazyFieldLite.java
  25. 1 1
      java/core/src/main/java/com/google/protobuf/MapEntry.java
  26. 2 2
      java/core/src/main/java/com/google/protobuf/MessageLiteToString.java
  27. 1 1
      java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
  28. 37 1
      java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java
  29. 0 24
      java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
  30. 13 0
      java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
  31. 26 0
      java/core/src/test/java/com/google/protobuf/LiteTest.java
  32. 0 1
      java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
  33. 50 55
      java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
  34. 82 75
      java/core/src/test/java/com/google/protobuf/MapTest.java
  35. 40 0
      java/core/src/test/java/com/google/protobuf/ParserTest.java
  36. 2 6
      java/util/src/main/java/com/google/protobuf/util/Durations.java
  37. 6 1
      java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java
  38. 28 11
      java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
  39. 2 6
      java/util/src/main/java/com/google/protobuf/util/Timestamps.java
  40. 37 1
      java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
  41. 5 0
      java/util/src/test/proto/com/google/protobuf/util/json_test.proto
  42. 46 0
      js/binary/decoder.js
  43. 45 2
      js/binary/encoder.js
  44. 39 2
      js/binary/proto_test.js
  45. 94 2
      js/binary/reader.js
  46. 10 0
      js/binary/utils.js
  47. 214 201
      js/binary/writer.js
  48. 1 0
      js/commonjs/export.js
  49. 1 0
      js/commonjs/export_testdeps.js
  50. 3 3
      js/gulpfile.js
  51. 4 1
      js/jasmine.json
  52. 53 1
      js/map.js
  53. 13 8
      js/maps_test.js
  54. 3 2
      js/message.js
  55. 6 1
      js/message_test.js
  56. 38 0
      js/proto3_test.js
  57. 3 0
      js/test.proto
  58. 0 5
      protobuf.bzl
  59. 99 0
      python/google/protobuf/descriptor_pool.py
  60. 3 3
      python/google/protobuf/internal/decoder.py
  61. 47 0
      python/google/protobuf/internal/descriptor_pool_test.py
  62. 10 10
      python/google/protobuf/internal/message_factory_test.py
  63. 12 25
      python/google/protobuf/internal/python_message.py
  64. 57 10
      python/google/protobuf/internal/reflection_test.py
  65. 153 1
      python/google/protobuf/internal/test_util.py
  66. 0 2
      python/google/protobuf/internal/testing_refleaks.py
  67. 14 16
      python/google/protobuf/internal/text_format_test.py
  68. 8 7
      python/google/protobuf/internal/type_checkers.py
  69. 2 2
      python/google/protobuf/json_format.py
  70. 67 0
      python/google/protobuf/pyext/descriptor_pool.cc
  71. 58 19
      python/google/protobuf/pyext/extension_dict.cc
  72. 1 1
      python/google/protobuf/pyext/map_container.cc
  73. 205 204
      python/google/protobuf/pyext/message.cc
  74. 10 14
      python/google/protobuf/pyext/message.h
  75. 66 0
      python/google/protobuf/pyext/message_factory.cc
  76. 6 6
      python/google/protobuf/pyext/message_factory.h
  77. 164 0
      python/google/protobuf/pyext/safe_numerics.h
  78. 4 2
      ruby/tests/basic.rb
  79. 2 0
      src/Makefile.am
  80. 4 4
      src/google/protobuf/any.cc
  81. 82 104
      src/google/protobuf/any.pb.cc
  82. 38 37
      src/google/protobuf/any.pb.h
  83. 220 291
      src/google/protobuf/api.pb.cc
  84. 131 114
      src/google/protobuf/api.pb.h
  85. 1 0
      src/google/protobuf/api.proto
  86. 14 4
      src/google/protobuf/arena.cc
  87. 31 0
      src/google/protobuf/arena_test_util.h
  88. 8 1
      src/google/protobuf/arena_unittest.cc
  89. 1 1
      src/google/protobuf/arenastring.cc
  90. 7 10
      src/google/protobuf/arenastring.h
  91. 10 12
      src/google/protobuf/arenastring_unittest.cc
  92. 5 5
      src/google/protobuf/compiler/code_generator.cc
  93. 3 3
      src/google/protobuf/compiler/code_generator.h
  94. 41 38
      src/google/protobuf/compiler/command_line_interface.cc
  95. 18 19
      src/google/protobuf/compiler/command_line_interface.h
  96. 4 4
      src/google/protobuf/compiler/command_line_interface_unittest.cc
  97. 1 1
      src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
  98. 21 18
      src/google/protobuf/compiler/cpp/cpp_enum.cc
  99. 6 2
      src/google/protobuf/compiler/cpp/cpp_enum.h
  100. 13 12
      src/google/protobuf/compiler/cpp/cpp_enum_field.cc

+ 3 - 0
Makefile.am

@@ -605,6 +605,8 @@ php_EXTRA_DIST=                                              \
   php/tests/test.proto                                       \
   php/tests/test.pb.php                                      \
   php/tests/memory_leak_test.php                             \
+  php/tests/google/protobuf/empty.pb.php                     \
+  php/tests/well_known_test.php                              \
   php/README.md                                              \
   php/ext/google/protobuf/utf8.h                             \
   php/ext/google/protobuf/message.c                          \
@@ -712,6 +714,7 @@ python_EXTRA_DIST=                                                           \
   python/google/protobuf/pyext/repeated_composite_container.h                \
   python/google/protobuf/pyext/repeated_scalar_container.cc                  \
   python/google/protobuf/pyext/repeated_scalar_container.h                   \
+  python/google/protobuf/pyext/safe_numerics.h                               \
   python/google/protobuf/pyext/scoped_pyobject_ptr.h                         \
   python/google/protobuf/reflection.py                                       \
   python/google/protobuf/service.py                                          \

+ 1 - 0
cmake/libprotoc.cmake

@@ -72,6 +72,7 @@ set(libprotoc_files
   ${protobuf_source_dir}/src/google/protobuf/compiler/javanano/javanano_message_field.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/js/js_generator.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/js/well_known_types_embed.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_enum.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_extension.cc

+ 176 - 4
conformance/ConformanceJava.java

@@ -1,8 +1,11 @@
-
+import com.google.protobuf.ByteString;
+import com.google.protobuf.CodedInputStream;
+import com.google.protobuf.InvalidProtocolBufferException;
 import com.google.protobuf.conformance.Conformance;
-import com.google.protobuf.util.JsonFormat;
 import com.google.protobuf.util.JsonFormat.TypeRegistry;
-import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.util.JsonFormat;
+import java.io.IOException;
+import java.nio.ByteBuffer;
 
 class ConformanceJava {
   private int testCount = 0;
@@ -47,13 +50,182 @@ class ConformanceJava {
     writeToStdout(buf);
   }
 
+  private enum BinaryDecoder {
+    BYTE_STRING_DECODER() {
+      @Override
+      public Conformance.TestAllTypes parse(ByteString bytes)
+          throws InvalidProtocolBufferException {
+        return Conformance.TestAllTypes.parseFrom(bytes);
+      }
+    },
+    BYTE_ARRAY_DECODER() {
+      @Override
+      public Conformance.TestAllTypes parse(ByteString bytes)
+          throws InvalidProtocolBufferException {
+        return Conformance.TestAllTypes.parseFrom(bytes.toByteArray());
+      }
+    },
+    ARRAY_BYTE_BUFFER_DECODER() {
+      @Override
+      public Conformance.TestAllTypes parse(ByteString bytes)
+          throws InvalidProtocolBufferException {
+        ByteBuffer buffer = ByteBuffer.allocate(bytes.size());
+        bytes.copyTo(buffer);
+        buffer.flip();
+        try {
+          return Conformance.TestAllTypes.parseFrom(CodedInputStream.newInstance(buffer));
+        } catch (InvalidProtocolBufferException e) {
+          throw e;
+        } catch (IOException e) {
+          throw new RuntimeException(
+              "ByteString based ByteBuffer should not throw IOException.", e);
+        }
+      }
+    },
+    READONLY_ARRAY_BYTE_BUFFER_DECODER() {
+      @Override
+      public Conformance.TestAllTypes parse(ByteString bytes)
+          throws InvalidProtocolBufferException {
+        try {
+          return Conformance.TestAllTypes.parseFrom(
+              CodedInputStream.newInstance(bytes.asReadOnlyByteBuffer()));
+        } catch (InvalidProtocolBufferException e) {
+          throw e;
+        } catch (IOException e) {
+          throw new RuntimeException(
+              "ByteString based ByteBuffer should not throw IOException.", e);
+        }
+      }
+    },
+    DIRECT_BYTE_BUFFER_DECODER() {
+      @Override
+      public Conformance.TestAllTypes parse(ByteString bytes)
+          throws InvalidProtocolBufferException {
+        ByteBuffer buffer = ByteBuffer.allocateDirect(bytes.size());
+        bytes.copyTo(buffer);
+        buffer.flip();
+        try {
+          return Conformance.TestAllTypes.parseFrom(CodedInputStream.newInstance(buffer));
+        } catch (InvalidProtocolBufferException e) {
+          throw e;
+        } catch (IOException e) {
+          throw new RuntimeException(
+              "ByteString based ByteBuffer should not throw IOException.", e);
+        }
+      }
+    },
+    READONLY_DIRECT_BYTE_BUFFER_DECODER() {
+      @Override
+      public Conformance.TestAllTypes parse(ByteString bytes)
+          throws InvalidProtocolBufferException {
+        ByteBuffer buffer = ByteBuffer.allocateDirect(bytes.size());
+        bytes.copyTo(buffer);
+        buffer.flip();
+        try {
+          return Conformance.TestAllTypes.parseFrom(
+              CodedInputStream.newInstance(buffer.asReadOnlyBuffer()));
+        } catch (InvalidProtocolBufferException e) {
+          throw e;
+        } catch (IOException e) {
+          throw new RuntimeException(
+              "ByteString based ByteBuffer should not throw IOException.", e);
+        }
+      }
+    },
+    INPUT_STREAM_DECODER() {
+      @Override
+      public Conformance.TestAllTypes parse(ByteString bytes)
+          throws InvalidProtocolBufferException {
+        try {
+          return Conformance.TestAllTypes.parseFrom(bytes.newInput());
+        } catch (InvalidProtocolBufferException e) {
+          throw e;
+        } catch (IOException e) {
+          throw new RuntimeException(
+              "ByteString based InputStream should not throw IOException.", e);
+        }
+      }
+    };
+
+    public abstract Conformance.TestAllTypes parse(ByteString bytes)
+        throws InvalidProtocolBufferException;
+  }
+
+  private Conformance.TestAllTypes parseBinary(ByteString bytes)
+      throws InvalidProtocolBufferException {
+    Conformance.TestAllTypes[] messages =
+        new Conformance.TestAllTypes[BinaryDecoder.values().length];
+    InvalidProtocolBufferException[] exceptions =
+        new InvalidProtocolBufferException[BinaryDecoder.values().length];
+
+    boolean hasMessage = false;
+    boolean hasException = false;
+    for (int i = 0; i < BinaryDecoder.values().length; ++i) {
+      try {
+        messages[i] = BinaryDecoder.values()[i].parse(bytes);
+        hasMessage = true;
+      } catch (InvalidProtocolBufferException e) {
+        exceptions[i] = e;
+        hasException = true;
+      }
+    }
+
+    if (hasMessage && hasException) {
+      StringBuilder sb =
+          new StringBuilder("Binary decoders disagreed on whether the payload was valid.\n");
+      for (int i = 0; i < BinaryDecoder.values().length; ++i) {
+        sb.append(BinaryDecoder.values()[i].name());
+        if (messages[i] != null) {
+          sb.append(" accepted the payload.\n");
+        } else {
+          sb.append(" rejected the payload.\n");
+        }
+      }
+      throw new RuntimeException(sb.toString());
+    }
+
+    if (hasException) {
+      // We do not check if exceptions are equal. Different implementations may return different
+      // exception messages. Throw an arbitrary one out instead.
+      throw exceptions[0];
+    }
+
+    // Fast path comparing all the messages with the first message, assuming equality being
+    // symmetric and transitive.
+    boolean allEqual = true;
+    for (int i = 1; i < messages.length; ++i) {
+      if (!messages[0].equals(messages[i])) {
+        allEqual = false;
+        break;
+      }
+    }
+
+    // Slow path: compare and find out all unequal pairs.
+    if (!allEqual) {
+      StringBuilder sb = new StringBuilder();
+      for (int i = 0; i < messages.length - 1; ++i) {
+        for (int j = i + 1; j < messages.length; ++j) {
+          if (!messages[i].equals(messages[j])) {
+            sb.append(BinaryDecoder.values()[i].name())
+                .append(" and ")
+                .append(BinaryDecoder.values()[j].name())
+                .append(" parsed the payload differently.\n");
+          }
+        }
+      }
+      throw new RuntimeException(sb.toString());
+    }
+
+    return messages[0];
+  }
+
   private Conformance.ConformanceResponse doTest(Conformance.ConformanceRequest request) {
     Conformance.TestAllTypes testMessage;
 
     switch (request.getPayloadCase()) {
       case PROTOBUF_PAYLOAD: {
         try {
-          testMessage = Conformance.TestAllTypes.parseFrom(request.getProtobufPayload());
+          testMessage = parseBinary(request.getProtobufPayload());
         } catch (InvalidProtocolBufferException e) {
           return Conformance.ConformanceResponse.newBuilder().setParseError(e.getMessage()).build();
         }

+ 12 - 14
conformance/conformance_test.cc

@@ -685,7 +685,7 @@ bool ConformanceTestSuite::RunSuite(ConformanceTestRunner* runner,
       R"({
         "fieldname1": 1,
         "fieldName2": 2,
-        "fieldName3": 3,
+        "FieldName3": 3,
         "fieldName4": 4
       })",
       R"(
@@ -725,12 +725,12 @@ bool ConformanceTestSuite::RunSuite(ConformanceTestRunner* runner,
   RunValidJsonTest(
       "FieldNameWithDoubleUnderscores", RECOMMENDED,
       R"({
-        "fieldName13": 13,
-        "fieldName14": 14,
+        "FieldName13": 13,
+        "FieldName14": 14,
         "fieldName15": 15,
         "fieldName16": 16,
         "fieldName17": 17,
-        "fieldName18": 18
+        "FieldName18": 18
       })",
       R"(
         __field_name13: 13
@@ -873,21 +873,19 @@ bool ConformanceTestSuite::RunSuite(ConformanceTestRunner* runner,
         "optionalNestedMessage": {a: 1},
         "optional_nested_message": {}
       })");
-  // NOTE: The spec for JSON support is still being sorted out, these may not
-  // all be correct.
   // Serializers should use lowerCamelCase by default.
   RunValidJsonTestWithValidator(
       "FieldNameInLowerCamelCase", REQUIRED,
       R"({
         "fieldname1": 1,
         "fieldName2": 2,
-        "fieldName3": 3,
+        "FieldName3": 3,
         "fieldName4": 4
       })",
       [](const Json::Value& value) {
         return value.isMember("fieldname1") &&
             value.isMember("fieldName2") &&
-            value.isMember("fieldName3") &&
+            value.isMember("FieldName3") &&
             value.isMember("fieldName4");
       });
   RunValidJsonTestWithValidator(
@@ -921,20 +919,20 @@ bool ConformanceTestSuite::RunSuite(ConformanceTestRunner* runner,
   RunValidJsonTestWithValidator(
       "FieldNameWithDoubleUnderscores", RECOMMENDED,
       R"({
-        "fieldName13": 13,
-        "fieldName14": 14,
+        "FieldName13": 13,
+        "FieldName14": 14,
         "fieldName15": 15,
         "fieldName16": 16,
         "fieldName17": 17,
-        "fieldName18": 18
+        "FieldName18": 18
       })",
       [](const Json::Value& value) {
-        return value.isMember("fieldName13") &&
-            value.isMember("fieldName14") &&
+        return value.isMember("FieldName13") &&
+            value.isMember("FieldName14") &&
             value.isMember("fieldName15") &&
             value.isMember("fieldName16") &&
             value.isMember("fieldName17") &&
-            value.isMember("fieldName18");
+            value.isMember("FieldName18");
       });
 
   // Integer fields.

+ 0 - 7
conformance/failure_list_cpp.txt

@@ -17,9 +17,6 @@ Recommended.JsonInput.FieldNameDuplicate
 Recommended.JsonInput.FieldNameDuplicateDifferentCasing1
 Recommended.JsonInput.FieldNameDuplicateDifferentCasing2
 Recommended.JsonInput.FieldNameNotQuoted
-Recommended.JsonInput.FieldNameWithDoubleUnderscores.JsonOutput
-Recommended.JsonInput.FieldNameWithDoubleUnderscores.ProtobufOutput
-Recommended.JsonInput.FieldNameWithDoubleUnderscores.Validator
 Recommended.JsonInput.MapFieldValueIsNull
 Recommended.JsonInput.RepeatedFieldMessageElementIsNull
 Recommended.JsonInput.RepeatedFieldPrimitiveElementIsNull
@@ -35,10 +32,6 @@ Recommended.JsonInput.TrailingCommaInAnObject
 Recommended.JsonInput.TrailingCommaInAnObjectWithNewlines
 Recommended.JsonInput.TrailingCommaInAnObjectWithSpace
 Recommended.JsonInput.TrailingCommaInAnObjectWithSpaceCommaSpace
-Required.JsonInput.DoubleFieldTooSmall
-Required.JsonInput.FieldNameInLowerCamelCase.Validator
-Required.JsonInput.FieldNameInSnakeCase.JsonOutput
-Required.JsonInput.FieldNameInSnakeCase.ProtobufOutput
 Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.MESSAGE
 Required.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE
 Required.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE

+ 0 - 6
conformance/failure_list_csharp.txt

@@ -1,6 +0,0 @@
-Recommended.JsonInput.FieldNameWithDoubleUnderscores.JsonOutput
-Recommended.JsonInput.FieldNameWithDoubleUnderscores.ProtobufOutput
-Recommended.JsonInput.FieldNameWithDoubleUnderscores.Validator
-Required.JsonInput.FieldNameInLowerCamelCase.Validator
-Required.JsonInput.FieldNameInSnakeCase.JsonOutput
-Required.JsonInput.FieldNameInSnakeCase.ProtobufOutput

+ 2 - 6
conformance/failure_list_java.txt

@@ -20,9 +20,6 @@ Recommended.JsonInput.DoubleFieldNegativeInfinityNotQuoted
 Recommended.JsonInput.FieldMaskInvalidCharacter
 Recommended.JsonInput.FieldNameDuplicate
 Recommended.JsonInput.FieldNameNotQuoted
-Recommended.JsonInput.FieldNameWithDoubleUnderscores.JsonOutput
-Recommended.JsonInput.FieldNameWithDoubleUnderscores.ProtobufOutput
-Recommended.JsonInput.FieldNameWithDoubleUnderscores.Validator
 Recommended.JsonInput.FloatFieldInfinityNotQuoted
 Recommended.JsonInput.FloatFieldNanNotQuoted
 Recommended.JsonInput.FloatFieldNegativeInfinityNotQuoted
@@ -38,12 +35,11 @@ Recommended.JsonInput.StringFieldUnpairedLowSurrogate
 Recommended.JsonInput.Uint32MapFieldKeyNotQuoted
 Recommended.JsonInput.Uint64MapFieldKeyNotQuoted
 Required.JsonInput.EnumFieldNotQuoted
-Required.JsonInput.FieldNameInLowerCamelCase.Validator
-Required.JsonInput.FieldNameInSnakeCase.JsonOutput
-Required.JsonInput.FieldNameInSnakeCase.ProtobufOutput
 Required.JsonInput.Int32FieldLeadingZero
 Required.JsonInput.Int32FieldNegativeWithLeadingZero
 Required.JsonInput.Int32FieldPlusSign
 Required.JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotBool
 Required.JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotInt
 Required.JsonInput.StringFieldNotAString
+Required.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE
+Required.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE

+ 0 - 6
conformance/failure_list_python.txt

@@ -1,18 +1,12 @@
 Recommended.JsonInput.DoubleFieldInfinityNotQuoted
 Recommended.JsonInput.DoubleFieldNanNotQuoted
 Recommended.JsonInput.DoubleFieldNegativeInfinityNotQuoted
-Recommended.JsonInput.FieldNameWithDoubleUnderscores.JsonOutput
-Recommended.JsonInput.FieldNameWithDoubleUnderscores.ProtobufOutput
-Recommended.JsonInput.FieldNameWithDoubleUnderscores.Validator
 Recommended.JsonInput.FloatFieldInfinityNotQuoted
 Recommended.JsonInput.FloatFieldNanNotQuoted
 Recommended.JsonInput.FloatFieldNegativeInfinityNotQuoted
 Required.JsonInput.BytesFieldInvalidBase64Characters
 Required.JsonInput.DoubleFieldTooSmall
 Required.JsonInput.EnumFieldUnknownValue.Validator
-Required.JsonInput.FieldNameInLowerCamelCase.Validator
-Required.JsonInput.FieldNameInSnakeCase.JsonOutput
-Required.JsonInput.FieldNameInSnakeCase.ProtobufOutput
 Required.JsonInput.FloatFieldTooLarge
 Required.JsonInput.FloatFieldTooSmall
 Required.JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotBool

+ 0 - 6
conformance/failure_list_python_cpp.txt

@@ -10,18 +10,12 @@
 Recommended.JsonInput.DoubleFieldInfinityNotQuoted
 Recommended.JsonInput.DoubleFieldNanNotQuoted
 Recommended.JsonInput.DoubleFieldNegativeInfinityNotQuoted
-Recommended.JsonInput.FieldNameWithDoubleUnderscores.JsonOutput
-Recommended.JsonInput.FieldNameWithDoubleUnderscores.ProtobufOutput
-Recommended.JsonInput.FieldNameWithDoubleUnderscores.Validator
 Recommended.JsonInput.FloatFieldInfinityNotQuoted
 Recommended.JsonInput.FloatFieldNanNotQuoted
 Recommended.JsonInput.FloatFieldNegativeInfinityNotQuoted
 Required.JsonInput.BytesFieldInvalidBase64Characters
 Required.JsonInput.DoubleFieldTooSmall
 Required.JsonInput.EnumFieldUnknownValue.Validator
-Required.JsonInput.FieldNameInLowerCamelCase.Validator
-Required.JsonInput.FieldNameInSnakeCase.JsonOutput
-Required.JsonInput.FieldNameInSnakeCase.ProtobufOutput
 Required.JsonInput.FloatFieldTooLarge
 Required.JsonInput.FloatFieldTooSmall
 Required.JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotBool

+ 0 - 6
conformance/failure_list_ruby.txt

@@ -7,9 +7,6 @@ Recommended.JsonInput.DurationHas3FractionalDigits.Validator
 Recommended.JsonInput.DurationHas6FractionalDigits.Validator
 Recommended.JsonInput.DurationHas9FractionalDigits.Validator
 Recommended.JsonInput.DurationHasZeroFractionalDigit.Validator
-Recommended.JsonInput.FieldNameWithDoubleUnderscores.JsonOutput
-Recommended.JsonInput.FieldNameWithDoubleUnderscores.ProtobufOutput
-Recommended.JsonInput.FieldNameWithDoubleUnderscores.Validator
 Recommended.JsonInput.Int64FieldBeString.Validator
 Recommended.JsonInput.OneofZeroDouble.JsonOutput
 Recommended.JsonInput.OneofZeroDouble.ProtobufOutput
@@ -80,9 +77,6 @@ Required.JsonInput.EnumFieldNumericValueZero.ProtobufOutput
 Required.JsonInput.EnumFieldUnknownValue.Validator
 Required.JsonInput.FieldMask.JsonOutput
 Required.JsonInput.FieldMask.ProtobufOutput
-Required.JsonInput.FieldNameInLowerCamelCase.Validator
-Required.JsonInput.FieldNameInSnakeCase.JsonOutput
-Required.JsonInput.FieldNameInSnakeCase.ProtobufOutput
 Required.JsonInput.FloatFieldInfinity.JsonOutput
 Required.JsonInput.FloatFieldInfinity.ProtobufOutput
 Required.JsonInput.FloatFieldNan.JsonOutput

+ 60 - 7
csharp/src/Google.Protobuf/Reflection/Descriptor.cs

@@ -120,9 +120,13 @@ namespace Google.Protobuf.Reflection {
             "COgHEICAgIACInsKDlNlcnZpY2VPcHRpb25zEhkKCmRlcHJlY2F0ZWQYISAB",
             "KAg6BWZhbHNlEkMKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdv",
             "b2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAIi",
-            "egoNTWV0aG9kT3B0aW9ucxIZCgpkZXByZWNhdGVkGCEgASgIOgVmYWxzZRJD",
-            "ChR1bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9i",
-            "dWYuVW5pbnRlcnByZXRlZE9wdGlvbioJCOgHEICAgIACIp4CChNVbmludGVy",
+            "rQIKDU1ldGhvZE9wdGlvbnMSGQoKZGVwcmVjYXRlZBghIAEoCDoFZmFsc2US",
+            "XwoRaWRlbXBvdGVuY3lfbGV2ZWwYIiABKA4yLy5nb29nbGUucHJvdG9idWYu",
+            "TWV0aG9kT3B0aW9ucy5JZGVtcG90ZW5jeUxldmVsOhNJREVNUE9URU5DWV9V",
+            "TktOT1dOEkMKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2ds",
+            "ZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uIlAKEElkZW1wb3RlbmN5",
+            "TGV2ZWwSFwoTSURFTVBPVEVOQ1lfVU5LTk9XThAAEhMKD05PX1NJREVfRUZG",
+            "RUNUUxABEg4KCklERU1QT1RFTlQQAioJCOgHEICAgIACIp4CChNVbmludGVy",
             "cHJldGVkT3B0aW9uEjsKBG5hbWUYAiADKAsyLS5nb29nbGUucHJvdG9idWYu",
             "VW5pbnRlcnByZXRlZE9wdGlvbi5OYW1lUGFydBIYChBpZGVudGlmaWVyX3Zh",
             "bHVlGAMgASgJEhoKEnBvc2l0aXZlX2ludF92YWx1ZRgEIAEoBBIaChJuZWdh",
@@ -160,7 +164,7 @@ namespace Google.Protobuf.Reflection {
             new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.EnumOptions), global::Google.Protobuf.Reflection.EnumOptions.Parser, new[]{ "AllowAlias", "Deprecated", "UninterpretedOption" }, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.EnumValueOptions), global::Google.Protobuf.Reflection.EnumValueOptions.Parser, new[]{ "Deprecated", "UninterpretedOption" }, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.ServiceOptions), global::Google.Protobuf.Reflection.ServiceOptions.Parser, new[]{ "Deprecated", "UninterpretedOption" }, null, null, null),
-            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.MethodOptions), global::Google.Protobuf.Reflection.MethodOptions.Parser, new[]{ "Deprecated", "UninterpretedOption" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.MethodOptions), global::Google.Protobuf.Reflection.MethodOptions.Parser, new[]{ "Deprecated", "IdempotencyLevel", "UninterpretedOption" }, null, new[]{ typeof(global::Google.Protobuf.Reflection.MethodOptions.Types.IdempotencyLevel) }, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.UninterpretedOption), global::Google.Protobuf.Reflection.UninterpretedOption.Parser, new[]{ "Name", "IdentifierValue", "PositiveIntValue", "NegativeIntValue", "DoubleValue", "StringValue", "AggregateValue" }, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.UninterpretedOption.Types.NamePart), global::Google.Protobuf.Reflection.UninterpretedOption.Types.NamePart.Parser, new[]{ "NamePart_", "IsExtension" }, null, null, null)}),
             new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.SourceCodeInfo), global::Google.Protobuf.Reflection.SourceCodeInfo.Parser, new[]{ "Location" }, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.SourceCodeInfo.Types.Location), global::Google.Protobuf.Reflection.SourceCodeInfo.Types.Location.Parser, new[]{ "Path", "Span", "LeadingComments", "TrailingComments", "LeadingDetachedComments" }, null, null, null)}),
             new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.GeneratedCodeInfo), global::Google.Protobuf.Reflection.GeneratedCodeInfo.Parser, new[]{ "Annotation" }, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.GeneratedCodeInfo.Types.Annotation), global::Google.Protobuf.Reflection.GeneratedCodeInfo.Types.Annotation.Parser, new[]{ "Path", "SourceFile", "Begin", "End" }, null, null, null)})
@@ -1790,9 +1794,6 @@ namespace Google.Protobuf.Reflection {
         /// </summary>
         [pbr::OriginalName("LABEL_OPTIONAL")] Optional = 1,
         [pbr::OriginalName("LABEL_REQUIRED")] Required = 2,
-        /// <summary>
-        ///  TODO(sanjay): Should we add LABEL_MAP?
-        /// </summary>
         [pbr::OriginalName("LABEL_REPEATED")] Repeated = 3,
       }
 
@@ -4617,6 +4618,7 @@ namespace Google.Protobuf.Reflection {
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
     public MethodOptions(MethodOptions other) : this() {
       deprecated_ = other.deprecated_;
+      idempotencyLevel_ = other.idempotencyLevel_;
       uninterpretedOption_ = other.uninterpretedOption_.Clone();
     }
 
@@ -4642,6 +4644,17 @@ namespace Google.Protobuf.Reflection {
       }
     }
 
+    /// <summary>Field number for the "idempotency_level" field.</summary>
+    public const int IdempotencyLevelFieldNumber = 34;
+    private global::Google.Protobuf.Reflection.MethodOptions.Types.IdempotencyLevel idempotencyLevel_ = 0;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public global::Google.Protobuf.Reflection.MethodOptions.Types.IdempotencyLevel IdempotencyLevel {
+      get { return idempotencyLevel_; }
+      set {
+        idempotencyLevel_ = value;
+      }
+    }
+
     /// <summary>Field number for the "uninterpreted_option" field.</summary>
     public const int UninterpretedOptionFieldNumber = 999;
     private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.UninterpretedOption> _repeated_uninterpretedOption_codec
@@ -4669,6 +4682,7 @@ namespace Google.Protobuf.Reflection {
         return true;
       }
       if (Deprecated != other.Deprecated) return false;
+      if (IdempotencyLevel != other.IdempotencyLevel) return false;
       if(!uninterpretedOption_.Equals(other.uninterpretedOption_)) return false;
       return true;
     }
@@ -4677,6 +4691,7 @@ namespace Google.Protobuf.Reflection {
     public override int GetHashCode() {
       int hash = 1;
       if (Deprecated != false) hash ^= Deprecated.GetHashCode();
+      if (IdempotencyLevel != 0) hash ^= IdempotencyLevel.GetHashCode();
       hash ^= uninterpretedOption_.GetHashCode();
       return hash;
     }
@@ -4692,6 +4707,10 @@ namespace Google.Protobuf.Reflection {
         output.WriteRawTag(136, 2);
         output.WriteBool(Deprecated);
       }
+      if (IdempotencyLevel != 0) {
+        output.WriteRawTag(144, 2);
+        output.WriteEnum((int) IdempotencyLevel);
+      }
       uninterpretedOption_.WriteTo(output, _repeated_uninterpretedOption_codec);
     }
 
@@ -4701,6 +4720,9 @@ namespace Google.Protobuf.Reflection {
       if (Deprecated != false) {
         size += 2 + 1;
       }
+      if (IdempotencyLevel != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeEnumSize((int) IdempotencyLevel);
+      }
       size += uninterpretedOption_.CalculateSize(_repeated_uninterpretedOption_codec);
       return size;
     }
@@ -4713,6 +4735,9 @@ namespace Google.Protobuf.Reflection {
       if (other.Deprecated != false) {
         Deprecated = other.Deprecated;
       }
+      if (other.IdempotencyLevel != 0) {
+        IdempotencyLevel = other.IdempotencyLevel;
+      }
       uninterpretedOption_.Add(other.uninterpretedOption_);
     }
 
@@ -4728,6 +4753,10 @@ namespace Google.Protobuf.Reflection {
             Deprecated = input.ReadBool();
             break;
           }
+          case 272: {
+            idempotencyLevel_ = (global::Google.Protobuf.Reflection.MethodOptions.Types.IdempotencyLevel) input.ReadEnum();
+            break;
+          }
           case 7994: {
             uninterpretedOption_.AddEntriesFrom(input, _repeated_uninterpretedOption_codec);
             break;
@@ -4736,6 +4765,30 @@ namespace Google.Protobuf.Reflection {
       }
     }
 
+    #region Nested types
+    /// <summary>Container for nested types declared in the MethodOptions message type.</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public static partial class Types {
+      /// <summary>
+      ///  Is this method side-effect-free (or safe in HTTP parlance), or idempotent,
+      ///  or neither? HTTP based RPC implementation may choose GET verb for safe
+      ///  methods, and PUT verb for idempotent methods instead of the default POST.
+      /// </summary>
+      internal enum IdempotencyLevel {
+        [pbr::OriginalName("IDEMPOTENCY_UNKNOWN")] IdempotencyUnknown = 0,
+        /// <summary>
+        ///  implies idempotent
+        /// </summary>
+        [pbr::OriginalName("NO_SIDE_EFFECTS")] NoSideEffects = 1,
+        /// <summary>
+        ///  idempotent, but may have side effects
+        /// </summary>
+        [pbr::OriginalName("IDEMPOTENT")] Idempotent = 2,
+      }
+
+    }
+    #endregion
+
   }
 
   /// <summary>

+ 3 - 2
csharp/src/Google.Protobuf/WellKnownTypes/Api.cs

@@ -35,8 +35,9 @@ namespace Google.Protobuf.WellKnownTypes {
             "ChFyZXNwb25zZV90eXBlX3VybBgEIAEoCRIaChJyZXNwb25zZV9zdHJlYW1p",
             "bmcYBSABKAgSKAoHb3B0aW9ucxgGIAMoCzIXLmdvb2dsZS5wcm90b2J1Zi5P",
             "cHRpb24SJwoGc3ludGF4GAcgASgOMhcuZ29vZ2xlLnByb3RvYnVmLlN5bnRh",
-            "eCIjCgVNaXhpbhIMCgRuYW1lGAEgASgJEgwKBHJvb3QYAiABKAlCSAoTY29t",
-            "Lmdvb2dsZS5wcm90b2J1ZkIIQXBpUHJvdG9QAaICA0dQQqoCHkdvb2dsZS5Q",
+            "eCIjCgVNaXhpbhIMCgRuYW1lGAEgASgJEgwKBHJvb3QYAiABKAlCdQoTY29t",
+            "Lmdvb2dsZS5wcm90b2J1ZkIIQXBpUHJvdG9QAVorZ29vZ2xlLmdvbGFuZy5v",
+            "cmcvZ2VucHJvdG8vcHJvdG9idWYvYXBpO2FwaaICA0dQQqoCHkdvb2dsZS5Q",
             "cm90b2J1Zi5XZWxsS25vd25UeXBlc2IGcHJvdG8z"));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.SourceContextReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.TypeReflection.Descriptor, },

+ 5 - 3
csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs

@@ -23,9 +23,11 @@ namespace Google.Protobuf.WellKnownTypes {
       byte[] descriptorData = global::System.Convert.FromBase64String(
           string.Concat(
             "CiBnb29nbGUvcHJvdG9idWYvZmllbGRfbWFzay5wcm90bxIPZ29vZ2xlLnBy",
-            "b3RvYnVmIhoKCUZpZWxkTWFzaxINCgVwYXRocxgBIAMoCUJOChNjb20uZ29v",
-            "Z2xlLnByb3RvYnVmQg5GaWVsZE1hc2tQcm90b1ABogIDR1BCqgIeR29vZ2xl",
-            "LlByb3RvYnVmLldlbGxLbm93blR5cGVzYgZwcm90bzM="));
+            "b3RvYnVmIhoKCUZpZWxkTWFzaxINCgVwYXRocxgBIAMoCUKJAQoTY29tLmdv",
+            "b2dsZS5wcm90b2J1ZkIORmllbGRNYXNrUHJvdG9QAVo5Z29vZ2xlLmdvbGFu",
+            "Zy5vcmcvZ2VucHJvdG8vcHJvdG9idWYvZmllbGRfbWFzaztmaWVsZF9tYXNr",
+            "ogIDR1BCqgIeR29vZ2xlLlByb3RvYnVmLldlbGxLbm93blR5cGVzYgZwcm90",
+            "bzM="));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {

+ 4 - 3
csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs

@@ -24,9 +24,10 @@ namespace Google.Protobuf.WellKnownTypes {
           string.Concat(
             "CiRnb29nbGUvcHJvdG9idWYvc291cmNlX2NvbnRleHQucHJvdG8SD2dvb2ds",
             "ZS5wcm90b2J1ZiIiCg1Tb3VyY2VDb250ZXh0EhEKCWZpbGVfbmFtZRgBIAEo",
-            "CUJSChNjb20uZ29vZ2xlLnByb3RvYnVmQhJTb3VyY2VDb250ZXh0UHJvdG9Q",
-            "AaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IGcHJv",
-            "dG8z"));
+            "CUKVAQoTY29tLmdvb2dsZS5wcm90b2J1ZkISU291cmNlQ29udGV4dFByb3Rv",
+            "UAFaQWdvb2dsZS5nb2xhbmcub3JnL2dlbnByb3RvL3Byb3RvYnVmL3NvdXJj",
+            "ZV9jb250ZXh0O3NvdXJjZV9jb250ZXh0ogIDR1BCqgIeR29vZ2xlLlByb3Rv",
+            "YnVmLldlbGxLbm93blR5cGVzYgZwcm90bzM="));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {

+ 4 - 3
csharp/src/Google.Protobuf/WellKnownTypes/Type.cs

@@ -54,9 +54,10 @@ namespace Google.Protobuf.WellKnownTypes {
             "ASgFEigKB29wdGlvbnMYAyADKAsyFy5nb29nbGUucHJvdG9idWYuT3B0aW9u",
             "IjsKBk9wdGlvbhIMCgRuYW1lGAEgASgJEiMKBXZhbHVlGAIgASgLMhQuZ29v",
             "Z2xlLnByb3RvYnVmLkFueSouCgZTeW50YXgSEQoNU1lOVEFYX1BST1RPMhAA",
-            "EhEKDVNZTlRBWF9QUk9UTzMQAUJMChNjb20uZ29vZ2xlLnByb3RvYnVmQglU",
-            "eXBlUHJvdG9QAfgBAaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25v",
-            "d25UeXBlc2IGcHJvdG8z"));
+            "EhEKDVNZTlRBWF9QUk9UTzMQAUJ9ChNjb20uZ29vZ2xlLnByb3RvYnVmQglU",
+            "eXBlUHJvdG9QAVovZ29vZ2xlLmdvbGFuZy5vcmcvZ2VucHJvdG8vcHJvdG9i",
+            "dWYvcHR5cGU7cHR5cGX4AQGiAgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2Vs",
+            "bEtub3duVHlwZXNiBnByb3RvMw=="));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.AnyReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.SourceContextReflection.Descriptor, },
           new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Google.Protobuf.WellKnownTypes.Syntax), }, new pbr::GeneratedClrTypeInfo[] {

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

@@ -232,7 +232,7 @@ public abstract class AbstractParser<MessageType extends MessageLite>
       }
       size = CodedInputStream.readRawVarint32(firstByte, input);
     } catch (IOException e) {
-      throw new InvalidProtocolBufferException(e.getMessage());
+      throw new InvalidProtocolBufferException(e);
     }
     InputStream limitedInput = new LimitedInputStream(input, size);
     return parsePartialFrom(limitedInput, extensionRegistry);

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

@@ -51,14 +51,12 @@ import java.util.List;
 import java.util.NoSuchElementException;
 
 /**
- * Immutable sequence of bytes.  Substring is supported by sharing the reference
- * to the immutable underlying bytes.  Concatenation is likewise supported
- * without copying (long strings) by building a tree of pieces in
- * {@link RopeByteString}.
- * <p>
- * Like {@link String}, the contents of a {@link ByteString} can never be
- * observed to change, not even in the presence of a data race or incorrect
- * API usage in the client code.
+ * Immutable sequence of bytes. Substring is supported by sharing the reference to the immutable
+ * underlying bytes. Concatenation is likewise supported without copying (long strings) by building
+ * a tree of pieces in {@link RopeByteString}.
+ *
+ * <p>Like {@link String}, the contents of a {@link ByteString} can never be observed to change, not
+ * even in the presence of a data race or incorrect API usage in the client code.
  *
  * @author crazybob@google.com Bob Lee
  * @author kenton@google.com Kenton Varda
@@ -565,7 +563,9 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
   // Create a balanced concatenation of the next "length" elements from the
   // iterable.
   private static ByteString balancedConcat(Iterator<ByteString> iterator, int length) {
-    assert length >= 1;
+    if (length < 1) {
+      throw new IllegalArgumentException(String.format("length (%s) must be >= 1", length));
+    }
     ByteString result;
     if (length == 1) {
       result = iterator.next();

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

@@ -2123,7 +2123,7 @@ public final class Descriptors {
           // Can't happen, because addPackage() only fails when the name
           // conflicts with a non-package, but we have not yet added any
           // non-packages at this point.
-          assert false;
+          throw new AssertionError(e);
         }
       }
     }

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

@@ -297,7 +297,7 @@ public final class DynamicMessage extends AbstractMessage {
         } catch (InvalidProtocolBufferException e) {
           throw e.setUnfinishedMessage(builder.buildPartial());
         } catch (IOException e) {
-          throw new InvalidProtocolBufferException(e.getMessage())
+          throw new InvalidProtocolBufferException(e)
               .setUnfinishedMessage(builder.buildPartial());
         }
         return builder.buildPartial();

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

@@ -32,7 +32,6 @@ package com.google.protobuf;
 
 import com.google.protobuf.Descriptors.Descriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
-
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;

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

@@ -105,9 +105,9 @@ public class ExtensionRegistryLite {
 
   /**
    * Construct a new, empty instance.
-   * 
-   * <p>
-   * This may be an {@code ExtensionRegistry} if the full (non-Lite) proto libraries are available.
+   *
+   * <p>This may be an {@code ExtensionRegistry} if the full (non-Lite) proto libraries are
+   * available.
    */
   public static ExtensionRegistryLite newInstance() {
     return ExtensionRegistryFactory.create();
@@ -121,6 +121,7 @@ public class ExtensionRegistryLite {
     return ExtensionRegistryFactory.createEmpty();
   }
 
+
   /** Returns an unmodifiable view of the registry. */
   public ExtensionRegistryLite getUnmodifiable() {
     return new ExtensionRegistryLite(this);

+ 151 - 12
java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java

@@ -39,7 +39,6 @@ import com.google.protobuf.Internal.IntList;
 import com.google.protobuf.Internal.LongList;
 import com.google.protobuf.Internal.ProtobufList;
 import com.google.protobuf.WireFormat.FieldType;
-
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.ObjectStreamException;
@@ -479,7 +478,6 @@ public abstract class GeneratedMessageLite<
         CodedInputStream input,
         ExtensionRegistryLite extensionRegistry,
         int tag) throws IOException {
-      int wireType = WireFormat.getTagWireType(tag);
       int fieldNumber = WireFormat.getTagFieldNumber(tag);
 
       // TODO(dweis): How much bytecode would be saved by not requiring the generated code to
@@ -487,6 +485,17 @@ public abstract class GeneratedMessageLite<
       GeneratedExtension<MessageType, ?> extension = extensionRegistry.findLiteExtensionByNumber(
           defaultInstance, fieldNumber);
 
+      return parseExtension(input, extensionRegistry, extension, tag, fieldNumber);
+    }
+
+    private boolean parseExtension(
+        CodedInputStream input,
+        ExtensionRegistryLite extensionRegistry,
+        GeneratedExtension<?, ?> extension,
+        int tag,
+        int fieldNumber)
+        throws IOException {
+      int wireType = WireFormat.getTagWireType(tag);
       boolean unknown = false;
       boolean packed = false;
       if (extension == null) {
@@ -508,7 +517,7 @@ public abstract class GeneratedMessageLite<
       if (unknown) {  // Unknown field or wrong wire type.  Skip.
         return parseUnknownField(tag, input);
       }
-
+      
       if (packed) {
         int length = input.readRawVarint32();
         int limit = input.pushLimit(length);
@@ -587,9 +596,147 @@ public abstract class GeneratedMessageLite<
                               extension.singularToFieldSetType(value));
         }
       }
-
       return true;
     }
+    
+    /**
+     * Parse an unknown field or an extension. For use by generated code only.
+     *
+     * <p>For use by generated code only.
+     *
+     * @return {@code true} unless the tag is an end-group tag.
+     */
+    protected <MessageType extends MessageLite> boolean parseUnknownFieldAsMessageSet(
+        MessageType defaultInstance,
+        CodedInputStream input,
+        ExtensionRegistryLite extensionRegistry,
+        int tag)
+        throws IOException {
+
+      if (tag == WireFormat.MESSAGE_SET_ITEM_TAG) {
+        mergeMessageSetExtensionFromCodedStream(defaultInstance, input, extensionRegistry);
+        return true;
+      }
+
+      // TODO(dweis): Do we really want to support non message set wire format in message sets?
+      // Full runtime does... So we do for now.
+      int wireType = WireFormat.getTagWireType(tag);
+      if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) {
+        return parseUnknownField(defaultInstance, input, extensionRegistry, tag);
+      } else {
+        // TODO(dweis): Should we throw on invalid input? Full runtime does not...
+        return input.skipField(tag);
+      }
+    }
+
+    /**
+     * Merges the message set from the input stream; requires message set wire format.
+     * 
+     * @param defaultInstance the default instance of the containing message we are parsing in
+     * @param input the stream to parse from
+     * @param extensionRegistry the registry to use when parsing
+     */
+    private <MessageType extends MessageLite> void mergeMessageSetExtensionFromCodedStream(
+        MessageType defaultInstance,
+        CodedInputStream input,
+        ExtensionRegistryLite extensionRegistry)
+        throws IOException {
+      // The wire format for MessageSet is:
+      //   message MessageSet {
+      //     repeated group Item = 1 {
+      //       required int32 typeId = 2;
+      //       required bytes message = 3;
+      //     }
+      //   }
+      // "typeId" is the extension's field number.  The extension can only be
+      // a message type, where "message" contains the encoded bytes of that
+      // message.
+      //
+      // In practice, we will probably never see a MessageSet item in which
+      // the message appears before the type ID, or where either field does not
+      // appear exactly once.  However, in theory such cases are valid, so we
+      // should be prepared to accept them.
+
+      int typeId = 0;
+      ByteString rawBytes = null; // If we encounter "message" before "typeId"
+      GeneratedExtension<?, ?> extension = null;
+
+      // Read bytes from input, if we get it's type first then parse it eagerly,
+      // otherwise we store the raw bytes in a local variable.
+      while (true) {
+        final int tag = input.readTag();
+        if (tag == 0) {
+          break;
+        }
+
+        if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) {
+          typeId = input.readUInt32();
+          if (typeId != 0) {
+            extension = extensionRegistry.findLiteExtensionByNumber(defaultInstance, typeId);
+          }
+
+        } else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) {
+          if (typeId != 0) {
+            if (extension != null) {
+              // We already know the type, so we can parse directly from the
+              // input with no copying.  Hooray!
+              eagerlyMergeMessageSetExtension(input, extension, extensionRegistry, typeId);
+              rawBytes = null;
+              continue;
+            }
+          }
+          // We haven't seen a type ID yet or we want parse message lazily.
+          rawBytes = input.readBytes();
+
+        } else { // Unknown tag. Skip it.
+          if (!input.skipField(tag)) {
+            break; // End of group
+          }
+        }
+      }
+      input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG);
+
+      // Process the raw bytes.
+      if (rawBytes != null && typeId != 0) { // Zero is not a valid type ID.
+        if (extension != null) { // We known the type
+          mergeMessageSetExtensionFromBytes(rawBytes, extensionRegistry, extension);
+        } else { // We don't know how to parse this. Ignore it.
+          if (rawBytes != null) {
+            mergeLengthDelimitedField(typeId, rawBytes);
+          }
+        }
+      }
+    }
+
+    private void eagerlyMergeMessageSetExtension(
+        CodedInputStream input,
+        GeneratedExtension<?, ?> extension,
+        ExtensionRegistryLite extensionRegistry,
+        int typeId)
+        throws IOException {
+      int fieldNumber = typeId;
+      int tag = WireFormat.makeTag(typeId, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+      parseExtension(input, extensionRegistry, extension, tag, fieldNumber);
+    }
+
+    private void mergeMessageSetExtensionFromBytes(
+        ByteString rawBytes,
+        ExtensionRegistryLite extensionRegistry,
+        GeneratedExtension<?, ?> extension)
+        throws IOException {
+      MessageLite.Builder subBuilder = null;
+      MessageLite existingValue = (MessageLite) extensions.getField(extension.descriptor);
+      if (existingValue != null) {
+        subBuilder = existingValue.toBuilder();
+      }
+      if (subBuilder == null) {
+        subBuilder = extension.getMessageDefaultInstance().newBuilderForType();
+      }
+      rawBytes.newCodedInput().readMessage(subBuilder, extensionRegistry);
+      MessageLite value = subBuilder.build();
+
+      extensions.setField(extension.descriptor, extension.singularToFieldSetType(value));
+    }
 
     private void verifyExtensionContainingType(
         final GeneratedExtension<MessageType, ?> extension) {
@@ -807,14 +954,6 @@ public abstract class GeneratedMessageLite<
       return instance.getExtension(extension, index);
     }
 
-    // This is implemented here only to work around an apparent bug in the
-    // Java compiler and/or build system.  See bug #1898463.  The mere presence
-    // of this dummy clone() implementation makes it go away.
-    @Override
-    public BuilderType clone() {
-      return super.clone();
-    }
-
     /** Set the value of an extension. */
     public final <Type> BuilderType setExtension(
         final ExtensionLite<MessageType, Type> extension,

+ 12 - 14
java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java

@@ -36,6 +36,16 @@ import com.google.protobuf.Descriptors.EnumValueDescriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import com.google.protobuf.Descriptors.FileDescriptor;
 import com.google.protobuf.Descriptors.OneofDescriptor;
+// In opensource protobuf, we have versioned this GeneratedMessageV3 class to GeneratedMessageV3V3 and
+// in the future may have GeneratedMessageV3V4 etc. This allows us to change some aspects of this
+// class without breaking binary compatibility with old generated code that still subclasses
+// the old GeneratedMessageV3 class. To allow these different GeneratedMessageV3V? classes to
+// interoperate (e.g., a GeneratedMessageV3V3 object has a message extension field whose class
+// type is GeneratedMessageV3V4), these classes still share a common parent class AbstarctMessage
+// and are using the same GeneratedMessage.GeneratedExtension class for extension definitions.
+// Since this class becomes GeneratedMessageV3V? in opensource, we have to add an import here
+// to be able to use GeneratedMessage.GeneratedExtension. The GeneratedExtension definition in
+// this file is also excluded from opensource to avoid conflict.
 import com.google.protobuf.GeneratedMessage.GeneratedExtension;
 
 import java.io.IOException;
@@ -1207,14 +1217,6 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
       return super.clear();
     }
 
-    // This is implemented here only to work around an apparent bug in the
-    // Java compiler and/or build system.  See bug #1898463.  The mere presence
-    // of this clone() implementation makes it go away.
-    @Override
-    public BuilderType clone() {
-      return super.clone();
-    }
-
     private void ensureExtensionsIsMutable() {
       if (extensions.isImmutable()) {
         extensions = extensions.clone();
@@ -1610,6 +1612,7 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
     FieldDescriptor getDescriptor();
   }
 
+
   // =================================================================
 
   /** Calls Class.getMethod and throws a RuntimeException if it fails. */
@@ -1705,11 +1708,6 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
       initialized = false;
     }
 
-    private boolean isMapFieldEnabled(FieldDescriptor field) {
-      boolean result = true;
-      return result;
-    }
-
     /**
      * Ensures the field accessors are initialized. This method is thread-safe.
      *
@@ -1733,7 +1731,7 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
           }
           if (field.isRepeated()) {
             if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
-              if (field.isMapField() && isMapFieldEnabled(field)) {
+              if (field.isMapField()) {
                 fields[i] = new MapFieldAccessor(
                     field, camelCaseNames[i], messageClass, builderClass);
               } else {

+ 2 - 23
java/core/src/main/java/com/google/protobuf/LazyFieldLite.java

@@ -284,29 +284,8 @@ public class LazyFieldLite {
       return;
     }
 
-    // At this point we have two fully parsed messages. We can't merge directly from one to the
-    // other because only generated builder code contains methods to mergeFrom another parsed
-    // message. We have to serialize one instance and then merge the bytes into the other. This may
-    // drop extensions from one of the messages if one of the values had an extension set on it
-    // directly.
-    //
-    // To mitigate this we prefer serializing a message that has an extension registry, and
-    // therefore a chance that all extensions set on it are in that registry.
-    //
-    // NOTE: The check for other.extensionRegistry not being null must come first because at this
-    // point in time if other.extensionRegistry is not null then this.extensionRegistry will not be
-    // null either.
-    if (other.extensionRegistry != null) {
-      setValue(mergeValueAndBytes(this.value, other.toByteString(), other.extensionRegistry));
-      return;
-    } else if (this.extensionRegistry != null) {
-      setValue(mergeValueAndBytes(other.value, this.toByteString(), this.extensionRegistry));
-      return;
-    } else {
-      // All extensions from the other message will be dropped because we have no registry.
-      setValue(mergeValueAndBytes(this.value, other.toByteString(), EMPTY_REGISTRY));
-      return;
-    }
+    // At this point we have two fully parsed messages.
+    setValue(this.value.toBuilder().mergeFrom(other.value).build());
   }
   
   /**

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

@@ -109,7 +109,7 @@ public final class MapEntry<K, V> extends AbstractMessage {
     } catch (InvalidProtocolBufferException e) {
       throw e.setUnfinishedMessage(this);
     } catch (IOException e) {
-      throw new InvalidProtocolBufferException(e.getMessage()).setUnfinishedMessage(this);
+      throw new InvalidProtocolBufferException(e).setUnfinishedMessage(this);
     }
   }
 

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

@@ -95,7 +95,7 @@ final class MessageLiteToString {
         // Try to reflectively get the value and toString() the field as if it were repeated. This
         // only works if the method names have not be proguarded out or renamed.
         Method listMethod = nameToNoArgMethod.get("get" + suffix);
-        if (listMethod != null) {
+        if (listMethod != null && listMethod.getReturnType().equals(List.class)) {
           printField(
               buffer,
               indent,
@@ -115,7 +115,7 @@ final class MessageLiteToString {
         // Heuristic to skip bytes based accessors for string fields.
         continue;
       }
-      
+
       String camelCase = suffix.substring(0, 1).toLowerCase() + suffix.substring(1);
 
       // Try to reflectively get the value and toString() the field as if it were optional. This

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

@@ -1022,7 +1022,7 @@ public final class UnknownFieldSet implements MessageLite {
       } catch (InvalidProtocolBufferException e) {
         throw e.setUnfinishedMessage(builder.buildPartial());
       } catch (IOException e) {
-        throw new InvalidProtocolBufferException(e.getMessage())
+        throw new InvalidProtocolBufferException(e)
             .setUnfinishedMessage(builder.buildPartial());
       }
       return builder.buildPartial();

+ 37 - 1
java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java

@@ -175,6 +175,41 @@ public final class UnknownFieldSetLite {
     }
   }
 
+  /**
+   * Serializes the set and writes it to {@code output} using {@code MessageSet} wire format.
+   *
+   * <p>For use by generated code only.
+   */
+  public void writeAsMessageSetTo(CodedOutputStream output) throws IOException {
+    for (int i = 0; i < count; i++) {
+      int fieldNumber = WireFormat.getTagFieldNumber(tags[i]);
+      output.writeRawMessageSetExtension(fieldNumber, (ByteString) objects[i]);
+    }
+  }
+  
+  /**
+   * Get the number of bytes required to encode this field, including field
+   * number, using {@code MessageSet} wire format.
+   */
+  public int getSerializedSizeAsMessageSet() {
+    int size = memoizedSerializedSize;
+    if (size != -1) {
+      return size;
+    }
+    
+    size = 0;
+    for (int i = 0; i < count; i++) {
+      int tag = tags[i];
+      int fieldNumber = WireFormat.getTagFieldNumber(tag);
+      size += CodedOutputStream.computeRawMessageSetExtensionSize(
+          fieldNumber, (ByteString) objects[i]);
+    }
+    
+    memoizedSerializedSize = size;
+    
+    return size;
+  }
+
   /**
    * Get the number of bytes required to encode this set.
    *
@@ -268,7 +303,8 @@ public final class UnknownFieldSetLite {
     }
   }
 
-  private void storeField(int tag, Object value) {
+  // Package private for unsafe experimental runtime.
+  void storeField(int tag, Object value) {
     ensureCapacity();
     
     tags[count] = tag;

+ 0 - 24
java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java

@@ -31,7 +31,6 @@
 package com.google.protobuf;
 
 import static protobuf_unittest.UnittestProto.optionalInt32Extension;
-import static protobuf_unittest.UnittestProto.optionalInt64Extension;
 
 import protobuf_unittest.UnittestProto.TestAllExtensions;
 import protobuf_unittest.UnittestProto.TestAllTypes;
@@ -219,29 +218,6 @@ public class LazyFieldLiteTest extends TestCase {
     assertEquals(messageWithExtensions, field.getValue(TestAllExtensions.getDefaultInstance()));
   }
 
-  public void testMergeMightLoseExtensions() throws Exception {
-    // Test that we don't know about the extensions when parsing.
-    TestAllExtensions message1 =
-        TestAllExtensions.newBuilder().setExtension(optionalInt32Extension, 1).build();
-    TestAllExtensions message2 =
-        TestAllExtensions.newBuilder().setExtension(optionalInt64Extension, 2L).build();
-
-    LazyFieldLite field = LazyFieldLite.fromValue(message1);
-    field.merge(LazyFieldLite.fromValue(message2));
-
-    // We lose the extensions from message 2 because we have to serialize it and then parse it
-    // again, using the empty registry this time.
-    TestAllExtensions value =
-        (TestAllExtensions) field.getValue(TestAllExtensions.getDefaultInstance());
-    assertTrue(value.hasExtension(optionalInt32Extension));
-    assertEquals(Integer.valueOf(1), value.getExtension(optionalInt32Extension));
-    assertFalse(value.hasExtension(optionalInt64Extension));
-
-    // The field is still there, it is just unknown.
-    assertTrue(value.getUnknownFields()
-        .hasField(optionalInt64Extension.getDescriptor().getNumber()));
-  }
-
 
   // Help methods.
 

+ 13 - 0
java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java

@@ -101,6 +101,19 @@ public class LazyMessageLiteTest extends TestCase {
     assertEquals(119, outer.getRepeatedInner(0).getNum());
     assertEquals(122, outer.getRepeatedInner(1).getNum());
   }
+  
+  public void testRepeatedMutability() throws Exception {
+    LazyMessageLite outer = LazyMessageLite.newBuilder()
+        .addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(119))
+        .addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(122))
+        .build();
+    
+    outer = LazyMessageLite.parseFrom(outer.toByteArray());
+    try {
+      outer.getRepeatedInnerList().set(1, null);
+      fail();
+    } catch (UnsupportedOperationException expected) {}
+  }
 
   public void testAddAll() {
     ArrayList<LazyInnerMessageLite> inners = new ArrayList<LazyInnerMessageLite>();

+ 26 - 0
java/core/src/test/java/com/google/protobuf/LiteTest.java

@@ -45,6 +45,7 @@ import com.google.protobuf.UnittestLite.TestAllTypesLite.OneofFieldCase;
 import com.google.protobuf.UnittestLite.TestAllTypesLite.OptionalGroup;
 import com.google.protobuf.UnittestLite.TestAllTypesLite.RepeatedGroup;
 import com.google.protobuf.UnittestLite.TestAllTypesLiteOrBuilder;
+import com.google.protobuf.UnittestLite.TestHugeFieldNumbersLite;
 import com.google.protobuf.UnittestLite.TestNestedExtensionLite;
 import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Bar;
 import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.BarPrime;
@@ -1424,6 +1425,12 @@ public class LiteTest extends TestCase {
     assertToStringEquals("", TestAllTypesLite.getDefaultInstance());
   }
 
+  public void testToStringScalarFieldsSuffixedWithList() throws Exception {
+    assertToStringEquals("deceptively_named_list: 7", TestAllTypesLite.newBuilder()
+        .setDeceptivelyNamedList(7)
+        .build());
+  }
+
   public void testToStringPrimitives() throws Exception {
     TestAllTypesLite proto = TestAllTypesLite.newBuilder()
         .setOptionalInt32(1)
@@ -2235,6 +2242,25 @@ public class LiteTest extends TestCase {
     assertFalse(other.equals(mine));
   }
 
+  public void testHugeFieldNumbers() throws InvalidProtocolBufferException {
+    TestHugeFieldNumbersLite message =
+        TestHugeFieldNumbersLite.newBuilder()
+            .setOptionalInt32(1)
+            .addRepeatedInt32(2)
+            .setOptionalEnum(ForeignEnumLite.FOREIGN_LITE_FOO)
+            .setOptionalString("xyz")
+            .setOptionalMessage(ForeignMessageLite.newBuilder().setC(3).build())
+            .build();
+
+    TestHugeFieldNumbersLite parsedMessage =
+        TestHugeFieldNumbersLite.parseFrom(message.toByteArray());
+    assertEquals(1, parsedMessage.getOptionalInt32());
+    assertEquals(2, parsedMessage.getRepeatedInt32(0));
+    assertEquals(ForeignEnumLite.FOREIGN_LITE_FOO, parsedMessage.getOptionalEnum());
+    assertEquals("xyz", parsedMessage.getOptionalString());
+    assertEquals(3, parsedMessage.getOptionalMessage().getC());
+  }
+
   private void assertEqualsAndHashCodeAreFalse(Object o1, Object o2) {
     assertFalse(o1.equals(o2));
     assertFalse(o1.hashCode() == o2.hashCode());

+ 0 - 1
java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java

@@ -501,7 +501,6 @@ public final class MapForProto2LiteTest extends TestCase {
     assertEquals(54321, messageWithUnknownEnums.getInt32ToInt32Field().get(2).intValue());
   }
 
-
   public void testIterationOrder() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValues(builder);

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

@@ -58,26 +58,26 @@ public class MapForProto2Test extends TestCase {
     builder.getMutableInt32ToInt32Field().put(1, 11);
     builder.getMutableInt32ToInt32Field().put(2, 22);
     builder.getMutableInt32ToInt32Field().put(3, 33);
-
+  //
     builder.getMutableInt32ToStringField().put(1, "11");
     builder.getMutableInt32ToStringField().put(2, "22");
     builder.getMutableInt32ToStringField().put(3, "33");
-
+  //
     builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("11"));
     builder.getMutableInt32ToBytesField().put(2, TestUtil.toBytes("22"));
     builder.getMutableInt32ToBytesField().put(3, TestUtil.toBytes("33"));
-
+  //
     builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.FOO);
     builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.BAR);
     builder.getMutableInt32ToEnumField().put(3, TestMap.EnumValue.BAZ);
-
+  //
     builder.getMutableInt32ToMessageField().put(
         1, MessageValue.newBuilder().setValue(11).build());
     builder.getMutableInt32ToMessageField().put(
         2, MessageValue.newBuilder().setValue(22).build());
     builder.getMutableInt32ToMessageField().put(
         3, MessageValue.newBuilder().setValue(33).build());
-
+  //
     builder.getMutableStringToInt32Field().put("1", 11);
     builder.getMutableStringToInt32Field().put("2", 22);
     builder.getMutableStringToInt32Field().put("3", 33);
@@ -120,6 +120,7 @@ public class MapForProto2Test extends TestCase {
     setMapValuesUsingAccessors(usingAccessorsBuilder);
     TestMap usingAccessors = usingAccessorsBuilder.build();
     assertMapValuesSet(usingAccessors);
+
     assertEquals(usingAccessors, usingMutableMap);
   }
 
@@ -169,25 +170,25 @@ public class MapForProto2Test extends TestCase {
     builder.getMutableInt32ToInt32Field().put(1, 111);
     builder.getMutableInt32ToInt32Field().remove(2);
     builder.getMutableInt32ToInt32Field().put(4, 44);
-
+  //
     builder.getMutableInt32ToStringField().put(1, "111");
     builder.getMutableInt32ToStringField().remove(2);
     builder.getMutableInt32ToStringField().put(4, "44");
-
+  //
     builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("111"));
     builder.getMutableInt32ToBytesField().remove(2);
     builder.getMutableInt32ToBytesField().put(4, TestUtil.toBytes("44"));
-
+  //
     builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.BAR);
     builder.getMutableInt32ToEnumField().remove(2);
     builder.getMutableInt32ToEnumField().put(4, TestMap.EnumValue.QUX);
-
+  //
     builder.getMutableInt32ToMessageField().put(
         1, MessageValue.newBuilder().setValue(111).build());
     builder.getMutableInt32ToMessageField().remove(2);
     builder.getMutableInt32ToMessageField().put(
         4, MessageValue.newBuilder().setValue(44).build());
-
+  //
     builder.getMutableStringToInt32Field().put("1", 111);
     builder.getMutableStringToInt32Field().remove("2");
     builder.getMutableStringToInt32Field().put("4", 44);
@@ -230,8 +231,9 @@ public class MapForProto2Test extends TestCase {
     setMapValuesUsingAccessors(usingAccessorsBuilder);
     TestMap usingAccessors = usingAccessorsBuilder.build();
     assertMapValuesSet(usingAccessors);
-    assertEquals(usingAccessors, usingMutableMap);
 
+    assertEquals(usingAccessors, usingMutableMap);
+    //
     usingMutableMapBuilder = usingMutableMap.toBuilder();
     updateMapValuesUsingMutableMap(usingMutableMapBuilder);
     usingMutableMap = usingMutableMapBuilder.build();
@@ -335,7 +337,7 @@ public class MapForProto2Test extends TestCase {
     assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
     builder.getMutableInt32ToInt32Field().put(2, 3);
     assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field());
-
+ //
     Map<Integer, TestMap.EnumValue> enumMap = builder.getMutableInt32ToEnumField();
     enumMap.put(1, TestMap.EnumValue.BAR);
     assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumField());
@@ -350,7 +352,7 @@ public class MapForProto2Test extends TestCase {
     assertEquals(
         newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO),
         builder.getInt32ToEnumField());
-
+  //
     Map<Integer, String> stringMap = builder.getMutableInt32ToStringField();
     stringMap.put(1, "1");
     assertEquals(newMap(1, "1"), builder.build().getInt32ToStringField());
@@ -365,7 +367,7 @@ public class MapForProto2Test extends TestCase {
     assertEquals(
         newMap(1, "1", 2, "2"),
         builder.getInt32ToStringField());
-
+  //
     Map<Integer, TestMap.MessageValue> messageMap = builder.getMutableInt32ToMessageField();
     messageMap.put(1, TestMap.MessageValue.getDefaultInstance());
     assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
@@ -384,7 +386,7 @@ public class MapForProto2Test extends TestCase {
             2, TestMap.MessageValue.getDefaultInstance()),
         builder.getInt32ToMessageField());
   }
-
+  //
   public void testMutableMapLifecycle_collections() {
     TestMap.Builder builder = TestMap.newBuilder();
     Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
@@ -431,18 +433,19 @@ public class MapForProto2Test extends TestCase {
     assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
   }
 
+
   public void testGettersAndSetters() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     TestMap message = builder.build();
     assertMapValuesCleared(message);
 
     builder = message.toBuilder();
-    setMapValuesUsingMutableMap(builder);
+    setMapValuesUsingAccessors(builder);
     message = builder.build();
     assertMapValuesSet(message);
 
     builder = message.toBuilder();
-    updateMapValuesUsingMutableMap(builder);
+    updateMapValuesUsingAccessors(builder);
     message = builder.build();
     assertMapValuesUpdated(message);
 
@@ -455,7 +458,7 @@ public class MapForProto2Test extends TestCase {
 
   public void testPutAll() throws Exception {
     TestMap.Builder sourceBuilder = TestMap.newBuilder();
-    setMapValuesUsingMutableMap(sourceBuilder);
+    setMapValuesUsingAccessors(sourceBuilder);
     TestMap source = sourceBuilder.build();
     assertMapValuesSet(source);
 
@@ -507,14 +510,14 @@ public class MapForProto2Test extends TestCase {
 
   public void testSerializeAndParse() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValuesUsingMutableMap(builder);
+    setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
     assertEquals(message.getSerializedSize(), message.toByteString().size());
     message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesSet(message);
 
     builder = message.toBuilder();
-    updateMapValuesUsingMutableMap(builder);
+    updateMapValuesUsingAccessors(builder);
     message = builder.build();
     assertEquals(message.getSerializedSize(), message.toByteString().size());
     message = TestMap.parser().parseFrom(message.toByteString());
@@ -579,7 +582,7 @@ public class MapForProto2Test extends TestCase {
 
   public void testMergeFrom() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValuesUsingMutableMap(builder);
+    setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
 
     TestMap.Builder other = TestMap.newBuilder();
@@ -594,22 +597,22 @@ public class MapForProto2Test extends TestCase {
     // We can't control the order of elements in a HashMap. The best we can do
     // here is to add elements in different order.
     TestMap.Builder b1 = TestMap.newBuilder();
-    b1.getMutableInt32ToInt32Field().put(1, 2);
-    b1.getMutableInt32ToInt32Field().put(3, 4);
-    b1.getMutableInt32ToInt32Field().put(5, 6);
+    b1.putInt32ToInt32Field(1, 2);
+    b1.putInt32ToInt32Field(3, 4);
+    b1.putInt32ToInt32Field(5, 6);
     TestMap m1 = b1.build();
 
     TestMap.Builder b2 = TestMap.newBuilder();
-    b2.getMutableInt32ToInt32Field().put(5, 6);
-    b2.getMutableInt32ToInt32Field().put(1, 2);
-    b2.getMutableInt32ToInt32Field().put(3, 4);
+    b2.putInt32ToInt32Field(5, 6);
+    b2.putInt32ToInt32Field(1, 2);
+    b2.putInt32ToInt32Field(3, 4);
     TestMap m2 = b2.build();
 
     assertEquals(m1, m2);
     assertEquals(m1.hashCode(), m2.hashCode());
 
     // Make sure we did compare map fields.
-    b2.getMutableInt32ToInt32Field().put(1, 0);
+    b2.putInt32ToInt32Field(1, 0);
     m2 = b2.build();
     assertFalse(m1.equals(m2));
     // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
@@ -684,13 +687,11 @@ public class MapForProto2Test extends TestCase {
 
   public void testReflectionApi() throws Exception {
     // In reflection API, map fields are just repeated message fields.
-    TestMap.Builder builder = TestMap.newBuilder();
-    builder.getMutableInt32ToInt32Field().put(1, 2);
-    builder.getMutableInt32ToInt32Field().put(3, 4);
-    builder.getMutableInt32ToMessageField().put(
-        11, MessageValue.newBuilder().setValue(22).build());
-    builder.getMutableInt32ToMessageField().put(
-        33, MessageValue.newBuilder().setValue(44).build());
+    TestMap.Builder builder = TestMap.newBuilder()
+        .putInt32ToInt32Field(1, 2)
+        .putInt32ToInt32Field(3, 4)
+        .putInt32ToMessageField(11, MessageValue.newBuilder().setValue(22).build())
+        .putInt32ToMessageField(33, MessageValue.newBuilder().setValue(44).build());
     TestMap message = builder.build();
 
     // Test getField(), getRepeatedFieldCount(), getRepeatedField().
@@ -760,7 +761,7 @@ public class MapForProto2Test extends TestCase {
 
   public void testTextFormat() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValuesUsingMutableMap(builder);
+    setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
 
     String textData = TextFormat.printToString(message);
@@ -774,7 +775,7 @@ public class MapForProto2Test extends TestCase {
 
   public void testDynamicMessage() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValuesUsingMutableMap(builder);
+    setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
 
     Message dynamicDefaultInstance =
@@ -819,10 +820,9 @@ public class MapForProto2Test extends TestCase {
   }
 
   public void testUnknownEnumValues() throws Exception {
-    TestUnknownEnumValue.Builder builder =
-        TestUnknownEnumValue.newBuilder();
-    builder.getMutableInt32ToInt32Field().put(1, 1);
-    builder.getMutableInt32ToInt32Field().put(2, 54321);
+    TestUnknownEnumValue.Builder builder = TestUnknownEnumValue.newBuilder()
+        .putInt32ToInt32Field(1, 1)
+        .putInt32ToInt32Field(2, 54321);
     ByteString data = builder.build().toByteString();
 
     TestMap message = TestMap.parseFrom(data);
@@ -841,26 +841,21 @@ public class MapForProto2Test extends TestCase {
     assertEquals(54321, messageWithUnknownEnums.getInt32ToInt32Field().get(2).intValue());
   }
 
-
   public void testRequiredMessage() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    builder.getMutableRequiredMessageMap().put(0,
-        MessageWithRequiredFields.newBuilder().buildPartial());
+    builder.putRequiredMessageMap(0, MessageWithRequiredFields.newBuilder().buildPartial());
     TestMap message = builder.buildPartial();
     assertFalse(message.isInitialized());
 
-    builder.getMutableRequiredMessageMap().put(0,
-        MessageWithRequiredFields.newBuilder().setValue(1).build());
+    builder.putRequiredMessageMap(0, MessageWithRequiredFields.newBuilder().setValue(1).build());
     message = builder.build();
     assertTrue(message.isInitialized());
   }
 
   public void testRecursiveMap() throws Exception {
     TestRecursiveMap.Builder builder = TestRecursiveMap.newBuilder();
-    builder.getMutableRecursiveMapField().put(
-        1, TestRecursiveMap.newBuilder().setValue(2).build());
-    builder.getMutableRecursiveMapField().put(
-        3, TestRecursiveMap.newBuilder().setValue(4).build());
+    builder.putRecursiveMapField(1, TestRecursiveMap.newBuilder().setValue(2).build());
+    builder.putRecursiveMapField(3, TestRecursiveMap.newBuilder().setValue(4).build());
     ByteString data = builder.build().toByteString();
 
     TestRecursiveMap message = TestRecursiveMap.parseFrom(data);
@@ -870,7 +865,7 @@ public class MapForProto2Test extends TestCase {
 
   public void testIterationOrder() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValuesUsingMutableMap(builder);
+    setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
 
     assertEquals(Arrays.asList("1", "2", "3"),
@@ -879,7 +874,7 @@ public class MapForProto2Test extends TestCase {
 
   public void testContains() {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValuesUsingMutableMap(builder);
+    setMapValuesUsingAccessors(builder);
     assertMapContainsSetValues(builder);
     assertMapContainsSetValues(builder.build());
   }
@@ -920,7 +915,7 @@ public class MapForProto2Test extends TestCase {
     TestMap.Builder builder = TestMap.newBuilder();
     assertMapCounts(0, builder);
 
-    setMapValuesUsingMutableMap(builder);
+    setMapValuesUsingAccessors(builder);
     assertMapCounts(3, builder);
 
     TestMap message = builder.build();
@@ -1091,7 +1086,7 @@ public class MapForProto2Test extends TestCase {
 
   public void testRemove() {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValuesUsingMutableMap(builder);
+    setMapValuesUsingAccessors(builder);
     assertEquals(11, builder.getInt32ToInt32FieldOrThrow(1));
     for (int times = 0; times < 2; times++) {
       builder.removeInt32ToInt32Field(1);
@@ -1137,7 +1132,7 @@ public class MapForProto2Test extends TestCase {
 
     map_test.Message1.Builder builder =
         map_test.Message1.newBuilder();
-    builder.getMutableMapField().put("key", true);
+    builder.putMapField("key", true);
     map_test.Message1 message = builder.build();
     Message mapEntry = (Message) message.getRepeatedField(
         message.getDescriptorForType().findFieldByName("map_field"), 0);

+ 82 - 75
java/core/src/test/java/com/google/protobuf/MapTest.java

@@ -60,26 +60,26 @@ public class MapTest extends TestCase {
     builder.getMutableInt32ToInt32Field().put(1, 11);
     builder.getMutableInt32ToInt32Field().put(2, 22);
     builder.getMutableInt32ToInt32Field().put(3, 33);
-
+  //
     builder.getMutableInt32ToStringField().put(1, "11");
     builder.getMutableInt32ToStringField().put(2, "22");
     builder.getMutableInt32ToStringField().put(3, "33");
-
+  //
     builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("11"));
     builder.getMutableInt32ToBytesField().put(2, TestUtil.toBytes("22"));
     builder.getMutableInt32ToBytesField().put(3, TestUtil.toBytes("33"));
-
+  //
     builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.FOO);
     builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.BAR);
     builder.getMutableInt32ToEnumField().put(3, TestMap.EnumValue.BAZ);
-
+  //
     builder.getMutableInt32ToMessageField().put(
         1, MessageValue.newBuilder().setValue(11).build());
     builder.getMutableInt32ToMessageField().put(
         2, MessageValue.newBuilder().setValue(22).build());
     builder.getMutableInt32ToMessageField().put(
         3, MessageValue.newBuilder().setValue(33).build());
-
+  //
     builder.getMutableStringToInt32Field().put("1", 11);
     builder.getMutableStringToInt32Field().put("2", 22);
     builder.getMutableStringToInt32Field().put("3", 33);
@@ -122,6 +122,7 @@ public class MapTest extends TestCase {
     setMapValuesUsingAccessors(usingAccessorsBuilder);
     TestMap usingAccessors = usingAccessorsBuilder.build();
     assertMapValuesSet(usingAccessors);
+
     assertEquals(usingAccessors, usingMutableMap);
   }
 
@@ -171,25 +172,25 @@ public class MapTest extends TestCase {
     builder.getMutableInt32ToInt32Field().put(1, 111);
     builder.getMutableInt32ToInt32Field().remove(2);
     builder.getMutableInt32ToInt32Field().put(4, 44);
-
+  //
     builder.getMutableInt32ToStringField().put(1, "111");
     builder.getMutableInt32ToStringField().remove(2);
     builder.getMutableInt32ToStringField().put(4, "44");
-
+  //
     builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("111"));
     builder.getMutableInt32ToBytesField().remove(2);
     builder.getMutableInt32ToBytesField().put(4, TestUtil.toBytes("44"));
-
+  //
     builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.BAR);
     builder.getMutableInt32ToEnumField().remove(2);
     builder.getMutableInt32ToEnumField().put(4, TestMap.EnumValue.QUX);
-
+  //
     builder.getMutableInt32ToMessageField().put(
         1, MessageValue.newBuilder().setValue(111).build());
     builder.getMutableInt32ToMessageField().remove(2);
     builder.getMutableInt32ToMessageField().put(
         4, MessageValue.newBuilder().setValue(44).build());
-
+  //
     builder.getMutableStringToInt32Field().put("1", 111);
     builder.getMutableStringToInt32Field().remove("2");
     builder.getMutableStringToInt32Field().put("4", 44);
@@ -232,8 +233,9 @@ public class MapTest extends TestCase {
     setMapValuesUsingAccessors(usingAccessorsBuilder);
     TestMap usingAccessors = usingAccessorsBuilder.build();
     assertMapValuesSet(usingAccessors);
-    assertEquals(usingAccessors, usingMutableMap);
 
+    assertEquals(usingAccessors, usingMutableMap);
+    //
     usingMutableMapBuilder = usingMutableMap.toBuilder();
     updateMapValuesUsingMutableMap(usingMutableMapBuilder);
     usingMutableMap = usingMutableMapBuilder.build();
@@ -337,7 +339,7 @@ public class MapTest extends TestCase {
     assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
     builder.getMutableInt32ToInt32Field().put(2, 3);
     assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field());
-
+  //
     Map<Integer, TestMap.EnumValue> enumMap = builder.getMutableInt32ToEnumField();
     enumMap.put(1, TestMap.EnumValue.BAR);
     assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumField());
@@ -352,7 +354,7 @@ public class MapTest extends TestCase {
     assertEquals(
         newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO),
         builder.getInt32ToEnumField());
-
+  //
     Map<Integer, String> stringMap = builder.getMutableInt32ToStringField();
     stringMap.put(1, "1");
     assertEquals(newMap(1, "1"), builder.build().getInt32ToStringField());
@@ -363,11 +365,11 @@ public class MapTest extends TestCase {
       // expected
     }
     assertEquals(newMap(1, "1"), builder.getInt32ToStringField());
-    builder.getMutableInt32ToStringField().put(2, "2");
+    builder.putInt32ToStringField(2, "2");
     assertEquals(
         newMap(1, "1", 2, "2"),
         builder.getInt32ToStringField());
-
+  //
     Map<Integer, TestMap.MessageValue> messageMap = builder.getMutableInt32ToMessageField();
     messageMap.put(1, TestMap.MessageValue.getDefaultInstance());
     assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
@@ -380,13 +382,13 @@ public class MapTest extends TestCase {
     }
     assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
         builder.getInt32ToMessageField());
-    builder.getMutableInt32ToMessageField().put(2, TestMap.MessageValue.getDefaultInstance());
+    builder.putInt32ToMessageField(2, TestMap.MessageValue.getDefaultInstance());
     assertEquals(
         newMap(1, TestMap.MessageValue.getDefaultInstance(),
             2, TestMap.MessageValue.getDefaultInstance()),
         builder.getInt32ToMessageField());
   }
-
+  //
   public void testMutableMapLifecycle_collections() {
     TestMap.Builder builder = TestMap.newBuilder();
     Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
@@ -433,18 +435,19 @@ public class MapTest extends TestCase {
     assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
   }
 
+
   public void testGettersAndSetters() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     TestMap message = builder.build();
     assertMapValuesCleared(message);
 
     builder = message.toBuilder();
-    setMapValuesUsingMutableMap(builder);
+    setMapValuesUsingAccessors(builder);
     message = builder.build();
     assertMapValuesSet(message);
 
     builder = message.toBuilder();
-    updateMapValuesUsingMutableMap(builder);
+    updateMapValuesUsingAccessors(builder);
     message = builder.build();
     assertMapValuesUpdated(message);
 
@@ -457,7 +460,7 @@ public class MapTest extends TestCase {
 
   public void testPutAll() throws Exception {
     TestMap.Builder sourceBuilder = TestMap.newBuilder();
-    setMapValuesUsingMutableMap(sourceBuilder);
+    setMapValuesUsingAccessors(sourceBuilder);
     TestMap source = sourceBuilder.build();
     assertMapValuesSet(source);
 
@@ -467,15 +470,16 @@ public class MapTest extends TestCase {
   }
 
   public void testPutAllForUnknownEnumValues() throws Exception {
-    TestMap.Builder sourceBuilder = TestMap.newBuilder();
-    sourceBuilder.getMutableInt32ToEnumFieldValue().put(0, 0);
-    sourceBuilder.getMutableInt32ToEnumFieldValue().put(1, 1);
-    sourceBuilder.getMutableInt32ToEnumFieldValue().put(2, 1000);  // unknown value.
-    TestMap source = sourceBuilder.build();
+    TestMap source = TestMap.newBuilder()
+        .putAllInt32ToEnumFieldValue(newMap(
+            0, 0,
+            1, 1,
+            2, 1000)) // unknown value.
+        .build();
 
-    TestMap.Builder destinationBuilder = TestMap.newBuilder();
-    destinationBuilder.putAllInt32ToEnumFieldValue(source.getInt32ToEnumFieldValue());
-    TestMap destination = destinationBuilder.build();
+    TestMap destination = TestMap.newBuilder()
+        .putAllInt32ToEnumFieldValue(source.getInt32ToEnumFieldValue())
+        .build();
 
     assertEquals(0, destination.getInt32ToEnumFieldValue().get(0).intValue());
     assertEquals(1, destination.getInt32ToEnumFieldValue().get(1).intValue());
@@ -542,14 +546,14 @@ public class MapTest extends TestCase {
 
   public void testSerializeAndParse() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValuesUsingMutableMap(builder);
+    setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
     assertEquals(message.getSerializedSize(), message.toByteString().size());
     message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesSet(message);
 
     builder = message.toBuilder();
-    updateMapValuesUsingMutableMap(builder);
+    updateMapValuesUsingAccessors(builder);
     message = builder.build();
     assertEquals(message.getSerializedSize(), message.toByteString().size());
     message = TestMap.parser().parseFrom(message.toByteString());
@@ -614,7 +618,7 @@ public class MapTest extends TestCase {
 
   public void testMergeFrom() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValuesUsingMutableMap(builder);
+    setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
 
     TestMap.Builder other = TestMap.newBuilder();
@@ -628,23 +632,23 @@ public class MapTest extends TestCase {
 
     // We can't control the order of elements in a HashMap. The best we can do
     // here is to add elements in different order.
-    TestMap.Builder b1 = TestMap.newBuilder();
-    b1.getMutableInt32ToInt32Field().put(1, 2);
-    b1.getMutableInt32ToInt32Field().put(3, 4);
-    b1.getMutableInt32ToInt32Field().put(5, 6);
+    TestMap.Builder b1 = TestMap.newBuilder()
+        .putInt32ToInt32Field(1, 2)
+        .putInt32ToInt32Field(3, 4)
+        .putInt32ToInt32Field(5, 6);
     TestMap m1 = b1.build();
 
-    TestMap.Builder b2 = TestMap.newBuilder();
-    b2.getMutableInt32ToInt32Field().put(5, 6);
-    b2.getMutableInt32ToInt32Field().put(1, 2);
-    b2.getMutableInt32ToInt32Field().put(3, 4);
+    TestMap.Builder b2 = TestMap.newBuilder()
+        .putInt32ToInt32Field(5, 6)
+        .putInt32ToInt32Field(1, 2)
+        .putInt32ToInt32Field(3, 4);
     TestMap m2 = b2.build();
 
     assertEquals(m1, m2);
     assertEquals(m1.hashCode(), m2.hashCode());
 
     // Make sure we did compare map fields.
-    b2.getMutableInt32ToInt32Field().put(1, 0);
+    b2.putInt32ToInt32Field(1, 0);
     m2 = b2.build();
     assertFalse(m1.equals(m2));
     // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
@@ -652,7 +656,7 @@ public class MapTest extends TestCase {
 
     // Regression test for b/18549190: if a map is a subset of the other map,
     // equals() should return false.
-    b2.getMutableInt32ToInt32Field().remove(1);
+    b2.removeInt32ToInt32Field(1);
     m2 = b2.build();
     assertFalse(m1.equals(m2));
     assertFalse(m2.equals(m1));
@@ -661,20 +665,19 @@ public class MapTest extends TestCase {
   public void testNestedBuilderOnChangeEventPropagation() {
     TestOnChangeEventPropagation.Builder parent =
         TestOnChangeEventPropagation.newBuilder();
-    parent.getOptionalMessageBuilder().getMutableInt32ToInt32Field().put(1, 2);
+    parent.getOptionalMessageBuilder().putInt32ToInt32Field(1, 2);
     TestOnChangeEventPropagation message = parent.build();
     assertEquals(2, message.getOptionalMessage().getInt32ToInt32Field().get(1).intValue());
 
     // Make a change using nested builder.
-    parent.getOptionalMessageBuilder().getMutableInt32ToInt32Field().put(1, 3);
+    parent.getOptionalMessageBuilder().putInt32ToInt32Field(1, 3);
 
     // Should be able to observe the change.
     message = parent.build();
     assertEquals(3, message.getOptionalMessage().getInt32ToInt32Field().get(1).intValue());
 
     // Make another change using mergeFrom()
-    TestMap.Builder other = TestMap.newBuilder();
-    other.getMutableInt32ToInt32Field().put(1, 4);
+    TestMap.Builder other = TestMap.newBuilder().putInt32ToInt32Field(1, 4);
     parent.getOptionalMessageBuilder().mergeFrom(other.build());
 
     // Should be able to observe the change.
@@ -697,8 +700,7 @@ public class MapTest extends TestCase {
     TestMap.Builder testMapBuilder = parentBuilder.getOptionalMessageBuilder();
 
     // Create a map entry message.
-    TestMap.Builder entryBuilder = TestMap.newBuilder();
-    entryBuilder.getMutableInt32ToInt32Field().put(1, 1);
+    TestMap.Builder entryBuilder = TestMap.newBuilder().putInt32ToInt32Field(1, 1);
 
     // Put the entry into the nested builder.
     testMapBuilder.addRepeatedField(
@@ -709,7 +711,7 @@ public class MapTest extends TestCase {
     assertEquals(1, message.getOptionalMessage().getInt32ToInt32Field().size());
 
     // Change the entry value.
-    entryBuilder.getMutableInt32ToInt32Field().put(1, 4);
+    entryBuilder.putInt32ToInt32Field(1, 4);
     testMapBuilder = parentBuilder.getOptionalMessageBuilder();
     testMapBuilder.setRepeatedField(
         intMapField, 0, entryBuilder.getRepeatedField(intMapField, 0));
@@ -796,13 +798,11 @@ public class MapTest extends TestCase {
 
   public void testReflectionApi() throws Exception {
     // In reflection API, map fields are just repeated message fields.
-    TestMap.Builder builder = TestMap.newBuilder();
-    builder.getMutableInt32ToInt32Field().put(1, 2);
-    builder.getMutableInt32ToInt32Field().put(3, 4);
-    builder.getMutableInt32ToMessageField().put(
-        11, MessageValue.newBuilder().setValue(22).build());
-    builder.getMutableInt32ToMessageField().put(
-        33, MessageValue.newBuilder().setValue(44).build());
+    TestMap.Builder builder = TestMap.newBuilder()
+        .putInt32ToInt32Field(1, 2)
+        .putInt32ToInt32Field(3, 4)
+        .putInt32ToMessageField(11, MessageValue.newBuilder().setValue(22).build())
+        .putInt32ToMessageField(33, MessageValue.newBuilder().setValue(44).build());
     TestMap message = builder.build();
 
     // Test getField(), getRepeatedFieldCount(), getRepeatedField().
@@ -872,7 +872,7 @@ public class MapTest extends TestCase {
 
   public void testTextFormat() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValuesUsingMutableMap(builder);
+    setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
 
     String textData = TextFormat.printToString(message);
@@ -886,7 +886,7 @@ public class MapTest extends TestCase {
 
   public void testDynamicMessage() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValuesUsingMutableMap(builder);
+    setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
 
     Message dynamicDefaultInstance =
@@ -931,10 +931,11 @@ public class MapTest extends TestCase {
   }
 
   public void testUnknownEnumValues() throws Exception {
-    TestMap.Builder builder = TestMap.newBuilder();
-    builder.getMutableInt32ToEnumFieldValue().put(0, 0);
-    builder.getMutableInt32ToEnumFieldValue().put(1, 1);
-    builder.getMutableInt32ToEnumFieldValue().put(2, 1000);  // unknown value.
+    TestMap.Builder builder = TestMap.newBuilder()
+        .putAllInt32ToEnumFieldValue(newMap(
+            0, 0,
+            1, 1,
+            2, 1000));  // unknown value.
     TestMap message = builder.build();
 
     assertEquals(TestMap.EnumValue.FOO,
@@ -957,7 +958,7 @@ public class MapTest extends TestCase {
     assertEquals(1000, builder.getInt32ToEnumFieldValue().get(2).intValue());
 
     // hashCode()/equals() should take unknown enum values into account.
-    builder.getMutableInt32ToEnumFieldValue().put(2, 1001);
+    builder.putAllInt32ToEnumFieldValue(newMap(2, 1001));
     TestMap message2 = builder.build();
     assertFalse(message.hashCode() == message2.hashCode());
     assertFalse(message.equals(message2));
@@ -971,15 +972,13 @@ public class MapTest extends TestCase {
     EnumDescriptor enumDescriptor = TestMap.EnumValue.getDescriptor();
     FieldDescriptor field = descriptor.findFieldByName("int32_to_enum_field");
 
-    Map<Integer, Integer> data = new HashMap<Integer, Integer>();
-    data.put(0, 0);
-    data.put(1, 1);
-    data.put(2, 1000);  // unknown value.
+    Map<Integer, Integer> data = newMap(
+        0, 0,
+        1, 1,
+        2, 1000); // unknown value
 
-    TestMap.Builder builder = TestMap.newBuilder();
-    for (Map.Entry<Integer, Integer> entry : data.entrySet()) {
-      builder.getMutableInt32ToEnumFieldValue().put(entry.getKey(), entry.getValue());
-    }
+    TestMap.Builder builder = TestMap.newBuilder()
+        .putAllInt32ToEnumFieldValue(data);
 
     // Try to read unknown enum values using reflection API.
     for (int i = 0; i < builder.getRepeatedFieldCount(field); i++) {
@@ -1003,7 +1002,7 @@ public class MapTest extends TestCase {
 
   public void testIterationOrder() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValuesUsingMutableMap(builder);
+    setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
 
     assertEquals(Arrays.asList("1", "2", "3"),
@@ -1012,7 +1011,7 @@ public class MapTest extends TestCase {
 
   public void testGetMap() {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValuesUsingMutableMap(builder);
+    setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
     assertEquals(
         message.getStringToInt32Field(),
@@ -1033,7 +1032,7 @@ public class MapTest extends TestCase {
 
   public void testContains() {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValuesUsingMutableMap(builder);
+    setMapValuesUsingAccessors(builder);
     assertMapContainsSetValues(builder);
     assertMapContainsSetValues(builder.build());
   }
@@ -1074,7 +1073,7 @@ public class MapTest extends TestCase {
     TestMap.Builder builder = TestMap.newBuilder();
     assertMapCounts(0, builder);
 
-    setMapValuesUsingMutableMap(builder);
+    setMapValuesUsingAccessors(builder);
     assertMapCounts(3, builder);
 
     TestMap message = builder.build();
@@ -1269,7 +1268,7 @@ public class MapTest extends TestCase {
 
   public void testRemove() {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValuesUsingMutableMap(builder);
+    setMapValuesUsingAccessors(builder);
     assertEquals(11, builder.getInt32ToInt32FieldOrThrow(1));
     for (int times = 0; times < 2; times++) {
       builder.removeInt32ToInt32Field(1);
@@ -1485,4 +1484,12 @@ public class MapTest extends TestCase {
     map.put(key2, value2);
     return map;
   }
+
+  private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2, K key3, V value3) {
+    Map<K, V> map = new HashMap<K, V>();
+    map.put(key1, value1);
+    map.put(key2, value2);
+    map.put(key3, value3);
+    return map;
+  }
 }

+ 40 - 0
java/core/src/test/java/com/google/protobuf/ParserTest.java

@@ -46,6 +46,7 @@ import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.InterruptedIOException;
 import junit.framework.TestCase;
 
 /**
@@ -372,4 +373,43 @@ public class ParserTest extends TestCase {
     assertEquals(3, parsingMerge.getExtensionCount(
         TestParsingMergeLite.repeatedExt));
   }
+
+  public void testParseDelimitedFrom_firstByteInterrupted_preservesCause() {
+    try {
+      TestUtil.getAllSet().parseDelimitedFrom(
+          new InputStream() {
+            @Override
+            public int read() throws IOException {
+              throw new InterruptedIOException();
+            }
+          });
+      fail("Expected InterruptedIOException");
+    } catch (Exception e) {
+      assertEquals(InterruptedIOException.class, e.getClass());
+    }
+  }
+
+  public void testParseDelimitedFrom_secondByteInterrupted_preservesCause() {
+    try {
+      TestUtil.getAllSet().parseDelimitedFrom(
+          new InputStream() {
+            private int i;
+
+            @Override
+            public int read() throws IOException {
+              switch (i++) {
+                case 0:
+                  return 1;
+                case 1:
+                  throw new InterruptedIOException();
+                default:
+                  throw new AssertionError();
+              }
+            }
+          });
+      fail("Expected InterruptedIOException");
+    } catch (Exception e) {
+      assertEquals(InterruptedIOException.class, e.getClass());
+    }
+  }
 }

+ 2 - 6
java/util/src/main/java/com/google/protobuf/util/Durations.java

@@ -42,7 +42,6 @@ import static com.google.protobuf.util.Timestamps.NANOS_PER_MICROSECOND;
 import static com.google.protobuf.util.Timestamps.NANOS_PER_MILLISECOND;
 import static com.google.protobuf.util.Timestamps.NANOS_PER_SECOND;
 
-import com.google.common.collect.ComparisonChain;
 import com.google.protobuf.Duration;
 import java.text.ParseException;
 import java.util.Comparator;
@@ -71,11 +70,8 @@ public final class Durations {
         public int compare(Duration d1, Duration d2) {
           checkValid(d1);
           checkValid(d2);
-
-          return ComparisonChain.start()
-              .compare(d1.getSeconds(), d2.getSeconds())
-              .compare(d1.getNanos(), d2.getNanos())
-              .result();
+          int secDiff = Long.compare(d1.getSeconds(), d2.getSeconds());
+          return (secDiff != 0) ? secDiff : Integer.compare(d1.getNanos(), d2.getNanos());
         }
       };
 

+ 6 - 1
java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java

@@ -217,7 +217,12 @@ final class FieldMaskTree {
       Message source,
       Message.Builder destination,
       FieldMaskUtil.MergeOptions options) {
-    assert source.getDescriptorForType() == destination.getDescriptorForType();
+    if (source.getDescriptorForType() != destination.getDescriptorForType()) {
+      throw new IllegalArgumentException(
+          String.format(
+              "source (%s) and destination (%s) descriptor must be equal",
+              source.getDescriptorForType(), destination.getDescriptorForType()));
+    }
 
     Descriptor descriptor = source.getDescriptorForType();
     for (Entry<String, Node> entry : node.children.entrySet()) {

+ 28 - 11
java/util/src/main/java/com/google/protobuf/util/JsonFormat.java

@@ -67,7 +67,6 @@ import com.google.protobuf.Timestamp;
 import com.google.protobuf.UInt32Value;
 import com.google.protobuf.UInt64Value;
 import com.google.protobuf.Value;
-
 import java.io.IOException;
 import java.io.Reader;
 import java.io.StringReader;
@@ -224,7 +223,7 @@ public class JsonFormat {
    * Creates a {@link Parser} with default configuration.
    */
   public static Parser parser() {
-    return new Parser(TypeRegistry.getEmptyTypeRegistry(), false);
+    return new Parser(TypeRegistry.getEmptyTypeRegistry(), false, Parser.DEFAULT_RECURSION_LIMIT);
   }
 
   /**
@@ -233,10 +232,15 @@ public class JsonFormat {
   public static class Parser {
     private final TypeRegistry registry;
     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) {
+    private Parser(TypeRegistry registry, boolean ignoreUnknownFields, int recursionLimit) {
       this.registry = registry;
       this.ignoringUnknownFields = ignoreUnknownFields;
+      this.recursionLimit = recursionLimit;
     }
 
     /**
@@ -249,16 +253,15 @@ public class JsonFormat {
       if (this.registry != TypeRegistry.getEmptyTypeRegistry()) {
         throw new IllegalArgumentException("Only one registry is allowed.");
       }
-      return new Parser(registry, this.ignoringUnknownFields);
+      return new Parser(registry, ignoringUnknownFields, recursionLimit);
     }
 
     /**
-     * Creates a new {@link Parser} configured to not throw an exception
-     * when an unknown field is encountered. The new Parser clones all other
-     * configurations from this Parser.
+     * Creates a new {@link Parser} configured to not throw an exception when an unknown field is
+     * encountered. The new Parser clones all other configurations from this Parser.
      */
     public Parser ignoringUnknownFields() {
-      return new Parser(this.registry, true);
+      return new Parser(this.registry, true, recursionLimit);
     }
 
     /**
@@ -270,7 +273,7 @@ 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).merge(json, builder);
+      new ParserImpl(registry, ignoringUnknownFields, recursionLimit).merge(json, builder);
     }
 
     /**
@@ -283,7 +286,12 @@ 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).merge(json, builder);
+      new ParserImpl(registry, ignoringUnknownFields, recursionLimit).merge(json, builder);
+    }
+
+    // For testing only.
+    Parser usingRecursionLimit(int recursionLimit) {
+      return new Parser(registry, ignoringUnknownFields, recursionLimit);
     }
   }
 
@@ -1040,11 +1048,15 @@ public class JsonFormat {
     private final TypeRegistry registry;
     private final JsonParser jsonParser;
     private final boolean ignoringUnknownFields;
+    private final int recursionLimit;
+    private int currentDepth;
 
-    ParserImpl(TypeRegistry registry, boolean ignoreUnknownFields) {
+    ParserImpl(TypeRegistry registry, boolean ignoreUnknownFields, int recursionLimit) {
       this.registry = registry;
       this.ignoringUnknownFields = ignoreUnknownFields;
       this.jsonParser = new JsonParser();
+      this.recursionLimit = recursionLimit;
+      this.currentDepth = 0;
     }
 
     void merge(Reader json, Message.Builder builder) throws IOException {
@@ -1715,8 +1727,13 @@ public class JsonFormat {
 
         case MESSAGE:
         case GROUP:
+          if (currentDepth >= recursionLimit) {
+            throw new InvalidProtocolBufferException("Hit recursion limit.");
+          }
+          ++currentDepth;
           Message.Builder subBuilder = builder.newBuilderForField(field);
           merge(json, subBuilder);
+          --currentDepth;
           return subBuilder.build();
 
         default:

+ 2 - 6
java/util/src/main/java/com/google/protobuf/util/Timestamps.java

@@ -37,7 +37,6 @@ import static com.google.common.math.LongMath.checkedAdd;
 import static com.google.common.math.LongMath.checkedMultiply;
 import static com.google.common.math.LongMath.checkedSubtract;
 
-import com.google.common.collect.ComparisonChain;
 import com.google.protobuf.Duration;
 import com.google.protobuf.Timestamp;
 import java.text.ParseException;
@@ -101,11 +100,8 @@ public final class Timestamps {
         public int compare(Timestamp t1, Timestamp t2) {
           checkValid(t1);
           checkValid(t2);
-
-          return ComparisonChain.start()
-              .compare(t1.getSeconds(), t2.getSeconds())
-              .compare(t1.getNanos(), t2.getNanos())
-              .result();
+          int secDiff = Long.compare(t1.getSeconds(), t2.getSeconds());
+          return (secDiff != 0) ? secDiff : Integer.compare(t1.getNanos(), t2.getNanos());
         }
       };
 

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

@@ -57,12 +57,15 @@ import com.google.protobuf.util.JsonTestProto.TestDuration;
 import com.google.protobuf.util.JsonTestProto.TestFieldMask;
 import com.google.protobuf.util.JsonTestProto.TestMap;
 import com.google.protobuf.util.JsonTestProto.TestOneof;
+import com.google.protobuf.util.JsonTestProto.TestRecursive;
 import com.google.protobuf.util.JsonTestProto.TestStruct;
 import com.google.protobuf.util.JsonTestProto.TestTimestamp;
 import com.google.protobuf.util.JsonTestProto.TestWrappers;
 import java.io.IOException;
 import java.math.BigDecimal;
 import java.math.BigInteger;
+import java.util.HashMap;
+import java.util.Map;
 import junit.framework.TestCase;
 
 public class JsonFormatTest extends TestCase {
@@ -216,7 +219,9 @@ public class JsonFormatTest extends TestCase {
 
     TestMap.Builder mapBuilder = TestMap.newBuilder();
     mapBuilder.putInt32ToEnumMapValue(1, 0);
-    mapBuilder.getMutableInt32ToEnumMapValue().put(2, 12345);
+    Map<Integer, Integer> mapWithInvalidValues = new HashMap<Integer, Integer>();
+    mapWithInvalidValues.put(2, 12345);
+    mapBuilder.putAllInt32ToEnumMapValue(mapWithInvalidValues);
     TestMap mapMessage = mapBuilder.build();
     assertEquals(
         "{\n"
@@ -1140,6 +1145,7 @@ public class JsonFormatTest extends TestCase {
       // Expected.
     }
   }
+
   public void testParserIgnoringUnknownFields() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     String json = "{\n" + "  \"unknownField\": \"XXX\"\n" + "}";
@@ -1358,4 +1364,34 @@ public class JsonFormatTest extends TestCase {
     Any any = builder.build();
     assertEquals(0, any.getValue().size());
   }
+
+  public void testRecursionLimit() throws Exception {
+    String input =
+        "{\n"
+            + "  \"nested\": {\n"
+            + "    \"nested\": {\n"
+            + "      \"nested\": {\n"
+            + "        \"nested\": {\n"
+            + "          \"value\": 1234\n"
+            + "        }\n"
+            + "      }\n"
+            + "    }\n"
+            + "  }\n"
+            + "}\n";
+
+    JsonFormat.Parser parser = JsonFormat.parser();
+    TestRecursive.Builder builder = TestRecursive.newBuilder();
+    parser.merge(input, builder);
+    TestRecursive message = builder.build();
+    assertEquals(1234, message.getNested().getNested().getNested().getNested().getValue());
+
+    parser = JsonFormat.parser().usingRecursionLimit(3);
+    builder = TestRecursive.newBuilder();
+    try {
+      parser.merge(input, builder);
+      fail("Exception is expected.");
+    } catch (InvalidProtocolBufferException e) {
+      // Expected.
+    }
+  }
 }

+ 5 - 0
java/util/src/test/proto/com/google/protobuf/util/json_test.proto

@@ -201,3 +201,8 @@ message TestAny {
 message TestCustomJsonName {
   int32 value = 1 [json_name = "@value"];
 }
+
+message TestRecursive {
+  int32 value = 1;
+  TestRecursive nested = 2;
+}

+ 46 - 0
js/binary/decoder.js

@@ -732,6 +732,24 @@ jspb.BinaryDecoder.prototype.readZigzagVarint64 = function() {
 };
 
 
+/**
+ * Reads a signed, zigzag-encoded 64-bit varint from the binary stream and
+ * returns its valud as a string.
+ *
+ * Zigzag encoding is a modification of varint encoding that reduces the
+ * storage overhead for small negative integers - for more details on the
+ * format, see https://developers.google.com/protocol-buffers/docs/encoding
+ *
+ * @return {string} The decoded signed, zigzag-encoded 64-bit varint as a
+ * string.
+ */
+jspb.BinaryDecoder.prototype.readZigzagVarint64String = function() {
+  // TODO(haberman): write lossless 64-bit zig-zag math.
+  var value = this.readZigzagVarint64();
+  return value.toString();
+};
+
+
 /**
  * Reads a raw unsigned 8-bit integer from the binary stream.
  *
@@ -790,6 +808,20 @@ jspb.BinaryDecoder.prototype.readUint64 = function() {
 };
 
 
+/**
+ * Reads a raw unsigned 64-bit integer from the binary stream. Note that since
+ * Javascript represents all numbers as double-precision floats, there will be
+ * precision lost if the absolute value of the integer is larger than 2^53.
+ *
+ * @return {string} The unsigned 64-bit integer read from the binary stream.
+ */
+jspb.BinaryDecoder.prototype.readUint64String = function() {
+  var bitsLow = this.readUint32();
+  var bitsHigh = this.readUint32();
+  return jspb.utils.joinUnsignedDecimalString(bitsLow, bitsHigh);
+};
+
+
 /**
  * Reads a raw signed 8-bit integer from the binary stream.
  *
@@ -848,6 +880,20 @@ jspb.BinaryDecoder.prototype.readInt64 = function() {
 };
 
 
+/**
+ * Reads a raw signed 64-bit integer from the binary stream and returns it as a
+ * string.
+ *
+ * @return {string} The signed 64-bit integer read from the binary stream.
+ *     Precision will be lost if the integer exceeds 2^53.
+ */
+jspb.BinaryDecoder.prototype.readInt64String = function() {
+  var bitsLow = this.readUint32();
+  var bitsHigh = this.readUint32();
+  return jspb.utils.joinSignedDecimalString(bitsLow, bitsHigh);
+};
+
+
 /**
  * Reads a 32-bit floating-point number from the binary stream, using the
  * temporary buffer to realign the data.

+ 45 - 2
js/binary/encoder.js

@@ -99,6 +99,24 @@ jspb.BinaryEncoder.prototype.writeSplitVarint64 = function(lowBits, highBits) {
 };
 
 
+/**
+ * Encodes a 64-bit integer in 32:32 split representation into its wire-format
+ * fixed representation and stores it in the buffer.
+ * @param {number} lowBits The low 32 bits of the int.
+ * @param {number} highBits The high 32 bits of the int.
+ */
+jspb.BinaryEncoder.prototype.writeSplitFixed64 = function(lowBits, highBits) {
+  goog.asserts.assert(lowBits == Math.floor(lowBits));
+  goog.asserts.assert(highBits == Math.floor(highBits));
+  goog.asserts.assert((lowBits >= 0) &&
+                      (lowBits < jspb.BinaryConstants.TWO_TO_32));
+  goog.asserts.assert((highBits >= 0) &&
+                      (highBits < jspb.BinaryConstants.TWO_TO_32));
+  this.writeUint32(lowBits);
+  this.writeUint32(highBits);
+};
+
+
 /**
  * Encodes a 32-bit unsigned integer into its wire-format varint representation
  * and stores it in the buffer.
@@ -207,6 +225,18 @@ jspb.BinaryEncoder.prototype.writeZigzagVarint64 = function(value) {
 };
 
 
+/**
+ * Encodes a JavaScript decimal string into its wire-format, zigzag-encoded
+ * varint representation and stores it in the buffer. Integers not representable
+ * in 64 bits will be truncated.
+ * @param {string} value The integer to convert.
+ */
+jspb.BinaryEncoder.prototype.writeZigzagVarint64String = function(value) {
+  // TODO(haberman): write lossless 64-bit zig-zag math.
+  this.writeZigzagVarint64(parseInt(value, 10));
+};
+
+
 /**
  * Writes a 8-bit unsigned integer to the buffer. Numbers outside the range
  * [0,2^8) will be truncated.
@@ -314,8 +344,21 @@ jspb.BinaryEncoder.prototype.writeInt64 = function(value) {
   goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
                       (value < jspb.BinaryConstants.TWO_TO_63));
   jspb.utils.splitInt64(value);
-  this.writeUint32(jspb.utils.split64Low);
-  this.writeUint32(jspb.utils.split64High);
+  this.writeSplitFixed64(jspb.utils.split64Low, jspb.utils.split64High);
+};
+
+
+/**
+ * Writes a 64-bit integer decimal strings to the buffer. Numbers outside the
+ * range [-2^63,2^63) will be truncated.
+ * @param {string} value The value to write.
+ */
+jspb.BinaryEncoder.prototype.writeInt64String = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
+                      (value < jspb.BinaryConstants.TWO_TO_63));
+  jspb.utils.splitHash64(jspb.utils.decimalStringToHash64(value));
+  this.writeSplitFixed64(jspb.utils.split64Low, jspb.utils.split64High);
 };
 
 

+ 39 - 2
js/binary/proto_test.js

@@ -32,6 +32,7 @@
 
 goog.require('goog.crypt.base64');
 goog.require('goog.testing.asserts');
+goog.require('jspb.BinaryWriter');
 goog.require('jspb.Message');
 
 // CommonJS-LoadFromFile: ../testbinary_pb proto.jspb.test
@@ -87,6 +88,9 @@ goog.require('proto.jspb.test.extendRepeatedStringList');
 goog.require('proto.jspb.test.extendRepeatedUint32List');
 goog.require('proto.jspb.test.extendRepeatedUint64List');
 
+// CommonJS-LoadFromFile: ../node_modules/google-protobuf/google/protobuf/any_pb proto.google.protobuf
+goog.require('proto.google.protobuf.Any');
+
 
 var suite = {};
 
@@ -194,8 +198,6 @@ function bytesCompare(arr, expected) {
  * @param {proto.jspb.test.TestAllTypes} copy
  */
 function checkAllFields(original, copy) {
-  assertTrue(jspb.Message.equals(original, copy));
-
   assertEquals(copy.getOptionalInt32(), -42);
   assertEquals(copy.getOptionalInt64(), -0x7fffffff00000000);
   assertEquals(copy.getOptionalUint32(), 0x80000000);
@@ -270,6 +272,9 @@ function checkAllFields(original, copy) {
   assertElementsEquals(copy.getPackedRepeatedFloatList(), [1.5]);
   assertElementsEquals(copy.getPackedRepeatedDoubleList(), [-1.5]);
 
+
+  // Check last so we get more granular errors first.
+  assertTrue(jspb.Message.equals(original, copy));
 }
 
 
@@ -625,4 +630,36 @@ describe('protoBinaryTest', function() {
     var decoded = proto.jspb.test.TestExtendable.deserializeBinary(encoded);
     checkExtensions(decoded);
   });
+
+  /**
+   * Tests that unknown extensions don't cause deserialization failure.
+   */
+  it('testUnknownExtension', function() {
+    var msg = new proto.jspb.test.TestExtendable();
+    fillExtensions(msg);
+    var writer = new jspb.BinaryWriter();
+    writer.writeBool((1 << 29) - 1, true);
+    proto.jspb.test.TestExtendable.serializeBinaryToWriter(msg, writer);
+    var encoded = writer.getResultBuffer();
+    var decoded = proto.jspb.test.TestExtendable.deserializeBinary(encoded);
+    checkExtensions(decoded);
+  });
+
+  it('testAnyWellKnownType', function() {
+    var any = new proto.google.protobuf.Any();
+    var msg = new proto.jspb.test.TestAllTypes();
+
+    fillAllFields(msg);
+
+    any.pack(msg.serializeBinary(), 'jspb.test.TestAllTypes');
+
+    assertEquals('type.googleapis.com/jspb.test.TestAllTypes',
+                 any.getTypeUrl());
+
+    var msg2 = any.unpack(
+        proto.jspb.test.TestAllTypes.deserializeBinary,
+        'jspb.test.TestAllTypes');
+
+    checkAllFields(msg, msg2);
+  });
 });

+ 94 - 2
js/binary/reader.js

@@ -743,6 +743,20 @@ jspb.BinaryReader.prototype.readSint64 = function() {
 };
 
 
+/**
+ * Reads a signed zigzag-encoded 64-bit integer field from the binary stream,
+ * or throws an error if the next field in the stream is not of the correct
+ * wire type.
+ *
+ * @return {string} The value of the signed 64-bit integer field as a decimal string.
+ */
+jspb.BinaryReader.prototype.readSint64String = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
+  return this.decoder_.readZigzagVarint64String();
+};
+
+
 /**
  * Reads an unsigned 32-bit fixed-length integer fiield from the binary stream,
  * or throws an error if the next field in the stream is not of the correct
@@ -771,12 +785,29 @@ jspb.BinaryReader.prototype.readFixed64 = function() {
 };
 
 
+/**
+ * Reads a signed 64-bit integer field from the binary stream as a string, or
+ * throws an error if the next field in the stream is not of the correct wire
+ * type.
+ *
+ * Returns the value as a string.
+ *
+ * @return {string} The value of the unsigned 64-bit integer field as a decimal
+ * string.
+ */
+jspb.BinaryReader.prototype.readFixed64String = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED64);
+  return this.decoder_.readUint64String();
+};
+
+
 /**
  * Reads a signed 32-bit fixed-length integer fiield from the binary stream, or
  * throws an error if the next field in the stream is not of the correct wire
  * type.
  *
- * @return {number} The value of the double field.
+ * @return {number} The value of the signed 32-bit integer field.
  */
 jspb.BinaryReader.prototype.readSfixed32 = function() {
   goog.asserts.assert(
@@ -785,12 +816,27 @@ jspb.BinaryReader.prototype.readSfixed32 = function() {
 };
 
 
+/**
+ * Reads a signed 32-bit fixed-length integer fiield from the binary stream, or
+ * throws an error if the next field in the stream is not of the correct wire
+ * type.
+ *
+ * @return {string} The value of the signed 32-bit integer field as a decimal
+ * string.
+ */
+jspb.BinaryReader.prototype.readSfixed32String = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED32);
+  return this.decoder_.readInt32().toString();
+};
+
+
 /**
  * Reads a signed 64-bit fixed-length integer fiield from the binary stream, or
  * throws an error if the next field in the stream is not of the correct wire
  * type.
  *
- * @return {number} The value of the float field.
+ * @return {number} The value of the sfixed64 field.
  */
 jspb.BinaryReader.prototype.readSfixed64 = function() {
   goog.asserts.assert(
@@ -799,6 +845,22 @@ jspb.BinaryReader.prototype.readSfixed64 = function() {
 };
 
 
+/**
+ * Reads a signed 64-bit fixed-length integer fiield from the binary stream, or
+ * throws an error if the next field in the stream is not of the correct wire
+ * type.
+ *
+ * Returns the value as a string.
+ *
+ * @return {string} The value of the sfixed64 field as a decimal string.
+ */
+jspb.BinaryReader.prototype.readSfixed64String = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED64);
+  return this.decoder_.readInt64String();
+};
+
+
 /**
  * Reads a 32-bit floating-point field from the binary stream, or throws an
  * error if the next field in the stream is not of the correct wire type.
@@ -1027,6 +1089,16 @@ jspb.BinaryReader.prototype.readPackedSint64 = function() {
 };
 
 
+/**
+ * Reads a packed sint64 field, which consists of a length header and a list of
+ * zigzag varints.  Returns a list of strings.
+ * @return {!Array.<string>}
+ */
+jspb.BinaryReader.prototype.readPackedSint64String = function() {
+  return this.readPackedField_(this.decoder_.readZigzagVarint64String);
+};
+
+
 /**
  * Reads a packed fixed32 field, which consists of a length header and a list
  * of unsigned 32-bit ints.
@@ -1047,6 +1119,16 @@ jspb.BinaryReader.prototype.readPackedFixed64 = function() {
 };
 
 
+/**
+ * Reads a packed fixed64 field, which consists of a length header and a list
+ * of unsigned 64-bit ints.  Returns a list of strings.
+ * @return {!Array.<number>}
+ */
+jspb.BinaryReader.prototype.readPackedFixed64String = function() {
+  return this.readPackedField_(this.decoder_.readUint64String);
+};
+
+
 /**
  * Reads a packed sfixed32 field, which consists of a length header and a list
  * of 32-bit ints.
@@ -1067,6 +1149,16 @@ jspb.BinaryReader.prototype.readPackedSfixed64 = function() {
 };
 
 
+/**
+ * Reads a packed sfixed64 field, which consists of a length header and a list
+ * of 64-bit ints.  Returns a list of strings.
+ * @return {!Array.<string>}
+ */
+jspb.BinaryReader.prototype.readPackedSfixed64String = function() {
+  return this.readPackedField_(this.decoder_.readInt64String);
+};
+
+
 /**
  * Reads a packed float field, which consists of a length header and a list of
  * floats.

+ 10 - 0
js/binary/utils.js

@@ -617,6 +617,16 @@ jspb.utils.decimalStringToHash64 = function(dec) {
 };
 
 
+/**
+ * Converts a signed or unsigned decimal string into two 32-bit halves, and
+ * stores them in the temp variables listed above.
+ * @param {string} value The decimal string to convert.
+ */
+jspb.utils.splitDecimalString = function(value) {
+  jspb.utils.splitHash64(jspb.utils.decimalStringToHash64(value));
+};
+
+
 /**
  * Converts an 8-character hash string into its hexadecimal representation.
  * @param {string} hash

+ 214 - 201
js/binary/writer.js

@@ -434,6 +434,20 @@ jspb.BinaryWriter.prototype.writeZigzagVarint64_ = function(field, value) {
 };
 
 
+/**
+ * Writes a zigzag varint field to the buffer without range checking.
+ * @param {number} field The field number.
+ * @param {string?} value The value to write.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writeZigzagVarint64String_ = function(
+    field, value) {
+  if (value == null) return;
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.encoder_.writeZigzagVarint64String(value);
+};
+
+
 /**
  * Writes an int32 field to the buffer. Numbers outside the range [-2^31,2^31)
  * will be truncated.
@@ -574,6 +588,20 @@ jspb.BinaryWriter.prototype.writeSint64 = function(field, value) {
 };
 
 
+/**
+ * Writes a sint64 field to the buffer. Numbers outside the range [-2^63,2^63)
+ * will be truncated.
+ * @param {number} field The field number.
+ * @param {string?} value The decimal string to write.
+ */
+jspb.BinaryWriter.prototype.writeSint64String = function(field, value) {
+  if (value == null) return;
+  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
+                      (value < jspb.BinaryConstants.TWO_TO_63));
+  this.writeZigzagVarint64String_(field, value);
+};
+
+
 /**
  * Writes a fixed32 field to the buffer. Numbers outside the range [0,2^32)
  * will be truncated.
@@ -604,6 +632,19 @@ jspb.BinaryWriter.prototype.writeFixed64 = function(field, value) {
 };
 
 
+/**
+ * Writes a fixed64 field (with value as a string) to the buffer.
+ * @param {number} field The field number.
+ * @param {string?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeFixed64String = function(field, value) {
+  if (value == null) return;
+  var num = jspb.arith.UInt64.fromString(value);
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
+  this.encoder_.writeSplitFixed64(num.lo, num.hi);
+};
+
+
 /**
  * Writes a sfixed32 field to the buffer. Numbers outside the range
  * [-2^31,2^31) will be truncated.
@@ -634,6 +675,20 @@ jspb.BinaryWriter.prototype.writeSfixed64 = function(field, value) {
 };
 
 
+/**
+ * Writes a sfixed64 string field to the buffer. Numbers outside the range
+ * [-2^63,2^63) will be truncated.
+ * @param {number} field The field number.
+ * @param {string?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeSfixed64String = function(field, value) {
+  if (value == null) return;
+  var num = jspb.arith.Int64.fromString(value);
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
+  this.encoder_.writeSplitFixed64(num.lo, num.hi);
+};
+
+
 /**
  * Writes a single-precision floating point field to the buffer. Numbers
  * requiring more than 32 bits of precision will be truncated.
@@ -796,28 +851,11 @@ jspb.BinaryWriter.prototype.writeVarintHash64 = function(field, value) {
 
 
 /**
- * Writes an array of numbers to the buffer as a repeated varint field.
+ * Writes an array of numbers to the buffer as a repeated 32-bit int field.
  * @param {number} field The field number.
  * @param {?Array.<number>} value The array of ints to write.
- * @private
  */
-jspb.BinaryWriter.prototype.writeRepeatedUnsignedVarint32_ =
-    function(field, value) {
-  if (value == null) return;
-  for (var i = 0; i < value.length; i++) {
-    this.writeUnsignedVarint32_(field, value[i]);
-  }
-};
-
-
-/**
- * Writes an array of numbers to the buffer as a repeated varint field.
- * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
- * @private
- */
-jspb.BinaryWriter.prototype.writeRepeatedSignedVarint32_ =
-    function(field, value) {
+jspb.BinaryWriter.prototype.writeRepeatedInt32 = function(field, value) {
   if (value == null) return;
   for (var i = 0; i < value.length; i++) {
     this.writeSignedVarint32_(field, value[i]);
@@ -826,28 +864,25 @@ jspb.BinaryWriter.prototype.writeRepeatedSignedVarint32_ =
 
 
 /**
- * Writes an array of numbers to the buffer as a repeated varint field.
+ * Writes an array of numbers formatted as strings to the buffer as a repeated
+ * 32-bit int field.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
- * @private
+ * @param {?Array.<string>} value The array of ints to write.
  */
-jspb.BinaryWriter.prototype.writeRepeatedUnsignedVarint64_ =
-    function(field, value) {
+jspb.BinaryWriter.prototype.writeRepeatedInt32String = function(field, value) {
   if (value == null) return;
   for (var i = 0; i < value.length; i++) {
-    this.writeUnsignedVarint64_(field, value[i]);
+    this.writeInt32String(field, value[i]);
   }
 };
 
 
 /**
- * Writes an array of numbers to the buffer as a repeated varint field.
+ * Writes an array of numbers to the buffer as a repeated 64-bit int field.
  * @param {number} field The field number.
  * @param {?Array.<number>} value The array of ints to write.
- * @private
  */
-jspb.BinaryWriter.prototype.writeRepeatedSignedVarint64_ =
-    function(field, value) {
+jspb.BinaryWriter.prototype.writeRepeatedInt64 = function(field, value) {
   if (value == null) return;
   for (var i = 0; i < value.length; i++) {
     this.writeSignedVarint64_(field, value[i]);
@@ -856,147 +891,112 @@ jspb.BinaryWriter.prototype.writeRepeatedSignedVarint64_ =
 
 
 /**
- * Writes an array of numbers to the buffer as a repeated zigzag field.
+ * Writes an array of numbers formatted as strings to the buffer as a repeated
+ * 64-bit int field.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
- * @private
+ * @param {?Array.<string>} value The array of ints to write.
  */
-jspb.BinaryWriter.prototype.writeRepeatedZigzag32_ = function(field, value) {
+jspb.BinaryWriter.prototype.writeRepeatedInt64String = function(field, value) {
   if (value == null) return;
   for (var i = 0; i < value.length; i++) {
-    this.writeZigzagVarint32_(field, value[i]);
+    this.writeInt64String(field, value[i]);
   }
 };
 
 
 /**
- * Writes an array of numbers to the buffer as a repeated zigzag field.
+ * Writes an array numbers to the buffer as a repeated unsigned 32-bit int
+ *     field.
  * @param {number} field The field number.
  * @param {?Array.<number>} value The array of ints to write.
- * @private
  */
-jspb.BinaryWriter.prototype.writeRepeatedZigzag_ = function(field, value) {
+jspb.BinaryWriter.prototype.writeRepeatedUint32 = function(field, value) {
   if (value == null) return;
   for (var i = 0; i < value.length; i++) {
-    this.writeZigzagVarint64_(field, value[i]);
+    this.writeUnsignedVarint32_(field, value[i]);
   }
 };
 
 
-/**
- * Writes an array of numbers to the buffer as a repeated 32-bit int field.
- * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
- */
-jspb.BinaryWriter.prototype.writeRepeatedInt32 =
-    jspb.BinaryWriter.prototype.writeRepeatedSignedVarint32_;
-
-
 /**
  * Writes an array of numbers formatted as strings to the buffer as a repeated
- * 32-bit int field.
+ * unsigned 32-bit int field.
  * @param {number} field The field number.
  * @param {?Array.<string>} value The array of ints to write.
  */
-jspb.BinaryWriter.prototype.writeRepeatedInt32String =
-    function(field, value) {
+jspb.BinaryWriter.prototype.writeRepeatedUint32String = function(field, value) {
   if (value == null) return;
   for (var i = 0; i < value.length; i++) {
-    this.writeInt32String(field, value[i]);
+    this.writeUint32String(field, value[i]);
   }
 };
 
 
 /**
- * Writes an array of numbers to the buffer as a repeated 64-bit int field.
+ * Writes an array numbers to the buffer as a repeated unsigned 64-bit int
+ *     field.
  * @param {number} field The field number.
  * @param {?Array.<number>} value The array of ints to write.
  */
-jspb.BinaryWriter.prototype.writeRepeatedInt64 =
-    jspb.BinaryWriter.prototype.writeRepeatedSignedVarint64_;
-
-
-/**
- * Writes an array of numbers formatted as strings to the buffer as a repeated
- * 64-bit int field.
- * @param {number} field The field number.
- * @param {?Array.<string>} value The array of ints to write.
- */
-jspb.BinaryWriter.prototype.writeRepeatedInt64String =
-    function(field, value) {
+jspb.BinaryWriter.prototype.writeRepeatedUint64 = function(field, value) {
   if (value == null) return;
   for (var i = 0; i < value.length; i++) {
-    this.writeInt64String(field, value[i]);
+    this.writeUnsignedVarint64_(field, value[i]);
   }
 };
 
 
-/**
- * Writes an array numbers to the buffer as a repeated unsigned 32-bit int
- *     field.
- * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
- */
-jspb.BinaryWriter.prototype.writeRepeatedUint32 =
-    jspb.BinaryWriter.prototype.writeRepeatedUnsignedVarint32_;
-
-
 /**
  * Writes an array of numbers formatted as strings to the buffer as a repeated
- * unsigned 32-bit int field.
+ * unsigned 64-bit int field.
  * @param {number} field The field number.
  * @param {?Array.<string>} value The array of ints to write.
  */
-jspb.BinaryWriter.prototype.writeRepeatedUint32String =
-    function(field, value) {
+jspb.BinaryWriter.prototype.writeRepeatedUint64String = function(field, value) {
   if (value == null) return;
   for (var i = 0; i < value.length; i++) {
-    this.writeUint32String(field, value[i]);
+    this.writeUint64String(field, value[i]);
   }
 };
 
 
 /**
- * Writes an array numbers to the buffer as a repeated unsigned 64-bit int
- *     field.
+ * Writes an array numbers to the buffer as a repeated signed 32-bit int field.
  * @param {number} field The field number.
  * @param {?Array.<number>} value The array of ints to write.
  */
-jspb.BinaryWriter.prototype.writeRepeatedUint64 =
-    jspb.BinaryWriter.prototype.writeRepeatedUnsignedVarint64_;
-
-
-/**
- * Writes an array of numbers formatted as strings to the buffer as a repeated
- * unsigned 64-bit int field.
- * @param {number} field The field number.
- * @param {?Array.<string>} value The array of ints to write.
- */
-jspb.BinaryWriter.prototype.writeRepeatedUint64String =
-    function(field, value) {
+jspb.BinaryWriter.prototype.writeRepeatedSint32 = function(field, value) {
   if (value == null) return;
   for (var i = 0; i < value.length; i++) {
-    this.writeUint64String(field, value[i]);
+    this.writeZigzagVarint32_(field, value[i]);
   }
 };
 
 
 /**
- * Writes an array numbers to the buffer as a repeated signed 32-bit int field.
+ * Writes an array numbers to the buffer as a repeated signed 64-bit int field.
  * @param {number} field The field number.
  * @param {?Array.<number>} value The array of ints to write.
  */
-jspb.BinaryWriter.prototype.writeRepeatedSint32 =
-    jspb.BinaryWriter.prototype.writeRepeatedZigzag32_;
+jspb.BinaryWriter.prototype.writeRepeatedSint64 = function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeZigzagVarint64_(field, value[i]);
+  }
+};
 
 
 /**
  * Writes an array numbers to the buffer as a repeated signed 64-bit int field.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Array.<string>} value The array of ints to write.
  */
-jspb.BinaryWriter.prototype.writeRepeatedSint64 =
-    jspb.BinaryWriter.prototype.writeRepeatedZigzag_;
+jspb.BinaryWriter.prototype.writeRepeatedSint64String = function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeZigzagVarint64String_(field, value[i]);
+  }
+};
 
 
 /**
@@ -1027,6 +1027,21 @@ jspb.BinaryWriter.prototype.writeRepeatedFixed64 = function(field, value) {
 };
 
 
+/**
+ * Writes an array of numbers to the buffer as a repeated fixed64 field. This
+ * works for both signed and unsigned fixed64s.
+ * @param {number} field The field number.
+ * @param {?Array.<string>} value The array of decimal strings to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedFixed64String = function(
+    field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeFixed64String(field, value[i]);
+  }
+};
+
+
 /**
  * Writes an array of numbers to the buffer as a repeated sfixed32 field.
  * @param {number} field The field number.
@@ -1053,6 +1068,20 @@ jspb.BinaryWriter.prototype.writeRepeatedSfixed64 = function(field, value) {
 };
 
 
+/**
+ * Writes an array of decimal strings to the buffer as a repeated sfixed64
+ * field.
+ * @param {number} field The field number.
+ * @param {?Array.<string>} value The array of decimal strings to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedSfixed64String = function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeSfixed64String(field, value[i]);
+  }
+};
+
+
 /**
  * Writes an array of numbers to the buffer as a repeated float field.
  * @param {number} field The field number.
@@ -1203,151 +1232,127 @@ jspb.BinaryWriter.prototype.writeRepeatedVarintHash64 =
 
 
 /**
- * Writes an array of numbers to the buffer as a packed varint field.
+ * Writes an array of numbers to the buffer as a packed 32-bit int field.
  * @param {number} field The field number.
  * @param {?Array.<number>} value The array of ints to write.
- * @private
  */
-jspb.BinaryWriter.prototype.writePackedUnsignedVarint32_ = function(
-    field, value) {
+jspb.BinaryWriter.prototype.writePackedInt32 = function(field, value) {
   if (value == null || !value.length) return;
   var bookmark = this.beginDelimited_(field);
   for (var i = 0; i < value.length; i++) {
-    this.encoder_.writeUnsignedVarint32(value[i]);
+    this.encoder_.writeSignedVarint32(value[i]);
   }
   this.endDelimited_(bookmark);
 };
 
 
 /**
- * Writes an array of numbers to the buffer as a packed varint field.
- * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
- * @private
+ * Writes an array of numbers represented as strings to the buffer as a packed
+ * 32-bit int field.
+ * @param {number} field
+ * @param {?Array.<string>} value
  */
-jspb.BinaryWriter.prototype.writePackedSignedVarint32_ = function(
-    field, value) {
+jspb.BinaryWriter.prototype.writePackedInt32String = function(field, value) {
   if (value == null || !value.length) return;
   var bookmark = this.beginDelimited_(field);
   for (var i = 0; i < value.length; i++) {
-    this.encoder_.writeSignedVarint32(value[i]);
+    this.encoder_.writeSignedVarint32(parseInt(value[i], 10));
   }
   this.endDelimited_(bookmark);
 };
 
 
 /**
- * Writes an array of numbers to the buffer as a packed varint field.
+ * Writes an array of numbers to the buffer as a packed 64-bit int field.
  * @param {number} field The field number.
  * @param {?Array.<number>} value The array of ints to write.
- * @private
  */
-jspb.BinaryWriter.prototype.writePackedUnsignedVarint64_ = function(
-    field, value) {
+jspb.BinaryWriter.prototype.writePackedInt64 = function(field, value) {
   if (value == null || !value.length) return;
   var bookmark = this.beginDelimited_(field);
   for (var i = 0; i < value.length; i++) {
-    this.encoder_.writeUnsignedVarint64(value[i]);
+    this.encoder_.writeSignedVarint64(value[i]);
   }
   this.endDelimited_(bookmark);
 };
 
 
 /**
- * Writes an array of numbers to the buffer as a packed varint field.
- * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
- * @private
+ * Writes an array of numbers represented as strings to the buffer as a packed
+ * 64-bit int field.
+ * @param {number} field
+ * @param {?Array.<string>} value
  */
-jspb.BinaryWriter.prototype.writePackedSignedVarint64_ = function(
-    field, value) {
+jspb.BinaryWriter.prototype.writePackedInt64String = function(field, value) {
   if (value == null || !value.length) return;
   var bookmark = this.beginDelimited_(field);
   for (var i = 0; i < value.length; i++) {
-    this.encoder_.writeSignedVarint64(value[i]);
+    var num = jspb.arith.Int64.fromString(value[i]);
+    this.encoder_.writeSplitVarint64(num.lo, num.hi);
   }
   this.endDelimited_(bookmark);
 };
 
 
 /**
- * Writes an array of numbers to the buffer as a packed zigzag field.
+ * Writes an array numbers to the buffer as a packed unsigned 32-bit int field.
  * @param {number} field The field number.
  * @param {?Array.<number>} value The array of ints to write.
- * @private
  */
-jspb.BinaryWriter.prototype.writePackedZigzag32_ = function(field, value) {
+jspb.BinaryWriter.prototype.writePackedUint32 = function(field, value) {
   if (value == null || !value.length) return;
   var bookmark = this.beginDelimited_(field);
   for (var i = 0; i < value.length; i++) {
-    this.encoder_.writeZigzagVarint32(value[i]);
+    this.encoder_.writeUnsignedVarint32(value[i]);
   }
   this.endDelimited_(bookmark);
 };
 
 
 /**
- * Writes an array of numbers to the buffer as a packed zigzag field.
- * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
- * @private
+ * Writes an array of numbers represented as strings to the buffer as a packed
+ * unsigned 32-bit int field.
+ * @param {number} field
+ * @param {?Array.<string>} value
  */
-jspb.BinaryWriter.prototype.writePackedZigzag64_ = function(field, value) {
+jspb.BinaryWriter.prototype.writePackedUint32String =
+    function(field, value) {
   if (value == null || !value.length) return;
   var bookmark = this.beginDelimited_(field);
   for (var i = 0; i < value.length; i++) {
-    this.encoder_.writeZigzagVarint64(value[i]);
+    this.encoder_.writeUnsignedVarint32(parseInt(value[i], 10));
   }
   this.endDelimited_(bookmark);
 };
 
 
 /**
- * Writes an array of numbers to the buffer as a packed 32-bit int field.
+ * Writes an array numbers to the buffer as a packed unsigned 64-bit int field.
  * @param {number} field The field number.
  * @param {?Array.<number>} value The array of ints to write.
  */
-jspb.BinaryWriter.prototype.writePackedInt32 =
-    jspb.BinaryWriter.prototype.writePackedSignedVarint32_;
-
-
-/**
- * Writes an array of numbers represented as strings to the buffer as a packed
- * 32-bit int field.
- * @param {number} field
- * @param {?Array.<string>} value
- */
-jspb.BinaryWriter.prototype.writePackedInt32String = function(field, value) {
+jspb.BinaryWriter.prototype.writePackedUint64 = function(field, value) {
   if (value == null || !value.length) return;
   var bookmark = this.beginDelimited_(field);
   for (var i = 0; i < value.length; i++) {
-    this.encoder_.writeSignedVarint32(parseInt(value[i], 10));
+    this.encoder_.writeUnsignedVarint64(value[i]);
   }
   this.endDelimited_(bookmark);
 };
 
 
-/**
- * Writes an array of numbers to the buffer as a packed 64-bit int field.
- * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
- */
-jspb.BinaryWriter.prototype.writePackedInt64 =
-    jspb.BinaryWriter.prototype.writePackedSignedVarint64_;
-
-
 /**
  * Writes an array of numbers represented as strings to the buffer as a packed
- * 64-bit int field.
+ * unsigned 64-bit int field.
  * @param {number} field
  * @param {?Array.<string>} value
  */
-jspb.BinaryWriter.prototype.writePackedInt64String =
+jspb.BinaryWriter.prototype.writePackedUint64String =
     function(field, value) {
   if (value == null || !value.length) return;
   var bookmark = this.beginDelimited_(field);
   for (var i = 0; i < value.length; i++) {
-    var num = jspb.arith.Int64.fromString(value[i]);
+    var num = jspb.arith.UInt64.fromString(value[i]);
     this.encoder_.writeSplitVarint64(num.lo, num.hi);
   }
   this.endDelimited_(bookmark);
@@ -1355,74 +1360,50 @@ jspb.BinaryWriter.prototype.writePackedInt64String =
 
 
 /**
- * Writes an array numbers to the buffer as a packed unsigned 32-bit int field.
+ * Writes an array numbers to the buffer as a packed signed 32-bit int field.
  * @param {number} field The field number.
  * @param {?Array.<number>} value The array of ints to write.
  */
-jspb.BinaryWriter.prototype.writePackedUint32 =
-    jspb.BinaryWriter.prototype.writePackedUnsignedVarint32_;
-
-
-/**
- * Writes an array of numbers represented as strings to the buffer as a packed
- * unsigned 32-bit int field.
- * @param {number} field
- * @param {?Array.<string>} value
- */
-jspb.BinaryWriter.prototype.writePackedUint32String =
-    function(field, value) {
+jspb.BinaryWriter.prototype.writePackedSint32 = function(field, value) {
   if (value == null || !value.length) return;
   var bookmark = this.beginDelimited_(field);
   for (var i = 0; i < value.length; i++) {
-    this.encoder_.writeUnsignedVarint32(parseInt(value[i], 10));
+    this.encoder_.writeZigzagVarint32(value[i]);
   }
   this.endDelimited_(bookmark);
 };
 
 
 /**
- * Writes an array numbers to the buffer as a packed unsigned 64-bit int field.
+ * Writes an array of numbers to the buffer as a packed signed 64-bit int field.
  * @param {number} field The field number.
  * @param {?Array.<number>} value The array of ints to write.
  */
-jspb.BinaryWriter.prototype.writePackedUint64 =
-    jspb.BinaryWriter.prototype.writePackedUnsignedVarint64_;
-
-
-/**
- * Writes an array of numbers represented as strings to the buffer as a packed
- * unsigned 64-bit int field.
- * @param {number} field
- * @param {?Array.<string>} value
- */
-jspb.BinaryWriter.prototype.writePackedUint64String =
-    function(field, value) {
+jspb.BinaryWriter.prototype.writePackedSint64 = function(field, value) {
   if (value == null || !value.length) return;
   var bookmark = this.beginDelimited_(field);
   for (var i = 0; i < value.length; i++) {
-    var num = jspb.arith.UInt64.fromString(value[i]);
-    this.encoder_.writeSplitVarint64(num.lo, num.hi);
+    this.encoder_.writeZigzagVarint64(value[i]);
   }
   this.endDelimited_(bookmark);
 };
 
 
 /**
- * Writes an array numbers to the buffer as a packed signed 32-bit int field.
+ * Writes an array of decimal strings to the buffer as a packed signed 64-bit
+ * int field.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Array.<string>} value The array of decimal strings to write.
  */
-jspb.BinaryWriter.prototype.writePackedSint32 =
-    jspb.BinaryWriter.prototype.writePackedZigzag32_;
-
-
-/**
- * Writes an array numbers to the buffer as a packed signed 64-bit int field.
- * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
- */
-jspb.BinaryWriter.prototype.writePackedSint64 =
-    jspb.BinaryWriter.prototype.writePackedZigzag64_;
+jspb.BinaryWriter.prototype.writePackedSint64String = function(field, value) {
+  if (value == null || !value.length) return;
+  var bookmark = this.beginDelimited_(field);
+  for (var i = 0; i < value.length; i++) {
+    // TODO(haberman): make lossless
+    this.encoder_.writeZigzagVarint64(parseInt(value[i], 10));
+  }
+  this.endDelimited_(bookmark);
+};
 
 
 /**
@@ -1455,6 +1436,23 @@ jspb.BinaryWriter.prototype.writePackedFixed64 = function(field, value) {
 };
 
 
+/**
+ * Writes an array of numbers represented as strings to the buffer as a packed
+ * fixed64 field.
+ * @param {number} field The field number.
+ * @param {?Array.<string>} value The array of strings to write.
+ */
+jspb.BinaryWriter.prototype.writePackedFixed64String = function(field, value) {
+  if (value == null || !value.length) return;
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+  this.encoder_.writeUnsignedVarint32(value.length * 8);
+  for (var i = 0; i < value.length; i++) {
+    var num = jspb.arith.UInt64.fromString(value[i]);
+    this.encoder_.writeSplitFixed64(num.lo, num.hi);
+  }
+};
+
+
 /**
  * Writes an array of numbers to the buffer as a packed sfixed32 field.
  * @param {number} field The field number.
@@ -1485,6 +1483,21 @@ jspb.BinaryWriter.prototype.writePackedSfixed64 = function(field, value) {
 };
 
 
+/**
+ * Writes an array of numbers to the buffer as a packed sfixed64 field.
+ * @param {number} field The field number.
+ * @param {?Array.<string>} value The array of decimal strings to write.
+ */
+jspb.BinaryWriter.prototype.writePackedSfixed64String = function(field, value) {
+  if (value == null || !value.length) return;
+  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+  this.encoder_.writeUnsignedVarint32(value.length * 8);
+  for (var i = 0; i < value.length; i++) {
+    this.encoder_.writeInt64String(value[i]);
+  }
+};
+
+
 /**
  * Writes an array of numbers to the buffer as a packed float field.
  * @param {number} field The field number.

+ 1 - 0
js/commonjs/export.js

@@ -24,3 +24,4 @@ exports.ExtensionFieldBinaryInfo = jspb.ExtensionFieldBinaryInfo;
 exports.exportSymbol = goog.exportSymbol;
 exports.inherits = goog.inherits;
 exports.object = {extend: goog.object.extend};
+exports.typeOf = goog.typeOf;

+ 1 - 0
js/commonjs/export_testdeps.js

@@ -12,6 +12,7 @@ goog.require('jspb.arith.Int64');
 goog.require('jspb.arith.UInt64');
 goog.require('jspb.BinaryEncoder');
 goog.require('jspb.BinaryDecoder');
+goog.require('jspb.BinaryWriter');
 goog.require('jspb.utils');
 
 exports.goog = goog;

+ 3 - 3
js/gulpfile.js

@@ -24,7 +24,7 @@ var wellKnownTypes = [
 ];
 
 gulp.task('genproto_closure', function (cb) {
-  exec(protoc + ' --js_out=library=testproto_libs,binary:.  -I ../src -I . *.proto ../src/google/protobuf/descriptor.proto',
+  exec(protoc + ' --js_out=library=testproto_libs,binary:.  -I ../src -I . *.proto && ' + protoc + ' --js_out=one_output_file_per_input_file,binary:. -I ../src -I . ' + wellKnownTypes.join(' '),
        function (err, stdout, stderr) {
     console.log(stdout);
     console.log(stderr);
@@ -33,7 +33,7 @@ gulp.task('genproto_closure', function (cb) {
 });
 
 gulp.task('genproto_commonjs', function (cb) {
-  exec('mkdir -p commonjs_out && ' + protoc + ' --js_out=import_style=commonjs,binary:commonjs_out -I ../src -I commonjs -I . *.proto commonjs/test*/*.proto ../src/google/protobuf/descriptor.proto',
+  exec('mkdir -p commonjs_out && ' + protoc + ' --js_out=import_style=commonjs,binary:commonjs_out -I ../src -I commonjs -I . *.proto commonjs/test*/*.proto ' + wellKnownTypes.join(' '),
        function (err, stdout, stderr) {
     console.log(stdout);
     console.log(stderr);
@@ -42,7 +42,7 @@ gulp.task('genproto_commonjs', function (cb) {
 });
 
 gulp.task('genproto_commonjs_wellknowntypes', function (cb) {
-  exec('mkdir -p commonjs_out/node_modules/google-protobuf && ' + protoc + ' --js_out=import_style=commonjs,binary:commonjs_out/node_modules/google-protobuf -I ../src ../src/google/protobuf/descriptor.proto',
+  exec('mkdir -p commonjs_out/node_modules/google-protobuf && ' + protoc + ' --js_out=import_style=commonjs,binary:commonjs_out/node_modules/google-protobuf -I ../src ' + wellKnownTypes.join(' '),
        function (err, stdout, stderr) {
     console.log(stdout);
     console.log(stderr);

+ 4 - 1
js/jasmine.json

@@ -7,6 +7,9 @@
     "helpers": [
         "node_modules/google-closure-library/closure/goog/bootstrap/nodejs.js",
         "node_loader.js",
-        "deps.js"
+        "deps.js",
+        "google/protobuf/any.js",
+        "google/protobuf/struct.js",
+        "google/protobuf/timestamp.js"
     ]
 }

+ 53 - 1
js/map.js

@@ -130,6 +130,58 @@ jspb.Map.prototype.toArray = function() {
 };
 
 
+/**
+ * Returns the map formatted as an array of key-value pairs, suitable for the
+ * toObject() form of a message.
+ *
+ * @param {boolean=} includeInstance Whether to include the JSPB instance for
+ *    transitional soy proto support: http://goto/soy-param-migration
+ * @param {!function((boolean|undefined),!V):!Object=} valueToObject
+ *    The static toObject() method, if V is a message type.
+ * @return {!Array<!Array<!Object>>}
+ */
+jspb.Map.prototype.toObject = function(includeInstance, valueToObject) {
+  var rawArray = this.toArray();
+  var entries = [];
+  for (var i = 0; i < rawArray.length; i++) {
+    var entry = this.map_[rawArray[i][0].toString()];
+    this.wrapEntry_(entry);
+    var valueWrapper = /** @type {!V|undefined} */ (entry.valueWrapper);
+    if (valueWrapper) {
+      goog.asserts.assert(valueToObject);
+      entries.push([entry.key, valueToObject(includeInstance, valueWrapper)]);
+    } else {
+      entries.push([entry.key, entry.value]);
+    }
+  }
+  return entries;
+};
+
+
+/**
+ * Returns a Map from the given array of key-value pairs when the values are of
+ * message type. The values in the array must match the format returned by their
+ * message type's toObject() method.
+ *
+ * @template K, V
+ * @param {!Array<!Array<!Object>>} entries
+ * @param {!function(new:V)|function(new:V,?)} valueCtor
+ *    The constructor for type V.
+ * @param {!function(!Object):V} valueFromObject
+ *    The fromObject function for type V.
+ * @return {!jspb.Map<K, V>}
+ */
+jspb.Map.fromObject = function(entries, valueCtor, valueFromObject) {
+  var result = new jspb.Map([], valueCtor);
+  for (var i = 0; i < entries.length; i++) {
+    var key = entries[i][0];
+    var value = valueFromObject(entries[i][1]);
+    result.set(key, value);
+  }
+  return result;
+};
+
+
 /**
  * Helper: return an iterator over an array.
  * @template T
@@ -193,7 +245,7 @@ jspb.Map.prototype.del = function(key) {
  * to help out Angular 1.x users.  Still evaluating whether this is the best
  * option.
  *
- * @return {!Array<K|V>}
+ * @return {!Array<!Array<K|V>>}
  */
 jspb.Map.prototype.getEntryList = function() {
   var entries = [];

+ 13 - 8
js/maps_test.js

@@ -262,6 +262,7 @@ function makeTests(msgInfo, submessageCtor, suffix) {
     });
   }
 
+
   /**
    * Exercises the lazy map<->underlying array sync.
    */
@@ -290,12 +291,16 @@ function makeTests(msgInfo, submessageCtor, suffix) {
 }
 
 describe('mapsTest', function() {
-  makeTests({
-    constructor: proto.jspb.test.TestMapFields,
-    deserializeBinary: proto.jspb.test.TestMapFields.deserializeBinary
-  }, proto.jspb.test.MapValueMessage, "_Binary");
-  makeTests({
-    constructor: proto.jspb.test.TestMapFieldsNoBinary,
-    deserializeBinary: null
-  }, proto.jspb.test.MapValueMessageNoBinary, "_NoBinary");
+  makeTests(
+      {
+        constructor: proto.jspb.test.TestMapFields,
+        deserializeBinary: proto.jspb.test.TestMapFields.deserializeBinary
+      },
+      proto.jspb.test.MapValueMessage, '_Binary');
+  makeTests(
+      {
+        constructor: proto.jspb.test.TestMapFieldsNoBinary,
+        deserializeBinary: null
+      },
+      proto.jspb.test.MapValueMessageNoBinary, '_NoBinary');
 });

+ 3 - 2
js/message.js

@@ -550,11 +550,11 @@ jspb.Message.serializeBinaryExtensions = function(proto, writer, extensions,
 jspb.Message.readBinaryExtension = function(msg, reader, extensions,
     getExtensionFn, setExtensionFn) {
   var binaryFieldInfo = extensions[reader.getFieldNumber()];
-  var fieldInfo = binaryFieldInfo.fieldInfo;
   if (!binaryFieldInfo) {
     reader.skipField();
     return;
   }
+  var fieldInfo = binaryFieldInfo.fieldInfo;
   if (!binaryFieldInfo.binaryReaderFn) {
     throw new Error('Deserializing extension whose generated code does not ' +
                     'support binary format');
@@ -972,7 +972,8 @@ 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 {number} fieldNumber The field number.
- * @param {jspb.Message|undefined} value A new value for this proto field.
+ * @param {?jspb.Message|?jspb.Map|undefined} value A new value for this proto
+ * field.
  * @protected
  */
 jspb.Message.setWrapperField = function(msg, fieldNumber, value) {

+ 6 - 1
js/message_test.js

@@ -73,10 +73,12 @@ goog.require('proto.jspb.test.TestGroup1');
 goog.require('proto.jspb.test.TestMessageWithOneof');
 goog.require('proto.jspb.test.TestReservedNames');
 goog.require('proto.jspb.test.TestReservedNamesExtension');
+goog.require('proto.jspb.test.Deeply.Nested.Message');
 
 // CommonJS-LoadFromFile: test2_pb proto.jspb.test
 goog.require('proto.jspb.test.ExtensionMessage');
 goog.require('proto.jspb.test.TestExtensionsMessage');
+goog.require('proto.jspb.test.ForeignNestedFieldMessage');
 
 
 
@@ -1047,11 +1049,14 @@ describe('Message test suite', function() {
     var nested = new proto.jspb.test.Deeply.Nested.Message();
     nested.setCount(5);
     msg.setDeeplyNestedMessage(nested);
+    assertEquals(5, msg.getDeeplyNestedMessage().getCount());
 
     // After a serialization-deserialization round trip we should get back the
     // same data we started with.
     var serialized = msg.serializeBinary();
-    var deserialized = proto.jspb.test.ForeignNestedFieldMessage.deserializeBinary(serialized);
+    var deserialized =
+        proto.jspb.test.ForeignNestedFieldMessage.deserializeBinary(serialized);
     assertEquals(5, deserialized.getDeeplyNestedMessage().getCount());
   });
+
 });

+ 38 - 0
js/proto3_test.js

@@ -38,6 +38,12 @@ goog.require('proto.jspb.test.ForeignMessage');
 goog.require('proto.jspb.test.Proto3Enum');
 goog.require('proto.jspb.test.TestProto3');
 
+// CommonJS-LoadFromFile: google/protobuf/timestamp_pb proto.google.protobuf
+goog.require('proto.google.protobuf.Timestamp');
+
+// CommonJS-LoadFromFile: google/protobuf/struct_pb proto.google.protobuf
+goog.require('proto.google.protobuf.Struct');
+
 
 var BYTES = new Uint8Array([1, 2, 8, 9]);
 var BYTES_B64 = goog.crypt.base64.encodeByteArray(BYTES);
@@ -326,4 +332,36 @@ describe('proto3Test', function() {
     assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES));
 
   });
+
+  it('testTimestampWellKnownType', function() {
+    var msg = new proto.google.protobuf.Timestamp();
+    msg.fromDate(new Date(123456789));
+    assertEquals(123456, msg.getSeconds());
+    assertEquals(789000000, msg.getNanos());
+    var date = msg.toDate();
+    assertEquals(123456789, date.getTime());
+  });
+
+  it('testStructWellKnownType', function() {
+    var jsObj = {
+      abc: "def",
+      number: 12345.678,
+      nullKey: null,
+      boolKey: true,
+      listKey: [1, null, true, false, "abc"],
+      structKey: {foo: "bar", somenum: 123},
+      complicatedKey: [{xyz: {abc: [3, 4, null, false]}}, "zzz"]
+    };
+
+    var struct = proto.google.protobuf.Struct.fromJavaScript(jsObj);
+    var jsObj2 = struct.toJavaScript();
+
+    assertEquals("def", jsObj2.abc);
+    assertEquals(12345.678, jsObj2.number);
+    assertEquals(null, jsObj2.nullKey);
+    assertEquals(true, jsObj2.boolKey);
+    assertEquals("abc", jsObj2.listKey[4]);
+    assertEquals("bar", jsObj2.structKey.foo);
+    assertEquals(4, jsObj2.complicatedKey[0].xyz.abc[1]);
+  });
 });

+ 3 - 0
js/test.proto

@@ -234,7 +234,9 @@ message TestEndsWithBytes {
   optional bytes data = 2;
 }
 
+
 message TestMapFieldsNoBinary {
+
   map<string, string> map_string_string = 1;
   map<string, int32> map_string_int32 = 2;
   map<string, int64> map_string_int64 = 3;
@@ -258,6 +260,7 @@ enum MapValueEnumNoBinary {
 }
 
 message MapValueMessageNoBinary {
+
   optional int32 foo = 1;
 }
 

+ 0 - 5
protobuf.bzl

@@ -1,5 +1,3 @@
-# -*- mode: python; -*- PYTHON-PREPROCESSING-REQUIRED
-
 def _GetPath(ctx, path):
   if ctx.label.workspace_root:
     return ctx.label.workspace_root + '/' + path
@@ -240,7 +238,6 @@ def cc_proto_library(
       includes=includes,
       **kargs)
 
-
 def internal_gen_well_known_protos_java(srcs):
   """Bazel rule to generate the gen_well_known_protos_java genrule
 
@@ -264,7 +261,6 @@ def internal_gen_well_known_protos_java(srcs):
     tools = [":protoc"],
   )
 
-
 def internal_copied_filegroup(name, srcs, strip_prefix, dest, **kwargs):
   """Macro to copy files to a different directory and then create a filegroup.
 
@@ -294,7 +290,6 @@ def internal_copied_filegroup(name, srcs, strip_prefix, dest, **kwargs):
       srcs = outs,
       **kwargs)
 
-
 def py_proto_library(
         name,
         srcs=[],

+ 99 - 0
python/google/protobuf/descriptor_pool.py

@@ -57,6 +57,8 @@ directly instead of this class.
 
 __author__ = 'matthewtoia@google.com (Matt Toia)'
 
+import collections
+
 from google.protobuf import descriptor
 from google.protobuf import descriptor_database
 from google.protobuf import text_encoding
@@ -88,6 +90,14 @@ def _OptionsOrNone(descriptor_proto):
     return None
 
 
+def _IsMessageSetExtension(field):
+  return (field.is_extension and
+          field.containing_type.has_options and
+          field.containing_type.GetOptions().message_set_wire_format and
+          field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and
+          field.label == descriptor.FieldDescriptor.LABEL_OPTIONAL)
+
+
 class DescriptorPool(object):
   """A collection of protobufs dynamically constructed by descriptor protos."""
 
@@ -115,6 +125,12 @@ class DescriptorPool(object):
     self._descriptors = {}
     self._enum_descriptors = {}
     self._file_descriptors = {}
+    self._toplevel_extensions = {}
+    # We store extensions in two two-level mappings: The first key is the
+    # descriptor of the message being extended, the second key is the extension
+    # full name or its tag number.
+    self._extensions_by_name = collections.defaultdict(dict)
+    self._extensions_by_number = collections.defaultdict(dict)
 
   def Add(self, file_desc_proto):
     """Adds the FileDescriptorProto and its types to this pool.
@@ -170,6 +186,48 @@ class DescriptorPool(object):
     self._enum_descriptors[enum_desc.full_name] = enum_desc
     self.AddFileDescriptor(enum_desc.file)
 
+  def AddExtensionDescriptor(self, extension):
+    """Adds a FieldDescriptor describing an extension to the pool.
+
+    Args:
+      extension: A FieldDescriptor.
+
+    Raises:
+      AssertionError: when another extension with the same number extends the
+        same message.
+      TypeError: when the specified extension is not a
+        descriptor.FieldDescriptor.
+    """
+    if not (isinstance(extension, descriptor.FieldDescriptor) and
+            extension.is_extension):
+      raise TypeError('Expected an extension descriptor.')
+
+    if extension.extension_scope is None:
+      self._toplevel_extensions[extension.full_name] = extension
+
+    try:
+      existing_desc = self._extensions_by_number[
+          extension.containing_type][extension.number]
+    except KeyError:
+      pass
+    else:
+      if extension is not existing_desc:
+        raise AssertionError(
+            'Extensions "%s" and "%s" both try to extend message type "%s" '
+            'with field number %d.' %
+            (extension.full_name, existing_desc.full_name,
+             extension.containing_type.full_name, extension.number))
+
+    self._extensions_by_number[extension.containing_type][
+        extension.number] = extension
+    self._extensions_by_name[extension.containing_type][
+        extension.full_name] = extension
+
+    # Also register MessageSet extensions with the type name.
+    if _IsMessageSetExtension(extension):
+      self._extensions_by_name[extension.containing_type][
+          extension.message_type.full_name] = extension
+
   def AddFileDescriptor(self, file_desc):
     """Adds a FileDescriptor to the pool, non-recursively.
 
@@ -302,6 +360,14 @@ class DescriptorPool(object):
       A FieldDescriptor, describing the named extension.
     """
     full_name = _NormalizeFullyQualifiedName(full_name)
+    try:
+      # The proto compiler does not give any link between the FileDescriptor
+      # and top-level extensions unless the FileDescriptorProto is added to
+      # the DescriptorDatabase, but this can impact memory usage.
+      # So we registered these extensions by name explicitly.
+      return self._toplevel_extensions[full_name]
+    except KeyError:
+      pass
     message_name, _, extension_name = full_name.rpartition('.')
     try:
       # Most extensions are nested inside a message.
@@ -311,6 +377,39 @@ class DescriptorPool(object):
       scope = self.FindFileContainingSymbol(full_name)
     return scope.extensions_by_name[extension_name]
 
+  def FindExtensionByNumber(self, message_descriptor, number):
+    """Gets the extension of the specified message with the specified number.
+
+    Extensions have to be registered to this pool by calling
+    AddExtensionDescriptor.
+
+    Args:
+      message_descriptor: descriptor of the extended message.
+      number: integer, number of the extension field.
+
+    Returns:
+      A FieldDescriptor describing the extension.
+
+    Raise:
+      KeyError: when no extension with the given number is known for the
+        specified message.
+    """
+    return self._extensions_by_number[message_descriptor][number]
+
+  def FindAllExtensions(self, message_descriptor):
+    """Gets all the known extension of a given message.
+
+    Extensions have to be registered to this pool by calling
+    AddExtensionDescriptor.
+
+    Args:
+      message_descriptor: descriptor of the extended message.
+
+    Returns:
+      A list of FieldDescriptor describing the extensions.
+    """
+    return list(self._extensions_by_number[message_descriptor].values())
+
   def _ConvertFileProtoToFileDescriptor(self, file_proto):
     """Creates a FileDescriptor from a proto or returns a cached copy.
 

+ 3 - 3
python/google/protobuf/internal/decoder.py

@@ -642,10 +642,10 @@ def MessageDecoder(field_number, is_repeated, is_packed, key, new_default):
 
 MESSAGE_SET_ITEM_TAG = encoder.TagBytes(1, wire_format.WIRETYPE_START_GROUP)
 
-def MessageSetItemDecoder(extensions_by_number):
+def MessageSetItemDecoder(descriptor):
   """Returns a decoder for a MessageSet item.
 
-  The parameter is the _extensions_by_number map for the message class.
+  The parameter is the message Descriptor.
 
   The message set message looks like this:
     message MessageSet {
@@ -694,7 +694,7 @@ def MessageSetItemDecoder(extensions_by_number):
     if message_start == -1:
       raise _DecodeError('MessageSet item missing message.')
 
-    extension = extensions_by_number.get(type_id)
+    extension = message.Extensions._FindExtensionByNumber(type_id)
     if extension is not None:
       value = field_dict.get(extension)
       if value is None:

+ 47 - 0
python/google/protobuf/internal/descriptor_pool_test.py

@@ -254,6 +254,53 @@ class DescriptorPoolTest(unittest.TestCase):
     with self.assertRaises(KeyError):
       self.pool.FindFieldByName('Does not exist')
 
+  def testFindAllExtensions(self):
+    factory1_message = self.pool.FindMessageTypeByName(
+        'google.protobuf.python.internal.Factory1Message')
+    factory2_message = self.pool.FindMessageTypeByName(
+        'google.protobuf.python.internal.Factory2Message')
+    # An extension defined in a message.
+    one_more_field = factory2_message.extensions_by_name['one_more_field']
+    self.pool.AddExtensionDescriptor(one_more_field)
+    # An extension defined at file scope.
+    factory_test2 = self.pool.FindFileByName(
+        'google/protobuf/internal/factory_test2.proto')
+    another_field = factory_test2.extensions_by_name['another_field']
+    self.pool.AddExtensionDescriptor(another_field)
+
+    extensions = self.pool.FindAllExtensions(factory1_message)
+    expected_extension_numbers = set([one_more_field, another_field])
+    self.assertEqual(expected_extension_numbers, set(extensions))
+    # Verify that mutating the returned list does not affect the pool.
+    extensions.append('unexpected_element')
+    # Get the extensions again, the returned value does not contain the
+    # 'unexpected_element'.
+    extensions = self.pool.FindAllExtensions(factory1_message)
+    self.assertEqual(expected_extension_numbers, set(extensions))
+
+  def testFindExtensionByNumber(self):
+    factory1_message = self.pool.FindMessageTypeByName(
+        'google.protobuf.python.internal.Factory1Message')
+    factory2_message = self.pool.FindMessageTypeByName(
+        'google.protobuf.python.internal.Factory2Message')
+    # An extension defined in a message.
+    one_more_field = factory2_message.extensions_by_name['one_more_field']
+    self.pool.AddExtensionDescriptor(one_more_field)
+    # An extension defined at file scope.
+    factory_test2 = self.pool.FindFileByName(
+        'google/protobuf/internal/factory_test2.proto')
+    another_field = factory_test2.extensions_by_name['another_field']
+    self.pool.AddExtensionDescriptor(another_field)
+
+    # An extension defined in a message.
+    extension = self.pool.FindExtensionByNumber(factory1_message, 1001)
+    self.assertEqual(extension.name, 'one_more_field')
+    # An extension defined at file scope.
+    extension = self.pool.FindExtensionByNumber(factory1_message, 1002)
+    self.assertEqual(extension.name, 'another_field')
+    with self.assertRaises(KeyError):
+      extension = self.pool.FindExtensionByNumber(factory1_message, 1234567)
+
   def testExtensionsAreNotFields(self):
     with self.assertRaises(KeyError):
       self.pool.FindFieldByName('google.protobuf.python.internal.another_field')

+ 10 - 10
python/google/protobuf/internal/message_factory_test.py

@@ -114,18 +114,18 @@ class MessageFactoryTest(unittest.TestCase):
              ).issubset(set(messages.keys())))
       self._ExerciseDynamicClass(
           messages['google.protobuf.python.internal.Factory2Message'])
-      self.assertTrue(
-          set(['google.protobuf.python.internal.Factory2Message.one_more_field',
-               'google.protobuf.python.internal.another_field'],
-             ).issubset(
-                 set(messages['google.protobuf.python.internal.Factory1Message']
-                     ._extensions_by_name.keys())))
       factory_msg1 = messages['google.protobuf.python.internal.Factory1Message']
+      self.assertTrue(set(
+          ['google.protobuf.python.internal.Factory2Message.one_more_field',
+           'google.protobuf.python.internal.another_field'],).issubset(set(
+               ext.full_name
+               for ext in factory_msg1.DESCRIPTOR.file.pool.FindAllExtensions(
+                   factory_msg1.DESCRIPTOR))))
       msg1 = messages['google.protobuf.python.internal.Factory1Message']()
-      ext1 = factory_msg1._extensions_by_name[
-          'google.protobuf.python.internal.Factory2Message.one_more_field']
-      ext2 = factory_msg1._extensions_by_name[
-          'google.protobuf.python.internal.another_field']
+      ext1 = msg1.Extensions._FindExtensionByName(
+          'google.protobuf.python.internal.Factory2Message.one_more_field')
+      ext2 = msg1.Extensions._FindExtensionByName(
+          'google.protobuf.python.internal.another_field')
       msg1.Extensions[ext1] = 'test1'
       msg1.Extensions[ext2] = 'test2'
       self.assertEqual('test1', msg1.Extensions[ext1])

+ 12 - 25
python/google/protobuf/internal/python_message.py

@@ -51,8 +51,8 @@ this file*.
 __author__ = 'robinson@google.com (Will Robinson)'
 
 from io import BytesIO
-import sys
 import struct
+import sys
 import weakref
 
 import six
@@ -162,12 +162,10 @@ class GeneratedProtocolMessageType(type):
     """
     descriptor = dictionary[GeneratedProtocolMessageType._DESCRIPTOR_KEY]
     cls._decoders_by_tag = {}
-    cls._extensions_by_name = {}
-    cls._extensions_by_number = {}
     if (descriptor.has_options and
         descriptor.GetOptions().message_set_wire_format):
       cls._decoders_by_tag[decoder.MESSAGE_SET_ITEM_TAG] = (
-          decoder.MessageSetItemDecoder(cls._extensions_by_number), None)
+          decoder.MessageSetItemDecoder(descriptor), None)
 
     # Attach stuff to each FieldDescriptor for quick lookup later on.
     for field in descriptor.fields:
@@ -747,32 +745,21 @@ def _AddPropertiesForExtensions(descriptor, cls):
     constant_name = extension_name.upper() + "_FIELD_NUMBER"
     setattr(cls, constant_name, extension_field.number)
 
+  # TODO(amauryfa): Migrate all users of these attributes to functions like
+  #   pool.FindExtensionByNumber(descriptor).
+  if descriptor.file is not None:
+    # TODO(amauryfa): Use cls.MESSAGE_FACTORY.pool when available.
+    pool = descriptor.file.pool
+    cls._extensions_by_number = pool._extensions_by_number[descriptor]
+    cls._extensions_by_name = pool._extensions_by_name[descriptor]
 
 def _AddStaticMethods(cls):
   # TODO(robinson): This probably needs to be thread-safe(?)
   def RegisterExtension(extension_handle):
     extension_handle.containing_type = cls.DESCRIPTOR
+    # TODO(amauryfa): Use cls.MESSAGE_FACTORY.pool when available.
+    cls.DESCRIPTOR.file.pool.AddExtensionDescriptor(extension_handle)
     _AttachFieldHelpers(cls, extension_handle)
-
-    # Try to insert our extension, failing if an extension with the same number
-    # already exists.
-    actual_handle = cls._extensions_by_number.setdefault(
-        extension_handle.number, extension_handle)
-    if actual_handle is not extension_handle:
-      raise AssertionError(
-          'Extensions "%s" and "%s" both try to extend message type "%s" with '
-          'field number %d.' %
-          (extension_handle.full_name, actual_handle.full_name,
-           cls.DESCRIPTOR.full_name, extension_handle.number))
-
-    cls._extensions_by_name[extension_handle.full_name] = extension_handle
-
-    handle = extension_handle  # avoid line wrapping
-    if _IsMessageSetExtension(handle):
-      # MessageSet extension.  Also register under type name.
-      cls._extensions_by_name[
-          extension_handle.message_type.full_name] = extension_handle
-
   cls.RegisterExtension = staticmethod(RegisterExtension)
 
   def FromString(s):
@@ -1230,7 +1217,7 @@ def _AddMergeFromMethod(cls):
     if not isinstance(msg, cls):
       raise TypeError(
           "Parameter to MergeFrom() must be instance of same class: "
-          "expected %s got %s." % (cls.__name__, type(msg).__name__))
+          'expected %s got %s.' % (cls.__name__, msg.__class__.__name__))
 
     assert msg is not self
     self._Modified()

+ 57 - 10
python/google/protobuf/internal/reflection_test.py

@@ -99,12 +99,12 @@ class _MiniDecoder(object):
     return wire_format.UnpackTag(self.ReadVarint())
 
   def ReadFloat(self):
-    result = struct.unpack("<f", self._bytes[self._pos:self._pos+4])[0]
+    result = struct.unpack('<f', self._bytes[self._pos:self._pos+4])[0]
     self._pos += 4
     return result
 
   def ReadDouble(self):
-    result = struct.unpack("<d", self._bytes[self._pos:self._pos+8])[0]
+    result = struct.unpack('<d', self._bytes[self._pos:self._pos+8])[0]
     self._pos += 8
     return result
 
@@ -621,9 +621,15 @@ class ReflectionTest(BaseTestCase):
     self.assertRaises(TypeError, setattr, proto, 'optional_string', 10)
     self.assertRaises(TypeError, setattr, proto, 'optional_bytes', 10)
 
-  def testIntegerTypes(self):
+  def assertIntegerTypes(self, integer_fn):
+    """Verifies setting of scalar integers.
+
+    Args:
+      integer_fn: A function to wrap the integers that will be assigned.
+    """
     def TestGetAndDeserialize(field_name, value, expected_type):
       proto = unittest_pb2.TestAllTypes()
+      value = integer_fn(value)
       setattr(proto, field_name, value)
       self.assertIsInstance(getattr(proto, field_name), expected_type)
       proto2 = unittest_pb2.TestAllTypes()
@@ -635,7 +641,7 @@ class ReflectionTest(BaseTestCase):
     TestGetAndDeserialize('optional_uint32', 1 << 30, int)
     try:
       integer_64 = long
-    except NameError: # Python3
+    except NameError:  # Python3
       integer_64 = int
     if struct.calcsize('L') == 4:
       # Python only has signed ints, so 32-bit python can't fit an uint32
@@ -649,9 +655,33 @@ class ReflectionTest(BaseTestCase):
     TestGetAndDeserialize('optional_uint64', 1 << 30, integer_64)
     TestGetAndDeserialize('optional_uint64', 1 << 60, integer_64)
 
-  def testSingleScalarBoundsChecking(self):
+  def testIntegerTypes(self):
+    self.assertIntegerTypes(lambda x: x)
+
+  def testNonStandardIntegerTypes(self):
+    self.assertIntegerTypes(test_util.NonStandardInteger)
+
+  def testIllegalValuesForIntegers(self):
+    pb = unittest_pb2.TestAllTypes()
+
+    # Strings are illegal, even when the represent an integer.
+    with self.assertRaises(TypeError):
+      pb.optional_uint64 = '2'
+
+    # The exact error should propagate with a poorly written custom integer.
+    with self.assertRaisesRegexp(RuntimeError, 'my_error'):
+      pb.optional_uint64 = test_util.NonStandardInteger(5, 'my_error')
+
+  def assetIntegerBoundsChecking(self, integer_fn):
+    """Verifies bounds checking for scalar integer fields.
+
+    Args:
+      integer_fn: A function to wrap the integers that will be assigned.
+    """
     def TestMinAndMaxIntegers(field_name, expected_min, expected_max):
       pb = unittest_pb2.TestAllTypes()
+      expected_min = integer_fn(expected_min)
+      expected_max = integer_fn(expected_max)
       setattr(pb, field_name, expected_min)
       self.assertEqual(expected_min, getattr(pb, field_name))
       setattr(pb, field_name, expected_max)
@@ -663,11 +693,22 @@ class ReflectionTest(BaseTestCase):
     TestMinAndMaxIntegers('optional_uint32', 0, 0xffffffff)
     TestMinAndMaxIntegers('optional_int64', -(1 << 63), (1 << 63) - 1)
     TestMinAndMaxIntegers('optional_uint64', 0, 0xffffffffffffffff)
+    # A bit of white-box testing since -1 is an int and not a long in C++ and
+    # so goes down a different path.
+    pb = unittest_pb2.TestAllTypes()
+    with self.assertRaises(ValueError):
+      pb.optional_uint64 = integer_fn(-(1 << 63))
 
     pb = unittest_pb2.TestAllTypes()
-    pb.optional_nested_enum = 1
+    pb.optional_nested_enum = integer_fn(1)
     self.assertEqual(1, pb.optional_nested_enum)
 
+  def testSingleScalarBoundsChecking(self):
+    self.assetIntegerBoundsChecking(lambda x: x)
+
+  def testNonStandardSingleScalarBoundsChecking(self):
+    self.assetIntegerBoundsChecking(test_util.NonStandardInteger)
+
   def testRepeatedScalarTypeSafety(self):
     proto = unittest_pb2.TestAllTypes()
     self.assertRaises(TypeError, proto.repeated_int32.append, 1.1)
@@ -1187,12 +1228,18 @@ class ReflectionTest(BaseTestCase):
     self.assertTrue(not extendee_proto.HasExtension(extension))
 
   def testRegisteredExtensions(self):
-    self.assertTrue('protobuf_unittest.optional_int32_extension' in
-                    unittest_pb2.TestAllExtensions._extensions_by_name)
-    self.assertTrue(1 in unittest_pb2.TestAllExtensions._extensions_by_number)
+    pool = unittest_pb2.DESCRIPTOR.pool
+    self.assertTrue(
+        pool.FindExtensionByNumber(
+            unittest_pb2.TestAllExtensions.DESCRIPTOR, 1))
+    self.assertIs(
+        pool.FindExtensionByName(
+            'protobuf_unittest.optional_int32_extension').containing_type,
+        unittest_pb2.TestAllExtensions.DESCRIPTOR)
     # Make sure extensions haven't been registered into types that shouldn't
     # have any.
-    self.assertEqual(0, len(unittest_pb2.TestAllTypes._extensions_by_name))
+    self.assertEqual(0, len(
+        pool.FindAllExtensions(unittest_pb2.TestAllTypes.DESCRIPTOR)))
 
   # If message A directly contains message B, and
   # a.HasField('b') is currently False, then mutating any

+ 153 - 1
python/google/protobuf/internal/test_util.py

@@ -36,8 +36,9 @@ This is intentionally modeled on C++ code in
 
 __author__ = 'robinson@google.com (Will Robinson)'
 
+import numbers
+import operator
 import os.path
-
 import sys
 
 from google.protobuf import unittest_import_pb2
@@ -694,3 +695,154 @@ def SetAllUnpackedFields(message):
   message.unpacked_bool.extend([True, False])
   message.unpacked_enum.extend([unittest_pb2.FOREIGN_BAR,
                                 unittest_pb2.FOREIGN_BAZ])
+
+
+class NonStandardInteger(numbers.Integral):
+  """An integer object that does not subclass int.
+
+  This is used to verify that both C++ and regular proto systems can handle
+  integer others than int and long and that they handle them in predictable
+  ways.
+
+  NonStandardInteger is the minimal legal specification for a custom Integral.
+  As such, it does not support 0 < x < 5 and it is not hashable.
+
+  Note: This is added here instead of relying on numpy or a similar library with
+  custom integers to limit dependencies.
+  """
+
+  def __init__(self, val, error_string_on_conversion=None):
+    assert isinstance(val, numbers.Integral)
+    if isinstance(val, NonStandardInteger):
+      val = val.val
+    self.val = val
+    self.error_string_on_conversion = error_string_on_conversion
+
+  def __long__(self):
+    if self.error_string_on_conversion:
+      raise RuntimeError(self.error_string_on_conversion)
+    return long(self.val)
+
+  def __abs__(self):
+    return NonStandardInteger(operator.abs(self.val))
+
+  def __add__(self, y):
+    return NonStandardInteger(operator.add(self.val, y))
+
+  def __div__(self, y):
+    return NonStandardInteger(operator.div(self.val, y))
+
+  def __eq__(self, y):
+    return operator.eq(self.val, y)
+
+  def __floordiv__(self, y):
+    return NonStandardInteger(operator.floordiv(self.val, y))
+
+  def __truediv__(self, y):
+    return NonStandardInteger(operator.truediv(self.val, y))
+
+  def __invert__(self):
+    return NonStandardInteger(operator.invert(self.val))
+
+  def __mod__(self, y):
+    return NonStandardInteger(operator.mod(self.val, y))
+
+  def __mul__(self, y):
+    return NonStandardInteger(operator.mul(self.val, y))
+
+  def __neg__(self):
+    return NonStandardInteger(operator.neg(self.val))
+
+  def __pos__(self):
+    return NonStandardInteger(operator.pos(self.val))
+
+  def __pow__(self, y):
+    return NonStandardInteger(operator.pow(self.val, y))
+
+  def __trunc__(self):
+    return int(self.val)
+
+  def __radd__(self, y):
+    return NonStandardInteger(operator.add(y, self.val))
+
+  def __rdiv__(self, y):
+    return NonStandardInteger(operator.div(y, self.val))
+
+  def __rmod__(self, y):
+    return NonStandardInteger(operator.mod(y, self.val))
+
+  def __rmul__(self, y):
+    return NonStandardInteger(operator.mul(y, self.val))
+
+  def __rpow__(self, y):
+    return NonStandardInteger(operator.pow(y, self.val))
+
+  def __rfloordiv__(self, y):
+    return NonStandardInteger(operator.floordiv(y, self.val))
+
+  def __rtruediv__(self, y):
+    return NonStandardInteger(operator.truediv(y, self.val))
+
+  def __lshift__(self, y):
+    return NonStandardInteger(operator.lshift(self.val, y))
+
+  def __rshift__(self, y):
+    return NonStandardInteger(operator.rshift(self.val, y))
+
+  def __rlshift__(self, y):
+    return NonStandardInteger(operator.lshift(y, self.val))
+
+  def __rrshift__(self, y):
+    return NonStandardInteger(operator.rshift(y, self.val))
+
+  def __le__(self, y):
+    if isinstance(y, NonStandardInteger):
+      y = y.val
+    return operator.le(self.val, y)
+
+  def __lt__(self, y):
+    if isinstance(y, NonStandardInteger):
+      y = y.val
+    return operator.lt(self.val, y)
+
+  def __and__(self, y):
+    return NonStandardInteger(operator.and_(self.val, y))
+
+  def __or__(self, y):
+    return NonStandardInteger(operator.or_(self.val, y))
+
+  def __xor__(self, y):
+    return NonStandardInteger(operator.xor(self.val, y))
+
+  def __rand__(self, y):
+    return NonStandardInteger(operator.and_(y, self.val))
+
+  def __ror__(self, y):
+    return NonStandardInteger(operator.or_(y, self.val))
+
+  def __rxor__(self, y):
+    return NonStandardInteger(operator.xor(y, self.val))
+
+  def __bool__(self):
+    return self.val
+
+  def __nonzero__(self):
+    return self.val
+
+  def __ceil__(self):
+    return self
+
+  def __floor__(self):
+    return self
+
+  def __int__(self):
+    if self.error_string_on_conversion:
+      raise RuntimeError(self.error_string_on_conversion)
+    return int(self.val)
+
+  def __round__(self):
+    return self
+
+  def __repr__(self):
+    return 'NonStandardInteger(%s)' % self.val
+

+ 0 - 2
python/google/protobuf/internal/testing_refleaks.py

@@ -124,5 +124,3 @@ else:
     def Same(func):
       return func
     return Same
-
-

+ 14 - 16
python/google/protobuf/internal/text_format_test.py

@@ -582,22 +582,20 @@ class OnlyWorksWithProto2RightNowTests(TextFormatBase):
                       % (letter,) for letter in string.ascii_uppercase))
     self.CompareToGoldenText(text_format.MessageToString(message), golden)
 
-  def testMapOrderSemantics(self):
-    golden_lines = self.ReadGolden('map_test_data.txt')
-    # The C++ implementation emits defaulted-value fields, while the Python
-    # implementation does not.  Adjusting for this is awkward, but it is
-    # valuable to test against a common golden file.
-    line_blacklist = ('  key: 0\n', '  value: 0\n', '  key: false\n',
-                      '  value: false\n')
-    golden_lines = [line for line in golden_lines if line not in line_blacklist]
-
-    message = map_unittest_pb2.TestMap()
-    text_format.ParseLines(golden_lines, message)
-    candidate = text_format.MessageToString(message)
-    # The Python implementation emits "1.0" for the double value that the C++
-    # implementation emits as "1".
-    candidate = candidate.replace('1.0', '1', 2)
-    self.assertMultiLineEqual(candidate, ''.join(golden_lines))
+  # TODO(teboring): In c/137553523, not serializing default value for map entry
+  # message has been fixed. This test needs to be disabled in order to submit
+  # that cl. Add this back when c/137553523 has been submitted.
+  # def testMapOrderSemantics(self):
+  #   golden_lines = self.ReadGolden('map_test_data.txt')
+
+  #   message = map_unittest_pb2.TestMap()
+  #   text_format.ParseLines(golden_lines, message)
+  #   candidate = text_format.MessageToString(message)
+  #   # The Python implementation emits "1.0" for the double value that the C++
+  #   # implementation emits as "1".
+  #   candidate = candidate.replace('1.0', '1', 2)
+  #   candidate = candidate.replace('0.0', '0', 2)
+  #   self.assertMultiLineEqual(candidate, ''.join(golden_lines))
 
 
 # Tests of proto2-only features (MessageSet, extensions, etc.).

+ 8 - 7
python/google/protobuf/internal/type_checkers.py

@@ -45,6 +45,7 @@ TYPE_TO_DESERIALIZE_METHOD: A dictionary with field types and deserialization
 
 __author__ = 'robinson@google.com (Will Robinson)'
 
+import numbers
 import six
 
 if six.PY3:
@@ -126,11 +127,11 @@ class IntValueChecker(object):
   """Checker used for integer fields.  Performs type-check and range check."""
 
   def CheckValue(self, proposed_value):
-    if not isinstance(proposed_value, six.integer_types):
+    if not isinstance(proposed_value, numbers.Integral):
       message = ('%.1024r has type %s, but expected one of: %s' %
                  (proposed_value, type(proposed_value), six.integer_types))
       raise TypeError(message)
-    if not self._MIN <= proposed_value <= self._MAX:
+    if not self._MIN <= int(proposed_value) <= self._MAX:
       raise ValueError('Value out of range: %d' % proposed_value)
     # We force 32-bit values to int and 64-bit values to long to make
     # alternate implementations where the distinction is more significant
@@ -150,11 +151,11 @@ class EnumValueChecker(object):
     self._enum_type = enum_type
 
   def CheckValue(self, proposed_value):
-    if not isinstance(proposed_value, six.integer_types):
+    if not isinstance(proposed_value, numbers.Integral):
       message = ('%.1024r has type %s, but expected one of: %s' %
                  (proposed_value, type(proposed_value), six.integer_types))
       raise TypeError(message)
-    if proposed_value not in self._enum_type.values_by_number:
+    if int(proposed_value) not in self._enum_type.values_by_number:
       raise ValueError('Unknown enum value: %d' % proposed_value)
     return proposed_value
 
@@ -223,11 +224,11 @@ _VALUE_CHECKERS = {
     _FieldDescriptor.CPPTYPE_UINT32: Uint32ValueChecker(),
     _FieldDescriptor.CPPTYPE_UINT64: Uint64ValueChecker(),
     _FieldDescriptor.CPPTYPE_DOUBLE: TypeCheckerWithDefault(
-        0.0, float, int, long),
+        0.0, numbers.Real),
     _FieldDescriptor.CPPTYPE_FLOAT: TypeCheckerWithDefault(
-        0.0, float, int, long),
+        0.0, numbers.Real),
     _FieldDescriptor.CPPTYPE_BOOL: TypeCheckerWithDefault(
-        False, bool, int),
+        False, bool, numbers.Integral),
     _FieldDescriptor.CPPTYPE_STRING: TypeCheckerWithDefault(b'', bytes),
     }
 

+ 2 - 2
python/google/protobuf/json_format.py

@@ -43,9 +43,9 @@ Simple usage example:
 __author__ = 'jieluo@google.com (Jie Luo)'
 
 try:
-    from collections import OrderedDict
+  from collections import OrderedDict
 except ImportError:
-    from ordereddict import OrderedDict  #PY26
+  from ordereddict import OrderedDict  #PY26
 import base64
 import json
 import math

+ 67 - 0
python/google/protobuf/pyext/descriptor_pool.cc

@@ -319,6 +319,51 @@ PyObject* FindFileContainingSymbol(PyDescriptorPool* self, PyObject* arg) {
   return PyFileDescriptor_FromDescriptor(file_descriptor);
 }
 
+PyObject* FindExtensionByNumber(PyDescriptorPool* self, PyObject* args) {
+  PyObject* message_descriptor;
+  int number;
+  if (!PyArg_ParseTuple(args, "Oi", &message_descriptor, &number)) {
+    return NULL;
+  }
+  const Descriptor* descriptor = PyMessageDescriptor_AsDescriptor(
+      message_descriptor);
+  if (descriptor == NULL) {
+    return NULL;
+  }
+
+  const FieldDescriptor* extension_descriptor =
+      self->pool->FindExtensionByNumber(descriptor, number);
+  if (extension_descriptor == NULL) {
+    PyErr_Format(PyExc_KeyError, "Couldn't find extension %d", number);
+    return NULL;
+  }
+
+  return PyFieldDescriptor_FromDescriptor(extension_descriptor);
+}
+
+PyObject* FindAllExtensions(PyDescriptorPool* self, PyObject* arg) {
+  const Descriptor* descriptor = PyMessageDescriptor_AsDescriptor(arg);
+  if (descriptor == NULL) {
+    return NULL;
+  }
+
+  std::vector<const FieldDescriptor*> extensions;
+  self->pool->FindAllExtensions(descriptor, &extensions);
+
+  ScopedPyObjectPtr result(PyList_New(extensions.size()));
+  if (result == NULL) {
+    return NULL;
+  }
+  for (int i = 0; i < extensions.size(); i++) {
+    PyObject* extension = PyFieldDescriptor_FromDescriptor(extensions[i]);
+    if (extension == NULL) {
+      return NULL;
+    }
+    PyList_SET_ITEM(result.get(), i, extension);  // Steals the reference.
+  }
+  return result.release();
+}
+
 // These functions should not exist -- the only valid way to create
 // descriptors is to call Add() or AddSerializedFile().
 // But these AddDescriptor() functions were created in Python and some people
@@ -376,6 +421,22 @@ PyObject* AddEnumDescriptor(PyDescriptorPool* self, PyObject* descriptor) {
   Py_RETURN_NONE;
 }
 
+PyObject* AddExtensionDescriptor(PyDescriptorPool* self, PyObject* descriptor) {
+  const FieldDescriptor* extension_descriptor =
+      PyFieldDescriptor_AsDescriptor(descriptor);
+  if (!extension_descriptor) {
+    return NULL;
+  }
+  if (extension_descriptor !=
+      self->pool->FindExtensionByName(extension_descriptor->full_name())) {
+    PyErr_Format(PyExc_ValueError,
+                 "The extension descriptor %s does not belong to this pool",
+                 extension_descriptor->full_name().c_str());
+    return NULL;
+  }
+  Py_RETURN_NONE;
+}
+
 // The code below loads new Descriptors from a serialized FileDescriptorProto.
 
 
@@ -475,6 +536,8 @@ static PyMethodDef Methods[] = {
     "No-op. Add() must have been called before." },
   { "AddEnumDescriptor", (PyCFunction)AddEnumDescriptor, METH_O,
     "No-op. Add() must have been called before." },
+  { "AddExtensionDescriptor", (PyCFunction)AddExtensionDescriptor, METH_O,
+    "No-op. Add() must have been called before." },
 
   { "FindFileByName", (PyCFunction)FindFileByName, METH_O,
     "Searches for a file descriptor by its .proto name." },
@@ -495,6 +558,10 @@ static PyMethodDef Methods[] = {
 
   { "FindFileContainingSymbol", (PyCFunction)FindFileContainingSymbol, METH_O,
     "Gets the FileDescriptor containing the specified symbol." },
+  { "FindExtensionByNumber", (PyCFunction)FindExtensionByNumber, METH_VARARGS,
+    "Gets the extension descriptor for the given number." },
+  { "FindAllExtensions", (PyCFunction)FindAllExtensions, METH_O,
+    "Gets all known extensions of the given message descriptor." },
   {NULL}
 };
 

+ 58 - 19
python/google/protobuf/pyext/extension_dict.cc

@@ -38,6 +38,7 @@
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/message.h>
+#include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/pyext/descriptor.h>
 #include <google/protobuf/pyext/message.h>
 #include <google/protobuf/pyext/message_factory.h>
@@ -46,6 +47,16 @@
 #include <google/protobuf/pyext/scoped_pyobject_ptr.h>
 #include <google/protobuf/stubs/shared_ptr.h>
 
+#if PY_MAJOR_VERSION >= 3
+  #if PY_VERSION_HEX < 0x03030000
+    #error "Python 3.0 - 3.2 are not supported."
+  #endif
+  #define PyString_AsStringAndSize(ob, charpp, sizep) \
+    (PyUnicode_Check(ob)? \
+       ((*(charpp) = PyUnicode_AsUTF8AndSize(ob, (sizep))) == NULL? -1: 0): \
+       PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
+#endif
+
 namespace google {
 namespace protobuf {
 namespace python {
@@ -90,6 +101,7 @@ PyObject* subscript(ExtensionDict* self, PyObject* key) {
 
   if (descriptor->label() != FieldDescriptor::LABEL_REPEATED &&
       descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+    // TODO(plabatut): consider building the class on the fly!
     PyObject* sub_message = cmessage::InternalGetSubMessage(
         self->parent, descriptor);
     if (sub_message == NULL) {
@@ -101,7 +113,17 @@ PyObject* subscript(ExtensionDict* self, PyObject* key) {
 
   if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
     if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
-      CMessageClass* message_class = message_factory::GetMessageClass(
+      // On the fly message class creation is needed to support the following
+      // situation:
+      // 1- add FileDescriptor to the pool that contains extensions of a message
+      //    defined by another proto file. Do not create any message classes.
+      // 2- instantiate an extended message, and access the extension using
+      //    the field descriptor.
+      // 3- the extension submessage fails to be returned, because no class has
+      //    been created.
+      // It happens when deserializing text proto format, or when enumerating
+      // fields of a deserialized message.
+      CMessageClass* message_class = message_factory::GetOrCreateMessageClass(
           cmessage::GetFactoryForMessage(self->parent),
           descriptor->message_type());
       if (message_class == NULL) {
@@ -154,34 +176,51 @@ int ass_subscript(ExtensionDict* self, PyObject* key, PyObject* value) {
   return 0;
 }
 
-PyObject* _FindExtensionByName(ExtensionDict* self, PyObject* name) {
-  ScopedPyObjectPtr extensions_by_name(PyObject_GetAttrString(
-      reinterpret_cast<PyObject*>(self->parent), "_extensions_by_name"));
-  if (extensions_by_name == NULL) {
+PyObject* _FindExtensionByName(ExtensionDict* self, PyObject* arg) {
+  char* name;
+  Py_ssize_t name_size;
+  if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
     return NULL;
   }
-  PyObject* result = PyDict_GetItem(extensions_by_name.get(), name);
-  if (result == NULL) {
+
+  PyDescriptorPool* pool = cmessage::GetFactoryForMessage(self->parent)->pool;
+  const FieldDescriptor* message_extension =
+      pool->pool->FindExtensionByName(string(name, name_size));
+  if (message_extension == NULL) {
+    // Is is the name of a message set extension?
+    const Descriptor* message_descriptor = pool->pool->FindMessageTypeByName(
+        string(name, name_size));
+    if (message_descriptor && message_descriptor->extension_count() > 0) {
+      const FieldDescriptor* extension = message_descriptor->extension(0);
+      if (extension->is_extension() &&
+          extension->containing_type()->options().message_set_wire_format() &&
+          extension->type() == FieldDescriptor::TYPE_MESSAGE &&
+          extension->label() == FieldDescriptor::LABEL_OPTIONAL) {
+        message_extension = extension;
+      }
+    }
+  }
+  if (message_extension == NULL) {
     Py_RETURN_NONE;
-  } else {
-    Py_INCREF(result);
-    return result;
   }
+
+  return PyFieldDescriptor_FromDescriptor(message_extension);
 }
 
-PyObject* _FindExtensionByNumber(ExtensionDict* self, PyObject* number) {
-  ScopedPyObjectPtr extensions_by_number(PyObject_GetAttrString(
-      reinterpret_cast<PyObject*>(self->parent), "_extensions_by_number"));
-  if (extensions_by_number == NULL) {
+PyObject* _FindExtensionByNumber(ExtensionDict* self, PyObject* arg) {
+  int64 number = PyLong_AsLong(arg);
+  if (number == -1 && PyErr_Occurred()) {
     return NULL;
   }
-  PyObject* result = PyDict_GetItem(extensions_by_number.get(), number);
-  if (result == NULL) {
+
+  PyDescriptorPool* pool = cmessage::GetFactoryForMessage(self->parent)->pool;
+  const FieldDescriptor* message_extension = pool->pool->FindExtensionByNumber(
+      self->parent->message->GetDescriptor(), number);
+  if (message_extension == NULL) {
     Py_RETURN_NONE;
-  } else {
-    Py_INCREF(result);
-    return result;
   }
+
+  return PyFieldDescriptor_FromDescriptor(message_extension);
 }
 
 ExtensionDict* NewExtensionDict(CMessage *parent) {

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

@@ -374,7 +374,7 @@ static int InitializeAndCopyToParentContainer(MapContainer* from,
     // A somewhat roundabout way of copying just one field from old_message to
     // new_message.  This is the best we can do with what Reflection gives us.
     Message* mutable_old = from->GetMutableMessage();
-    vector<const FieldDescriptor*> fields;
+    std::vector<const FieldDescriptor*> fields;
     fields.push_back(from->parent_field_descriptor);
 
     // Move the map field into the new message.

+ 205 - 204
python/google/protobuf/pyext/message.cc

@@ -64,11 +64,11 @@
 #include <google/protobuf/pyext/repeated_scalar_container.h>
 #include <google/protobuf/pyext/map_container.h>
 #include <google/protobuf/pyext/message_factory.h>
+#include <google/protobuf/pyext/safe_numerics.h>
 #include <google/protobuf/pyext/scoped_pyobject_ptr.h>
 #include <google/protobuf/stubs/strutil.h>
 
 #if PY_MAJOR_VERSION >= 3
-  #define PyInt_Check PyLong_Check
   #define PyInt_AsLong PyLong_AsLong
   #define PyInt_FromLong PyLong_FromLong
   #define PyInt_FromSize_t PyLong_FromSize_t
@@ -92,8 +92,6 @@ namespace protobuf {
 namespace python {
 
 static PyObject* kDESCRIPTOR;
-static PyObject* k_extensions_by_name;
-static PyObject* k_extensions_by_number;
 PyObject* EnumTypeWrapper_class;
 static PyObject* PythonMessage_class;
 static PyObject* kEmptyWeakref;
@@ -128,19 +126,6 @@ static bool AddFieldNumberToClass(
 
 // Finalize the creation of the Message class.
 static int AddDescriptors(PyObject* cls, const Descriptor* descriptor) {
-  // If there are extension_ranges, the message is "extendable", and extension
-  // classes will register themselves in this class.
-  if (descriptor->extension_range_count() > 0) {
-    ScopedPyObjectPtr by_name(PyDict_New());
-    if (PyObject_SetAttr(cls, k_extensions_by_name, by_name.get()) < 0) {
-      return -1;
-    }
-    ScopedPyObjectPtr by_number(PyDict_New());
-    if (PyObject_SetAttr(cls, k_extensions_by_number, by_number.get()) < 0) {
-      return -1;
-    }
-  }
-
   // For each field set: cls.<field>_FIELD_NUMBER = <number>
   for (int i = 0; i < descriptor->field_count(); ++i) {
     if (!AddFieldNumberToClass(cls, descriptor->field(i))) {
@@ -357,6 +342,61 @@ static int InsertEmptyWeakref(PyTypeObject *base_type) {
 #endif  // PY_MAJOR_VERSION >= 3
 }
 
+// The _extensions_by_name dictionary is built on every access.
+// TODO(amauryfa): Migrate all users to pool.FindAllExtensions()
+static PyObject* GetExtensionsByName(CMessageClass *self, void *closure) {
+  const PyDescriptorPool* pool = self->py_message_factory->pool;
+
+  std::vector<const FieldDescriptor*> extensions;
+  pool->pool->FindAllExtensions(self->message_descriptor, &extensions);
+
+  ScopedPyObjectPtr result(PyDict_New());
+  for (int i = 0; i < extensions.size(); i++) {
+    ScopedPyObjectPtr extension(
+        PyFieldDescriptor_FromDescriptor(extensions[i]));
+    if (extension == NULL) {
+      return NULL;
+    }
+    if (PyDict_SetItemString(result.get(), extensions[i]->full_name().c_str(),
+                             extension.get()) < 0) {
+      return NULL;
+    }
+  }
+  return result.release();
+}
+
+// The _extensions_by_number dictionary is built on every access.
+// TODO(amauryfa): Migrate all users to pool.FindExtensionByNumber()
+static PyObject* GetExtensionsByNumber(CMessageClass *self, void *closure) {
+  const PyDescriptorPool* pool = self->py_message_factory->pool;
+
+  std::vector<const FieldDescriptor*> extensions;
+  pool->pool->FindAllExtensions(self->message_descriptor, &extensions);
+
+  ScopedPyObjectPtr result(PyDict_New());
+  for (int i = 0; i < extensions.size(); i++) {
+    ScopedPyObjectPtr extension(
+        PyFieldDescriptor_FromDescriptor(extensions[i]));
+    if (extension == NULL) {
+      return NULL;
+    }
+    ScopedPyObjectPtr number(PyInt_FromLong(extensions[i]->number()));
+    if (number == NULL) {
+      return NULL;
+    }
+    if (PyDict_SetItem(result.get(), number.get(), extension.get()) < 0) {
+      return NULL;
+    }
+  }
+  return result.release();
+}
+
+static PyGetSetDef Getters[] = {
+  {"_extensions_by_name", (getter)GetExtensionsByName, NULL},
+  {"_extensions_by_number", (getter)GetExtensionsByNumber, NULL},
+  {NULL}
+};
+
 }  // namespace message_meta
 
 PyTypeObject CMessageClass_Type = {
@@ -389,7 +429,7 @@ PyTypeObject CMessageClass_Type = {
   0,                                   // tp_iternext
   0,                                   // tp_methods
   0,                                   // tp_members
-  0,                                   // tp_getset
+  message_meta::Getters,               // tp_getset
   0,                                   // tp_base
   0,                                   // tp_dict
   0,                                   // tp_descr_get
@@ -525,23 +565,10 @@ int ForEachCompositeField(CMessage* self, Visitor visitor) {
 
 // ---------------------------------------------------------------------
 
-// Constants used for integer type range checking.
-PyObject* kPythonZero;
-PyObject* kint32min_py;
-PyObject* kint32max_py;
-PyObject* kuint32max_py;
-PyObject* kint64min_py;
-PyObject* kint64max_py;
-PyObject* kuint64max_py;
-
 PyObject* EncodeError_class;
 PyObject* DecodeError_class;
 PyObject* PickleError_class;
 
-// Constant PyString values used for GetAttr/GetItem.
-static PyObject* k_cdescriptor;
-static PyObject* kfull_name;
-
 /* Is 64bit */
 void FormatTypeError(PyObject* arg, char* expected_types) {
   PyObject* repr = PyObject_Repr(arg);
@@ -555,68 +582,126 @@ void FormatTypeError(PyObject* arg, char* expected_types) {
   }
 }
 
-template<class T>
-bool CheckAndGetInteger(
-    PyObject* arg, T* value, PyObject* min, PyObject* max) {
-  bool is_long = PyLong_Check(arg);
-#if PY_MAJOR_VERSION < 3
-  if (!PyInt_Check(arg) && !is_long) {
-    FormatTypeError(arg, "int, long");
-    return false;
+void OutOfRangeError(PyObject* arg) {
+  PyObject *s = PyObject_Str(arg);
+  if (s) {
+    PyErr_Format(PyExc_ValueError,
+                 "Value out of range: %s",
+                 PyString_AsString(s));
+    Py_DECREF(s);
   }
-  if (PyObject_Compare(min, arg) > 0 || PyObject_Compare(max, arg) < 0) {
-#else
-  if (!is_long) {
-    FormatTypeError(arg, "int");
+}
+
+template<class RangeType, class ValueType>
+bool VerifyIntegerCastAndRange(PyObject* arg, ValueType value) {
+  if GOOGLE_PREDICT_FALSE(value == -1 && PyErr_Occurred()) {
+    if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
+      // Replace it with the same ValueError as pure python protos instead of
+      // the default one.
+      PyErr_Clear();
+      OutOfRangeError(arg);
+    }  // Otherwise propagate existing error.
     return false;
   }
-  if (PyObject_RichCompareBool(min, arg, Py_LE) != 1 ||
-      PyObject_RichCompareBool(max, arg, Py_GE) != 1) {
-#endif
-    if (!PyErr_Occurred()) {
-      PyObject *s = PyObject_Str(arg);
-      if (s) {
-        PyErr_Format(PyExc_ValueError,
-                     "Value out of range: %s",
-                     PyString_AsString(s));
-        Py_DECREF(s);
-      }
-    }
+  if GOOGLE_PREDICT_FALSE(!IsValidNumericCast<RangeType>(value)) {
+    OutOfRangeError(arg);
     return false;
   }
+  return true;
+}
+
+template<class T>
+bool CheckAndGetInteger(PyObject* arg, T* value) {
+  // The fast path.
 #if PY_MAJOR_VERSION < 3
-  if (!is_long) {
-    *value = static_cast<T>(PyInt_AsLong(arg));
-  } else  // NOLINT
+  // For the typical case, offer a fast path.
+  if GOOGLE_PREDICT_TRUE(PyInt_Check(arg)) {
+    long int_result =  PyInt_AsLong(arg);
+    if GOOGLE_PREDICT_TRUE(IsValidNumericCast<T>(int_result)) {
+      *value = static_cast<T>(int_result);
+      return true;
+    } else {
+      OutOfRangeError(arg);
+      return false;
+    }
+  }
 #endif
-  {
-    if (min == kPythonZero) {
-      *value = static_cast<T>(PyLong_AsUnsignedLongLong(arg));
+  // This effectively defines an integer as "an object that can be cast as
+  // an integer and can be used as an ordinal number".
+  // This definition includes everything that implements numbers.Integral
+  // and shouldn't cast the net too wide.
+  if GOOGLE_PREDICT_FALSE(!PyIndex_Check(arg)) {
+    FormatTypeError(arg, "int, long");
+    return false;
+  }
+
+  // Now we have an integral number so we can safely use PyLong_ functions.
+  // We need to treat the signed and unsigned cases differently in case arg is
+  // holding a value above the maximum for signed longs.
+  if (std::numeric_limits<T>::min() == 0) {
+    // Unsigned case.
+    unsigned PY_LONG_LONG ulong_result;
+    if (PyLong_Check(arg)) {
+      ulong_result = PyLong_AsUnsignedLongLong(arg);
+    } else {
+      // Unlike PyLong_AsLongLong, PyLong_AsUnsignedLongLong is very
+      // picky about the exact type.
+      PyObject* casted = PyNumber_Long(arg);
+      if GOOGLE_PREDICT_FALSE(casted == NULL) {
+        // Propagate existing error.
+        return false;
+      }
+      ulong_result = PyLong_AsUnsignedLongLong(casted);
+      Py_DECREF(casted);
+    }
+    if (VerifyIntegerCastAndRange<T, unsigned PY_LONG_LONG>(arg,
+                                                            ulong_result)) {
+      *value = static_cast<T>(ulong_result);
+    } else {
+      return false;
+    }
+  } else {
+    // Signed case.
+    PY_LONG_LONG long_result;
+    PyNumberMethods *nb;
+    if ((nb = arg->ob_type->tp_as_number) != NULL && nb->nb_int != NULL) {
+      // PyLong_AsLongLong requires it to be a long or to have an __int__()
+      // method.
+      long_result = PyLong_AsLongLong(arg);
     } else {
-      *value = static_cast<T>(PyLong_AsLongLong(arg));
+      // Valid subclasses of numbers.Integral should have a __long__() method
+      // so fall back to that.
+      PyObject* casted = PyNumber_Long(arg);
+      if GOOGLE_PREDICT_FALSE(casted == NULL) {
+        // Propagate existing error.
+        return false;
+      }
+      long_result = PyLong_AsLongLong(casted);
+      Py_DECREF(casted);
+    }
+    if (VerifyIntegerCastAndRange<T, PY_LONG_LONG>(arg, long_result)) {
+      *value = static_cast<T>(long_result);
+    } else {
+      return false;
     }
   }
+
   return true;
 }
 
 // These are referenced by repeated_scalar_container, and must
 // be explicitly instantiated.
-template bool CheckAndGetInteger<int32>(
-    PyObject*, int32*, PyObject*, PyObject*);
-template bool CheckAndGetInteger<int64>(
-    PyObject*, int64*, PyObject*, PyObject*);
-template bool CheckAndGetInteger<uint32>(
-    PyObject*, uint32*, PyObject*, PyObject*);
-template bool CheckAndGetInteger<uint64>(
-    PyObject*, uint64*, PyObject*, PyObject*);
+template bool CheckAndGetInteger<int32>(PyObject*, int32*);
+template bool CheckAndGetInteger<int64>(PyObject*, int64*);
+template bool CheckAndGetInteger<uint32>(PyObject*, uint32*);
+template bool CheckAndGetInteger<uint64>(PyObject*, uint64*);
 
 bool CheckAndGetDouble(PyObject* arg, double* value) {
-  if (!PyInt_Check(arg) && !PyLong_Check(arg) &&
-      !PyFloat_Check(arg)) {
+  *value = PyFloat_AsDouble(arg);
+  if GOOGLE_PREDICT_FALSE(*value == -1 && PyErr_Occurred()) {
     FormatTypeError(arg, "int, long, float");
     return false;
   }
-  *value = PyFloat_AsDouble(arg);
   return true;
 }
 
@@ -630,11 +715,13 @@ bool CheckAndGetFloat(PyObject* arg, float* value) {
 }
 
 bool CheckAndGetBool(PyObject* arg, bool* value) {
-  if (!PyInt_Check(arg) && !PyBool_Check(arg) && !PyLong_Check(arg)) {
+  long long_value = PyInt_AsLong(arg);
+  if (long_value == -1 && PyErr_Occurred()) {
     FormatTypeError(arg, "int, long, bool");
     return false;
   }
-  *value = static_cast<bool>(PyInt_AsLong(arg));
+  *value = static_cast<bool>(long_value);
+
   return true;
 }
 
@@ -966,20 +1053,7 @@ int InternalDeleteRepeatedField(
   int min, max;
   length = reflection->FieldSize(*message, field_descriptor);
 
-  if (PyInt_Check(slice) || PyLong_Check(slice)) {
-    from = to = PyLong_AsLong(slice);
-    if (from < 0) {
-      from = to = length + from;
-    }
-    step = 1;
-    min = max = from;
-
-    // Range check.
-    if (from < 0 || from >= length) {
-      PyErr_Format(PyExc_IndexError, "list assignment index out of range");
-      return -1;
-    }
-  } else if (PySlice_Check(slice)) {
+  if (PySlice_Check(slice)) {
     from = to = step = slice_length = 0;
     PySlice_GetIndicesEx(
 #if PY_MAJOR_VERSION < 3
@@ -996,8 +1070,23 @@ int InternalDeleteRepeatedField(
       max = from;
     }
   } else {
-    PyErr_SetString(PyExc_TypeError, "list indices must be integers");
-    return -1;
+    from = to = PyLong_AsLong(slice);
+    if (from == -1 && PyErr_Occurred()) {
+      PyErr_SetString(PyExc_TypeError, "list indices must be integers");
+      return -1;
+    }
+
+    if (from < 0) {
+      from = to = length + from;
+    }
+    step = 1;
+    min = max = from;
+
+    // Range check.
+    if (from < 0 || from >= length) {
+      PyErr_Format(PyExc_IndexError, "list assignment index out of range");
+      return -1;
+    }
   }
 
   Py_ssize_t i = from;
@@ -1962,99 +2051,29 @@ static PyObject* ByteSize(CMessage* self, PyObject* args) {
   return PyLong_FromLong(self->message->ByteSize());
 }
 
-static PyObject* RegisterExtension(PyObject* cls,
-                                   PyObject* extension_handle) {
+PyObject* RegisterExtension(PyObject* cls, PyObject* extension_handle) {
   const FieldDescriptor* descriptor =
       GetExtensionDescriptor(extension_handle);
   if (descriptor == NULL) {
     return NULL;
   }
-
-  ScopedPyObjectPtr extensions_by_name(
-      PyObject_GetAttr(cls, k_extensions_by_name));
-  if (extensions_by_name == NULL) {
-    PyErr_SetString(PyExc_TypeError, "no extensions_by_name on class");
+  if (!PyObject_TypeCheck(cls, &CMessageClass_Type)) {
+    PyErr_Format(PyExc_TypeError, "Expected a message class, got %s",
+                 cls->ob_type->tp_name);
     return NULL;
   }
-  ScopedPyObjectPtr full_name(PyObject_GetAttr(extension_handle, kfull_name));
-  if (full_name == NULL) {
+  CMessageClass *message_class = reinterpret_cast<CMessageClass*>(cls);
+  if (message_class == NULL) {
     return NULL;
   }
-
   // If the extension was already registered, check that it is the same.
-  PyObject* existing_extension =
-      PyDict_GetItem(extensions_by_name.get(), full_name.get());
-  if (existing_extension != NULL) {
-    const FieldDescriptor* existing_extension_descriptor =
-        GetExtensionDescriptor(existing_extension);
-    if (existing_extension_descriptor != descriptor) {
-      PyErr_SetString(PyExc_ValueError, "Double registration of Extensions");
-      return NULL;
-    }
-    // Nothing else to do.
-    Py_RETURN_NONE;
-  }
-
-  if (PyDict_SetItem(extensions_by_name.get(), full_name.get(),
-                     extension_handle) < 0) {
-    return NULL;
-  }
-
-  // Also store a mapping from extension number to implementing class.
-  ScopedPyObjectPtr extensions_by_number(
-      PyObject_GetAttr(cls, k_extensions_by_number));
-  if (extensions_by_number == NULL) {
-    PyErr_SetString(PyExc_TypeError, "no extensions_by_number on class");
-    return NULL;
-  }
-
-  ScopedPyObjectPtr number(PyObject_GetAttrString(extension_handle, "number"));
-  if (number == NULL) {
-    return NULL;
-  }
-
-  // If the extension was already registered by number, check that it is the
-  // same.
-  existing_extension = PyDict_GetItem(extensions_by_number.get(), number.get());
-  if (existing_extension != NULL) {
-    const FieldDescriptor* existing_extension_descriptor =
-        GetExtensionDescriptor(existing_extension);
-    if (existing_extension_descriptor != descriptor) {
-      const Descriptor* msg_desc = GetMessageDescriptor(
-          reinterpret_cast<PyTypeObject*>(cls));
-      PyErr_Format(
-          PyExc_ValueError,
-          "Extensions \"%s\" and \"%s\" both try to extend message type "
-          "\"%s\" with field number %ld.",
-          existing_extension_descriptor->full_name().c_str(),
-          descriptor->full_name().c_str(),
-          msg_desc->full_name().c_str(),
-          PyInt_AsLong(number.get()));
-      return NULL;
-    }
-    // Nothing else to do.
-    Py_RETURN_NONE;
-  }
-  if (PyDict_SetItem(extensions_by_number.get(), number.get(),
-                     extension_handle) < 0) {
+  const FieldDescriptor* existing_extension =
+      message_class->py_message_factory->pool->pool->FindExtensionByNumber(
+          descriptor->containing_type(), descriptor->number());
+  if (existing_extension != NULL && existing_extension != descriptor) {
+    PyErr_SetString(PyExc_ValueError, "Double registration of Extensions");
     return NULL;
   }
-
-  // Check if it's a message set
-  if (descriptor->is_extension() &&
-      descriptor->containing_type()->options().message_set_wire_format() &&
-      descriptor->type() == FieldDescriptor::TYPE_MESSAGE &&
-      descriptor->label() == FieldDescriptor::LABEL_OPTIONAL) {
-    ScopedPyObjectPtr message_name(PyString_FromStringAndSize(
-        descriptor->message_type()->full_name().c_str(),
-        descriptor->message_type()->full_name().size()));
-    if (message_name == NULL) {
-      return NULL;
-    }
-    PyDict_SetItem(extensions_by_name.get(), message_name.get(),
-                   extension_handle);
-  }
-
   Py_RETURN_NONE;
 }
 
@@ -2091,7 +2110,7 @@ static PyObject* WhichOneof(CMessage* self, PyObject* arg) {
 static PyObject* GetExtensionDict(CMessage* self, void *closure);
 
 static PyObject* ListFields(CMessage* self) {
-  vector<const FieldDescriptor*> fields;
+  std::vector<const FieldDescriptor*> fields;
   self->message->GetReflection()->ListFields(*self->message, &fields);
 
   // Normally, the list will be exactly the size of the fields.
@@ -2182,7 +2201,7 @@ static PyObject* DiscardUnknownFields(CMessage* self) {
 
 PyObject* FindInitializationErrors(CMessage* self) {
   Message* message = self->message;
-  vector<string> errors;
+  std::vector<string> errors;
   message->FindInitializationErrors(&errors);
 
   PyObject* error_list = PyList_New(errors.size());
@@ -2574,11 +2593,24 @@ static PyObject* GetExtensionDict(CMessage* self, void *closure) {
   return NULL;
 }
 
+static PyObject* GetExtensionsByName(CMessage *self, void *closure) {
+  return message_meta::GetExtensionsByName(
+      reinterpret_cast<CMessageClass*>(Py_TYPE(self)), closure);
+}
+
+static PyObject* GetExtensionsByNumber(CMessage *self, void *closure) {
+  return message_meta::GetExtensionsByNumber(
+      reinterpret_cast<CMessageClass*>(Py_TYPE(self)), closure);
+}
+
 static PyGetSetDef Getters[] = {
   {"Extensions", (getter)GetExtensionDict, NULL, "Extension dict"},
+  {"_extensions_by_name", (getter)GetExtensionsByName, NULL},
+  {"_extensions_by_number", (getter)GetExtensionsByNumber, NULL},
   {NULL}
 };
 
+
 static PyMethodDef Methods[] = {
   { "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,
     "Makes a deep copy of the class." },
@@ -2839,19 +2871,7 @@ void InitGlobals() {
   // TODO(gps): Check all return values in this function for NULL and propagate
   // the error (MemoryError) on up to result in an import failure.  These should
   // also be freed and reset to NULL during finalization.
-  kPythonZero = PyInt_FromLong(0);
-  kint32min_py = PyInt_FromLong(kint32min);
-  kint32max_py = PyInt_FromLong(kint32max);
-  kuint32max_py = PyLong_FromLongLong(kuint32max);
-  kint64min_py = PyLong_FromLongLong(kint64min);
-  kint64max_py = PyLong_FromLongLong(kint64max);
-  kuint64max_py = PyLong_FromUnsignedLongLong(kuint64max);
-
   kDESCRIPTOR = PyString_FromString("DESCRIPTOR");
-  k_cdescriptor = PyString_FromString("_cdescriptor");
-  kfull_name = PyString_FromString("full_name");
-  k_extensions_by_name = PyString_FromString("_extensions_by_name");
-  k_extensions_by_number = PyString_FromString("_extensions_by_number");
 
   PyObject *dummy_obj = PySet_New(NULL);
   kEmptyWeakref = PyWeakref_NewRef(dummy_obj, NULL);
@@ -2891,25 +2911,6 @@ bool InitProto2MessageModule(PyObject *m) {
   // DESCRIPTOR is set on each protocol buffer message class elsewhere, but set
   // it here as well to document that subclasses need to set it.
   PyDict_SetItem(CMessage_Type.tp_dict, kDESCRIPTOR, Py_None);
-  // Subclasses with message extensions will override _extensions_by_name and
-  // _extensions_by_number with fresh mutable dictionaries in AddDescriptors.
-  // All other classes can share this same immutable mapping.
-  ScopedPyObjectPtr empty_dict(PyDict_New());
-  if (empty_dict == NULL) {
-    return false;
-  }
-  ScopedPyObjectPtr immutable_dict(PyDictProxy_New(empty_dict.get()));
-  if (immutable_dict == NULL) {
-    return false;
-  }
-  if (PyDict_SetItem(CMessage_Type.tp_dict,
-                     k_extensions_by_name, immutable_dict.get()) < 0) {
-    return false;
-  }
-  if (PyDict_SetItem(CMessage_Type.tp_dict,
-                     k_extensions_by_number, immutable_dict.get()) < 0) {
-    return false;
-  }
 
   PyModule_AddObject(m, "Message", reinterpret_cast<PyObject*>(&CMessage_Type));
 

+ 10 - 14
python/google/protobuf/pyext/message.h

@@ -117,6 +117,7 @@ typedef struct CMessage {
   PyObject* weakreflist;
 } CMessage;
 
+extern PyTypeObject CMessageClass_Type;
 extern PyTypeObject CMessage_Type;
 
 
@@ -235,6 +236,10 @@ int InitAttributes(CMessage* self, PyObject* args, PyObject* kwargs);
 
 PyObject* MergeFrom(CMessage* self, PyObject* arg);
 
+// This method does not do anything beyond checking that no other extension
+// has been registered with the same field number on this class.
+PyObject* RegisterExtension(PyObject* cls, PyObject* extension_handle);
+
 // Retrieves an attribute named 'name' from CMessage 'self'. Returns
 // the attribute value on success, or NULL on failure.
 //
@@ -275,25 +280,25 @@ PyObject* SetAllowOversizeProtos(PyObject* m, PyObject* arg);
 
 #define GOOGLE_CHECK_GET_INT32(arg, value, err)                        \
     int32 value;                                            \
-    if (!CheckAndGetInteger(arg, &value, kint32min_py, kint32max_py)) { \
+    if (!CheckAndGetInteger(arg, &value)) { \
       return err;                                          \
     }
 
 #define GOOGLE_CHECK_GET_INT64(arg, value, err)                        \
     int64 value;                                            \
-    if (!CheckAndGetInteger(arg, &value, kint64min_py, kint64max_py)) { \
+    if (!CheckAndGetInteger(arg, &value)) { \
       return err;                                          \
     }
 
 #define GOOGLE_CHECK_GET_UINT32(arg, value, err)                       \
     uint32 value;                                           \
-    if (!CheckAndGetInteger(arg, &value, kPythonZero, kuint32max_py)) { \
+    if (!CheckAndGetInteger(arg, &value)) { \
       return err;                                          \
     }
 
 #define GOOGLE_CHECK_GET_UINT64(arg, value, err)                       \
     uint64 value;                                           \
-    if (!CheckAndGetInteger(arg, &value, kPythonZero, kuint64max_py)) { \
+    if (!CheckAndGetInteger(arg, &value)) { \
       return err;                                          \
     }
 
@@ -316,20 +321,11 @@ PyObject* SetAllowOversizeProtos(PyObject* m, PyObject* arg);
     }
 
 
-extern PyObject* kPythonZero;
-extern PyObject* kint32min_py;
-extern PyObject* kint32max_py;
-extern PyObject* kuint32max_py;
-extern PyObject* kint64min_py;
-extern PyObject* kint64max_py;
-extern PyObject* kuint64max_py;
-
 #define FULL_MODULE_NAME "google.protobuf.pyext._message"
 
 void FormatTypeError(PyObject* arg, char* expected_types);
 template<class T>
-bool CheckAndGetInteger(
-    PyObject* arg, T* value, PyObject* min, PyObject* max);
+bool CheckAndGetInteger(PyObject* arg, T* value);
 bool CheckAndGetDouble(PyObject* arg, double* value);
 bool CheckAndGetFloat(PyObject* arg, float* value);
 bool CheckAndGetBool(PyObject* arg, bool* value);

+ 66 - 0
python/google/protobuf/pyext/message_factory.cc

@@ -130,6 +130,72 @@ int RegisterMessageClass(PyMessageFactory* self,
   return 0;
 }
 
+CMessageClass* GetOrCreateMessageClass(PyMessageFactory* self,
+                                       const Descriptor* descriptor) {
+  // This is the same implementation as MessageFactory.GetPrototype().
+  ScopedPyObjectPtr py_descriptor(
+      PyMessageDescriptor_FromDescriptor(descriptor));
+  if (py_descriptor == NULL) {
+    return NULL;
+  }
+  // Do not create a MessageClass that already exists.
+  hash_map<const Descriptor*, CMessageClass*>::iterator it =
+      self->classes_by_descriptor->find(descriptor);
+  if (it != self->classes_by_descriptor->end()) {
+    Py_INCREF(it->second);
+    return it->second;
+  }
+  // Create a new message class.
+  ScopedPyObjectPtr args(Py_BuildValue(
+      "s(){sOsOsO}", descriptor->name().c_str(),
+      "DESCRIPTOR", py_descriptor.get(),
+      "__module__", Py_None,
+      "message_factory", self));
+  if (args == NULL) {
+    return NULL;
+  }
+  ScopedPyObjectPtr message_class(PyObject_CallObject(
+      reinterpret_cast<PyObject*>(&CMessageClass_Type), args.get()));
+  if (message_class == NULL) {
+    return NULL;
+  }
+  // Create messages class for the messages used by the fields, and registers
+  // all extensions for these messages during the recursion.
+  for (int field_idx = 0; field_idx < descriptor->field_count(); field_idx++) {
+    const Descriptor* sub_descriptor =
+        descriptor->field(field_idx)->message_type();
+    // It is NULL if the field type is not a message.
+    if (sub_descriptor != NULL) {
+      CMessageClass* result = GetOrCreateMessageClass(self, sub_descriptor);
+      if (result == NULL) {
+        return NULL;
+      }
+      Py_DECREF(result);
+    }
+  }
+
+  // Register extensions defined in this message.
+  for (int ext_idx = 0 ; ext_idx < descriptor->extension_count() ; ext_idx++) {
+    const FieldDescriptor* extension = descriptor->extension(ext_idx);
+    ScopedPyObjectPtr py_extended_class(
+        GetOrCreateMessageClass(self, extension->containing_type())
+            ->AsPyObject());
+    if (py_extended_class == NULL) {
+      return NULL;
+    }
+    ScopedPyObjectPtr py_extension(PyFieldDescriptor_FromDescriptor(extension));
+    if (py_extension == NULL) {
+      return NULL;
+    }
+    ScopedPyObjectPtr result(cmessage::RegisterExtension(
+        py_extended_class.get(), py_extension.get()));
+    if (result == NULL) {
+      return NULL;
+    }
+  }
+  return reinterpret_cast<CMessageClass*>(message_class.release());
+}
+
 // Retrieve the message class added to our database.
 CMessageClass* GetMessageClass(PyMessageFactory* self,
                                const Descriptor* message_descriptor) {

+ 6 - 6
python/google/protobuf/pyext/message_factory.h

@@ -82,14 +82,14 @@ PyMessageFactory* NewMessageFactory(PyTypeObject* type, PyDescriptorPool* pool);
 int RegisterMessageClass(PyMessageFactory* self,
                          const Descriptor* message_descriptor,
                          CMessageClass* message_class);
-
-// Retrieves the Python class registered with the given message descriptor.
-//
-// Returns a *borrowed* reference if found, otherwise returns NULL with an
-// exception set.
+// Retrieves the Python class registered with the given message descriptor, or
+// fail with a TypeError. Returns a *borrowed* reference.
 CMessageClass* GetMessageClass(PyMessageFactory* self,
                                const Descriptor* message_descriptor);
-
+// Retrieves the Python class registered with the given message descriptor.
+// The class is created if not done yet. Returns a *new* reference.
+CMessageClass* GetOrCreateMessageClass(PyMessageFactory* self,
+                                       const Descriptor* message_descriptor);
 }  // namespace message_factory
 
 // Initialize objects used by this module.

+ 164 - 0
python/google/protobuf/pyext/safe_numerics.h

@@ -0,0 +1,164 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_SAFE_NUMERICS_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_SAFE_NUMERICS_H__
+// Copied from chromium with only changes to the namespace.
+
+#include <limits>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+template <bool SameSize, bool DestLarger,
+          bool DestIsSigned, bool SourceIsSigned>
+struct IsValidNumericCastImpl;
+
+#define BASE_NUMERIC_CAST_CASE_SPECIALIZATION(A, B, C, D, Code) \
+template <> struct IsValidNumericCastImpl<A, B, C, D> { \
+  template <class Source, class DestBounds> static inline bool Test( \
+      Source source, DestBounds min, DestBounds max) { \
+    return Code; \
+  } \
+}
+
+#define BASE_NUMERIC_CAST_CASE_SAME_SIZE(DestSigned, SourceSigned, Code) \
+  BASE_NUMERIC_CAST_CASE_SPECIALIZATION( \
+      true, true, DestSigned, SourceSigned, Code); \
+  BASE_NUMERIC_CAST_CASE_SPECIALIZATION( \
+      true, false, DestSigned, SourceSigned, Code)
+
+#define BASE_NUMERIC_CAST_CASE_SOURCE_LARGER(DestSigned, SourceSigned, Code) \
+  BASE_NUMERIC_CAST_CASE_SPECIALIZATION( \
+      false, false, DestSigned, SourceSigned, Code); \
+
+#define BASE_NUMERIC_CAST_CASE_DEST_LARGER(DestSigned, SourceSigned, Code) \
+  BASE_NUMERIC_CAST_CASE_SPECIALIZATION( \
+      false, true, DestSigned, SourceSigned, Code); \
+
+// The three top level cases are:
+// - Same size
+// - Source larger
+// - Dest larger
+// And for each of those three cases, we handle the 4 different possibilities
+// of signed and unsigned. This gives 12 cases to handle, which we enumerate
+// below.
+//
+// The last argument in each of the macros is the actual comparison code. It
+// has three arguments available, source (the value), and min/max which are
+// the ranges of the destination.
+
+
+// These are the cases where both types have the same size.
+
+// Both signed.
+BASE_NUMERIC_CAST_CASE_SAME_SIZE(true, true, true);
+// Both unsigned.
+BASE_NUMERIC_CAST_CASE_SAME_SIZE(false, false, true);
+// Dest unsigned, Source signed.
+BASE_NUMERIC_CAST_CASE_SAME_SIZE(false, true, source >= 0);
+// Dest signed, Source unsigned.
+// This cast is OK because Dest's max must be less than Source's.
+BASE_NUMERIC_CAST_CASE_SAME_SIZE(true, false,
+                                 source <= static_cast<Source>(max));
+
+
+// These are the cases where Source is larger.
+
+// Both unsigned.
+BASE_NUMERIC_CAST_CASE_SOURCE_LARGER(false, false, source <= max);
+// Both signed.
+BASE_NUMERIC_CAST_CASE_SOURCE_LARGER(true, true,
+                                     source >= min && source <= max);
+// Dest is unsigned, Source is signed.
+BASE_NUMERIC_CAST_CASE_SOURCE_LARGER(false, true,
+                                     source >= 0 && source <= max);
+// Dest is signed, Source is unsigned.
+// This cast is OK because Dest's max must be less than Source's.
+BASE_NUMERIC_CAST_CASE_SOURCE_LARGER(true, false,
+                                     source <= static_cast<Source>(max));
+
+
+// These are the cases where Dest is larger.
+
+// Both unsigned.
+BASE_NUMERIC_CAST_CASE_DEST_LARGER(false, false, true);
+// Both signed.
+BASE_NUMERIC_CAST_CASE_DEST_LARGER(true, true, true);
+// Dest is unsigned, Source is signed.
+BASE_NUMERIC_CAST_CASE_DEST_LARGER(false, true, source >= 0);
+// Dest is signed, Source is unsigned.
+BASE_NUMERIC_CAST_CASE_DEST_LARGER(true, false, true);
+
+#undef BASE_NUMERIC_CAST_CASE_SPECIALIZATION
+#undef BASE_NUMERIC_CAST_CASE_SAME_SIZE
+#undef BASE_NUMERIC_CAST_CASE_SOURCE_LARGER
+#undef BASE_NUMERIC_CAST_CASE_DEST_LARGER
+
+
+// The main test for whether the conversion will under or overflow.
+template <class Dest, class Source>
+inline bool IsValidNumericCast(Source source) {
+  typedef std::numeric_limits<Source> SourceLimits;
+  typedef std::numeric_limits<Dest> DestLimits;
+  GOOGLE_COMPILE_ASSERT(SourceLimits::is_specialized, argument_must_be_numeric);
+  GOOGLE_COMPILE_ASSERT(SourceLimits::is_integer, argument_must_be_integral);
+  GOOGLE_COMPILE_ASSERT(DestLimits::is_specialized, result_must_be_numeric);
+  GOOGLE_COMPILE_ASSERT(DestLimits::is_integer, result_must_be_integral);
+
+  return IsValidNumericCastImpl<
+      sizeof(Dest) == sizeof(Source),
+      (sizeof(Dest) > sizeof(Source)),
+      DestLimits::is_signed,
+      SourceLimits::is_signed>::Test(
+          source,
+          DestLimits::min(),
+          DestLimits::max());
+}
+
+// checked_numeric_cast<> is analogous to static_cast<> for numeric types,
+// except that it CHECKs that the specified numeric conversion will not
+// overflow or underflow. Floating point arguments are not currently allowed
+// (this is COMPILE_ASSERTd), though this could be supported if necessary.
+template <class Dest, class Source>
+inline Dest checked_numeric_cast(Source source) {
+  GOOGLE_CHECK(IsValidNumericCast<Dest>(source));
+  return static_cast<Dest>(source);
+}
+
+}  // namespace python
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_PYTHON_CPP_SAFE_NUMERICS_H__

+ 4 - 2
ruby/tests/basic.rb

@@ -1183,13 +1183,15 @@ module BasicTest
     end
 
     def test_comparison_with_arbitrary_object
-      assert_false MapMessage.new == nil
+      assert MapMessage.new != nil
     end
 
     def test_respond_to
+      # This test fails with JRuby 1.7.23, likely because of an old JRuby bug.
+      return if RUBY_PLATFORM == "java"
       msg = MapMessage.new
       assert msg.respond_to?(:map_string_int32)
-      assert_false msg.respond_to?(:bacon)
+      assert !msg.respond_to?(:bacon)
     end
   end
 end

+ 2 - 0
src/Makefile.am

@@ -161,6 +161,7 @@ nobase_include_HEADERS =                                         \
   google/protobuf/compiler/java/java_names.h                     \
   google/protobuf/compiler/javanano/javanano_generator.h         \
   google/protobuf/compiler/js/js_generator.h                     \
+  google/protobuf/compiler/js/well_known_types_embed.h           \
   google/protobuf/compiler/objectivec/objectivec_generator.h     \
   google/protobuf/compiler/objectivec/objectivec_helpers.h       \
   google/protobuf/compiler/php/php_generator.h                   \
@@ -399,6 +400,7 @@ libprotoc_la_SOURCES =                                         \
   google/protobuf/compiler/java/java_doc_comment.cc            \
   google/protobuf/compiler/java/java_doc_comment.h             \
   google/protobuf/compiler/js/js_generator.cc                  \
+  google/protobuf/compiler/js/well_known_types_embed.cc        \
   google/protobuf/compiler/javanano/javanano_enum.cc           \
   google/protobuf/compiler/javanano/javanano_enum.h            \
   google/protobuf/compiler/javanano/javanano_enum_field.cc     \

+ 4 - 4
src/google/protobuf/any.cc

@@ -30,6 +30,8 @@
 
 #include <google/protobuf/any.h>
 
+#include <google/protobuf/generated_message_util.h>
+
 namespace google {
 namespace protobuf {
 namespace internal {
@@ -70,13 +72,11 @@ bool AnyMetadata::UnpackTo(Message* message) const {
   if (!InternalIs(message->GetDescriptor())) {
     return false;
   }
-  return message->ParseFromString(
-      value_->GetNoArena(&::google::protobuf::internal::GetEmptyString()));
+  return message->ParseFromString(value_->GetNoArena());
 }
 
 bool AnyMetadata::InternalIs(const Descriptor* descriptor) const {
-  const string type_url = type_url_->GetNoArena(
-             &::google::protobuf::internal::GetEmptyString());
+  const string type_url = type_url_->GetNoArena();
   string full_name;
   if (!ParseAnyTypeUrl(type_url, &full_name)) {
     return false;

+ 82 - 104
src/google/protobuf/any.pb.cc

@@ -19,86 +19,88 @@
 
 namespace google {
 namespace protobuf {
+class AnyDefaultTypeInternal : public ::google::protobuf::internal::ExplicitlyConstructed<Any> {};
+AnyDefaultTypeInternal _Any_default_instance_;
 
 namespace {
 
-const ::google::protobuf::Descriptor* Any_descriptor_ = NULL;
-const ::google::protobuf::internal::GeneratedMessageReflection*
-  Any_reflection_ = NULL;
+::google::protobuf::Metadata file_level_metadata[1];
 
 }  // namespace
 
 
-void protobuf_AssignDesc_google_2fprotobuf_2fany_2eproto() GOOGLE_ATTRIBUTE_COLD;
-void protobuf_AssignDesc_google_2fprotobuf_2fany_2eproto() {
-  protobuf_AddDesc_google_2fprotobuf_2fany_2eproto();
-  const ::google::protobuf::FileDescriptor* file =
-    ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
-      "google/protobuf/any.proto");
-  GOOGLE_CHECK(file != NULL);
-  Any_descriptor_ = file->message_type(0);
-  static const int Any_offsets_[2] = {
+const ::google::protobuf::uint32* protobuf_Offsets_google_2fprotobuf_2fany_2eproto() GOOGLE_ATTRIBUTE_COLD;
+const ::google::protobuf::uint32* protobuf_Offsets_google_2fprotobuf_2fany_2eproto() {
+  static const ::google::protobuf::uint32 offsets[] = {
+    ~0u,  // no _has_bits_
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Any, _internal_metadata_),
+    ~0u,  // no _extensions_
+    ~0u,  // no _oneof_case_
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Any, type_url_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Any, value_),
   };
-  Any_reflection_ =
-    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
-      Any_descriptor_,
-      Any::internal_default_instance(),
-      Any_offsets_,
-      -1,
-      -1,
-      -1,
-      sizeof(Any),
-      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Any, _internal_metadata_));
+  return offsets;
 }
 
+static const ::google::protobuf::internal::MigrationSchema schemas[] = {
+  { 0, -1, sizeof(Any)},
+};
+
+static const ::google::protobuf::internal::DefaultInstanceData file_default_instances[] = {
+  {reinterpret_cast<const ::google::protobuf::Message*>(&_Any_default_instance_), NULL},
+};
+
 namespace {
 
-GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);
+void protobuf_AssignDescriptors() {
+  protobuf_AddDesc_google_2fprotobuf_2fany_2eproto();
+  ::google::protobuf::MessageFactory* factory = NULL;
+  AssignDescriptors(
+      "google/protobuf/any.proto", schemas, file_default_instances, protobuf_Offsets_google_2fprotobuf_2fany_2eproto(), factory,
+      file_level_metadata, NULL, NULL);
+}
+
 void protobuf_AssignDescriptorsOnce() {
-  ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,
-                 &protobuf_AssignDesc_google_2fprotobuf_2fany_2eproto);
+  static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
+  ::google::protobuf::GoogleOnceInit(&once, &protobuf_AssignDescriptors);
 }
 
 void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;
 void protobuf_RegisterTypes(const ::std::string&) {
   protobuf_AssignDescriptorsOnce();
-  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
-      Any_descriptor_, Any::internal_default_instance());
+  ::google::protobuf::internal::RegisterAllTypes(file_level_metadata, 1);
 }
 
 }  // namespace
 
 void protobuf_ShutdownFile_google_2fprotobuf_2fany_2eproto() {
-  Any_default_instance_.Shutdown();
-  delete Any_reflection_;
+  _Any_default_instance_.Shutdown();
+  delete file_level_metadata[0].reflection;
 }
 
 void protobuf_InitDefaults_google_2fprotobuf_2fany_2eproto_impl() {
   GOOGLE_PROTOBUF_VERIFY_VERSION;
 
-  ::google::protobuf::internal::GetEmptyString();
-  Any_default_instance_.DefaultConstruct();
-  Any_default_instance_.get_mutable()->InitAsDefaultInstance();
+  ::google::protobuf::internal::InitProtobufDefaults();
+  _Any_default_instance_.DefaultConstruct();
 }
 
-GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_InitDefaults_google_2fprotobuf_2fany_2eproto_once_);
 void protobuf_InitDefaults_google_2fprotobuf_2fany_2eproto() {
-  ::google::protobuf::GoogleOnceInit(&protobuf_InitDefaults_google_2fprotobuf_2fany_2eproto_once_,
-                 &protobuf_InitDefaults_google_2fprotobuf_2fany_2eproto_impl);
+  static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
+  ::google::protobuf::GoogleOnceInit(&once, &protobuf_InitDefaults_google_2fprotobuf_2fany_2eproto_impl);
 }
 void protobuf_AddDesc_google_2fprotobuf_2fany_2eproto_impl() {
-  GOOGLE_PROTOBUF_VERIFY_VERSION;
-
   protobuf_InitDefaults_google_2fprotobuf_2fany_2eproto();
+  static const char descriptor[] = {
+      "\n\031google/protobuf/any.proto\022\017google.prot"
+      "obuf\"&\n\003Any\022\020\n\010type_url\030\001 \001(\t\022\r\n\005value\030\002"
+      " \001(\014Bo\n\023com.google.protobufB\010AnyProtoP\001Z"
+      "%github.com/golang/protobuf/ptypes/any\242\002"
+      "\003GPB\252\002\036Google.Protobuf.WellKnownTypesb\006p"
+      "roto3"
+  };
   ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
-    "\n\031google/protobuf/any.proto\022\017google.prot"
-    "obuf\"&\n\003Any\022\020\n\010type_url\030\001 \001(\t\022\r\n\005value\030\002"
-    " \001(\014Bo\n\023com.google.protobufB\010AnyProtoP\001Z"
-    "%github.com/golang/protobuf/ptypes/any\242\002"
-    "\003GPB\252\002\036Google.Protobuf.WellKnownTypesb\006p"
-    "roto3", 205);
+      descriptor, 205);
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
     "google/protobuf/any.proto", &protobuf_RegisterTypes);
   ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_google_2fprotobuf_2fany_2eproto);
@@ -116,16 +118,6 @@ struct StaticDescriptorInitializer_google_2fprotobuf_2fany_2eproto {
   }
 } static_descriptor_initializer_google_2fprotobuf_2fany_2eproto_;
 
-namespace {
-
-static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD GOOGLE_ATTRIBUTE_NORETURN;
-static void MergeFromFail(int line) {
-  ::google::protobuf::internal::MergeFromFail(__FILE__, line);
-}
-
-}  // namespace
-
-
 // ===================================================================
 
 void Any::PackFrom(const ::google::protobuf::Message& message) {
@@ -148,20 +140,26 @@ const int Any::kValueFieldNumber;
 
 Any::Any()
   : ::google::protobuf::Message(), _internal_metadata_(NULL), _any_metadata_(&type_url_, &value_) {
-  if (this != internal_default_instance()) protobuf_InitDefaults_google_2fprotobuf_2fany_2eproto();
+  if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) {
+    protobuf_InitDefaults_google_2fprotobuf_2fany_2eproto();
+  }
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.Any)
 }
-
-void Any::InitAsDefaultInstance() {
-}
-
 Any::Any(const Any& from)
   : ::google::protobuf::Message(),
-    _internal_metadata_(NULL),
-    _any_metadata_(&type_url_, &value_) {
-  SharedCtor();
-  UnsafeMergeFrom(from);
+      _internal_metadata_(NULL),
+      _cached_size_(0),
+      _any_metadata_(&type_url_, &value_) {
+  _internal_metadata_.MergeFrom(from._internal_metadata_);
+  type_url_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  if (from.type_url().size() > 0) {
+    type_url_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.type_url_);
+  }
+  value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  if (from.value().size() > 0) {
+    value_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.value_);
+  }
   // @@protoc_insertion_point(copy_constructor:google.protobuf.Any)
 }
 
@@ -188,7 +186,7 @@ void Any::SetCachedSize(int size) const {
 }
 const ::google::protobuf::Descriptor* Any::descriptor() {
   protobuf_AssignDescriptorsOnce();
-  return Any_descriptor_;
+  return file_level_metadata[0].descriptor;
 }
 
 const Any& Any::default_instance() {
@@ -196,8 +194,6 @@ const Any& Any::default_instance() {
   return *internal_default_instance();
 }
 
-::google::protobuf::internal::ExplicitlyConstructed<Any> Any_default_instance_;
-
 Any* Any::New(::google::protobuf::Arena* arena) const {
   Any* n = new Any;
   if (arena != NULL) {
@@ -218,13 +214,13 @@ bool Any::MergePartialFromCodedStream(
   ::google::protobuf::uint32 tag;
   // @@protoc_insertion_point(parse_start:google.protobuf.Any)
   for (;;) {
-    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoffNoLastTag(127u);
     tag = p.first;
     if (!p.second) goto handle_unusual;
     switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
-      // optional string type_url = 1;
+      // string type_url = 1;
       case 1: {
-        if (tag == 10) {
+        if (tag == 10u) {
           DO_(::google::protobuf::internal::WireFormatLite::ReadString(
                 input, this->mutable_type_url()));
           DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
@@ -234,20 +230,17 @@ bool Any::MergePartialFromCodedStream(
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(18)) goto parse_value;
         break;
       }
 
-      // optional bytes value = 2;
+      // bytes value = 2;
       case 2: {
-        if (tag == 18) {
-         parse_value:
+        if (tag == 18u) {
           DO_(::google::protobuf::internal::WireFormatLite::ReadBytes(
                 input, this->mutable_value()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectAtEnd()) goto success;
         break;
       }
 
@@ -275,7 +268,7 @@ failure:
 void Any::SerializeWithCachedSizes(
     ::google::protobuf::io::CodedOutputStream* output) const {
   // @@protoc_insertion_point(serialize_start:google.protobuf.Any)
-  // optional string type_url = 1;
+  // string type_url = 1;
   if (this->type_url().size() > 0) {
     ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
       this->type_url().data(), this->type_url().length(),
@@ -285,7 +278,7 @@ void Any::SerializeWithCachedSizes(
       1, this->type_url(), output);
   }
 
-  // optional bytes value = 2;
+  // bytes value = 2;
   if (this->value().size() > 0) {
     ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased(
       2, this->value(), output);
@@ -298,7 +291,7 @@ void Any::SerializeWithCachedSizes(
     bool deterministic, ::google::protobuf::uint8* target) const {
   (void)deterministic; // Unused
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Any)
-  // optional string type_url = 1;
+  // string type_url = 1;
   if (this->type_url().size() > 0) {
     ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
       this->type_url().data(), this->type_url().length(),
@@ -309,7 +302,7 @@ void Any::SerializeWithCachedSizes(
         1, this->type_url(), target);
   }
 
-  // optional bytes value = 2;
+  // bytes value = 2;
   if (this->value().size() > 0) {
     target =
       ::google::protobuf::internal::WireFormatLite::WriteBytesToArray(
@@ -324,14 +317,14 @@ size_t Any::ByteSizeLong() const {
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.Any)
   size_t total_size = 0;
 
-  // optional string type_url = 1;
+  // string type_url = 1;
   if (this->type_url().size() > 0) {
     total_size += 1 +
       ::google::protobuf::internal::WireFormatLite::StringSize(
         this->type_url());
   }
 
-  // optional bytes value = 2;
+  // bytes value = 2;
   if (this->value().size() > 0) {
     total_size += 1 +
       ::google::protobuf::internal::WireFormatLite::BytesSize(
@@ -347,7 +340,7 @@ size_t Any::ByteSizeLong() const {
 
 void Any::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Any)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  GOOGLE_DCHECK_NE(&from, this);
   const Any* source =
       ::google::protobuf::internal::DynamicCastToGenerated<const Any>(
           &from);
@@ -356,21 +349,14 @@ void Any::MergeFrom(const ::google::protobuf::Message& from) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
   // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Any)
-    UnsafeMergeFrom(*source);
+    MergeFrom(*source);
   }
 }
 
 void Any::MergeFrom(const Any& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Any)
-  if (GOOGLE_PREDICT_TRUE(&from != this)) {
-    UnsafeMergeFrom(from);
-  } else {
-    MergeFromFail(__LINE__);
-  }
-}
-
-void Any::UnsafeMergeFrom(const Any& from) {
-  GOOGLE_DCHECK(&from != this);
+  GOOGLE_DCHECK_NE(&from, this);
+  _internal_metadata_.MergeFrom(from._internal_metadata_);
   if (from.type_url().size() > 0) {
 
     type_url_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.type_url_);
@@ -392,11 +378,10 @@ void Any::CopyFrom(const Any& from) {
 // @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Any)
   if (&from == this) return;
   Clear();
-  UnsafeMergeFrom(from);
+  MergeFrom(from);
 }
 
 bool Any::IsInitialized() const {
-
   return true;
 }
 
@@ -407,28 +392,24 @@ void Any::Swap(Any* other) {
 void Any::InternalSwap(Any* other) {
   type_url_.Swap(&other->type_url_);
   value_.Swap(&other->value_);
-  _internal_metadata_.Swap(&other->_internal_metadata_);
   std::swap(_cached_size_, other->_cached_size_);
 }
 
 ::google::protobuf::Metadata Any::GetMetadata() const {
   protobuf_AssignDescriptorsOnce();
-  ::google::protobuf::Metadata metadata;
-  metadata.descriptor = Any_descriptor_;
-  metadata.reflection = Any_reflection_;
-  return metadata;
+  return file_level_metadata[0];
 }
 
 #if PROTOBUF_INLINE_NOT_IN_HEADERS
 // Any
 
-// optional string type_url = 1;
+// string type_url = 1;
 void Any::clear_type_url() {
   type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 const ::std::string& Any::type_url() const {
   // @@protoc_insertion_point(field_get:google.protobuf.Any.type_url)
-  return type_url_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  return type_url_.GetNoArena();
 }
 void Any::set_type_url(const ::std::string& value) {
   
@@ -466,13 +447,13 @@ void Any::set_allocated_type_url(::std::string* type_url) {
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.Any.type_url)
 }
 
-// optional bytes value = 2;
+// bytes value = 2;
 void Any::clear_value() {
   value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 const ::std::string& Any::value() const {
   // @@protoc_insertion_point(field_get:google.protobuf.Any.value)
-  return value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  return value_.GetNoArena();
 }
 void Any::set_value(const ::std::string& value) {
   
@@ -510,9 +491,6 @@ void Any::set_allocated_value(::std::string* value) {
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.Any.value)
 }
 
-inline const Any* Any::internal_default_instance() {
-  return &Any_default_instance_.get();
-}
 #endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // @@protoc_insertion_point(namespace_scope)

+ 38 - 37
src/google/protobuf/any.pb.h

@@ -24,11 +24,18 @@
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/metadata.h>
 #include <google/protobuf/message.h>
-#include <google/protobuf/repeated_field.h>
-#include <google/protobuf/extension_set.h>
+#include <google/protobuf/repeated_field.h>  // IWYU pragma: export
+#include <google/protobuf/extension_set.h>  // IWYU pragma: export
 #include <google/protobuf/unknown_field_set.h>
 #include <google/protobuf/any.h>
 // @@protoc_insertion_point(includes)
+namespace google {
+namespace protobuf {
+class Any;
+class AnyDefaultTypeInternal;
+extern AnyDefaultTypeInternal _Any_default_instance_;
+}  // namespace protobuf
+}  // namespace google
 
 namespace google {
 namespace protobuf {
@@ -36,10 +43,6 @@ namespace protobuf {
 // Internal implementation detail -- do not call these.
 void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fany_2eproto();
 void LIBPROTOBUF_EXPORT protobuf_InitDefaults_google_2fprotobuf_2fany_2eproto();
-void protobuf_AssignDesc_google_2fprotobuf_2fany_2eproto();
-void protobuf_ShutdownFile_google_2fprotobuf_2fany_2eproto();
-
-class Any;
 
 // ===================================================================
 
@@ -58,7 +61,10 @@ class LIBPROTOBUF_EXPORT Any : public ::google::protobuf::Message /* @@protoc_in
   static const ::google::protobuf::Descriptor* descriptor();
   static const Any& default_instance();
 
-  static const Any* internal_default_instance();
+  static inline const Any* internal_default_instance() {
+    return reinterpret_cast<const Any*>(
+               &_Any_default_instance_);
+  }
 
   // implements Any -----------------------------------------------
 
@@ -74,49 +80,49 @@ class LIBPROTOBUF_EXPORT Any : public ::google::protobuf::Message /* @@protoc_in
 
   // implements Message ----------------------------------------------
 
-  inline Any* New() const { return New(NULL); }
+  inline Any* New() const PROTOBUF_FINAL { return New(NULL); }
 
-  Any* New(::google::protobuf::Arena* arena) const;
-  void CopyFrom(const ::google::protobuf::Message& from);
-  void MergeFrom(const ::google::protobuf::Message& from);
+  Any* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
+  void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
+  void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void CopyFrom(const Any& from);
   void MergeFrom(const Any& from);
-  void Clear();
-  bool IsInitialized() const;
+  void Clear() PROTOBUF_FINAL;
+  bool IsInitialized() const PROTOBUF_FINAL;
 
-  size_t ByteSizeLong() const;
+  size_t ByteSizeLong() const PROTOBUF_FINAL;
   bool MergePartialFromCodedStream(
-      ::google::protobuf::io::CodedInputStream* input);
+      ::google::protobuf::io::CodedInputStream* input) PROTOBUF_FINAL;
   void SerializeWithCachedSizes(
-      ::google::protobuf::io::CodedOutputStream* output) const;
+      ::google::protobuf::io::CodedOutputStream* output) const PROTOBUF_FINAL;
   ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
-      bool deterministic, ::google::protobuf::uint8* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+      bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output)
+      const PROTOBUF_FINAL {
     return InternalSerializeWithCachedSizesToArray(false, output);
   }
-  int GetCachedSize() const { return _cached_size_; }
+  int GetCachedSize() const PROTOBUF_FINAL { return _cached_size_; }
   private:
   void SharedCtor();
   void SharedDtor();
-  void SetCachedSize(int size) const;
+  void SetCachedSize(int size) const PROTOBUF_FINAL;
   void InternalSwap(Any* other);
-  void UnsafeMergeFrom(const Any& from);
   private:
   inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
-    return _internal_metadata_.arena();
+    return NULL;
   }
   inline void* MaybeArenaPtr() const {
-    return _internal_metadata_.raw_arena_ptr();
+    return NULL;
   }
   public:
 
-  ::google::protobuf::Metadata GetMetadata() const;
+  ::google::protobuf::Metadata GetMetadata() const PROTOBUF_FINAL;
 
   // nested types ----------------------------------------------------
 
   // accessors -------------------------------------------------------
 
-  // optional string type_url = 1;
+  // string type_url = 1;
   void clear_type_url();
   static const int kTypeUrlFieldNumber = 1;
   const ::std::string& type_url() const;
@@ -127,7 +133,7 @@ class LIBPROTOBUF_EXPORT Any : public ::google::protobuf::Message /* @@protoc_in
   ::std::string* release_type_url();
   void set_allocated_type_url(::std::string* type_url);
 
-  // optional bytes value = 2;
+  // bytes value = 2;
   void clear_value();
   static const int kValueFieldNumber = 2;
   const ::std::string& value() const;
@@ -148,13 +154,10 @@ class LIBPROTOBUF_EXPORT Any : public ::google::protobuf::Message /* @@protoc_in
   ::google::protobuf::internal::AnyMetadata _any_metadata_;
   friend void LIBPROTOBUF_EXPORT protobuf_InitDefaults_google_2fprotobuf_2fany_2eproto_impl();
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fany_2eproto_impl();
-  friend void protobuf_AssignDesc_google_2fprotobuf_2fany_2eproto();
+  friend const ::google::protobuf::uint32* protobuf_Offsets_google_2fprotobuf_2fany_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fany_2eproto();
 
-  void InitAsDefaultInstance();
 };
-extern ::google::protobuf::internal::ExplicitlyConstructed<Any> Any_default_instance_;
-
 // ===================================================================
 
 
@@ -163,13 +166,13 @@ extern ::google::protobuf::internal::ExplicitlyConstructed<Any> Any_default_inst
 #if !PROTOBUF_INLINE_NOT_IN_HEADERS
 // Any
 
-// optional string type_url = 1;
+// string type_url = 1;
 inline void Any::clear_type_url() {
   type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline const ::std::string& Any::type_url() const {
   // @@protoc_insertion_point(field_get:google.protobuf.Any.type_url)
-  return type_url_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  return type_url_.GetNoArena();
 }
 inline void Any::set_type_url(const ::std::string& value) {
   
@@ -207,13 +210,13 @@ inline void Any::set_allocated_type_url(::std::string* type_url) {
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.Any.type_url)
 }
 
-// optional bytes value = 2;
+// bytes value = 2;
 inline void Any::clear_value() {
   value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline const ::std::string& Any::value() const {
   // @@protoc_insertion_point(field_get:google.protobuf.Any.value)
-  return value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  return value_.GetNoArena();
 }
 inline void Any::set_value(const ::std::string& value) {
   
@@ -251,13 +254,11 @@ inline void Any::set_allocated_value(::std::string* value) {
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.Any.value)
 }
 
-inline const Any* Any::internal_default_instance() {
-  return &Any_default_instance_.get();
-}
 #endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // @@protoc_insertion_point(namespace_scope)
 
+
 }  // namespace protobuf
 }  // namespace google
 

File diff suppressed because it is too large
+ 220 - 291
src/google/protobuf/api.pb.cc


+ 131 - 114
src/google/protobuf/api.pb.h

@@ -24,12 +24,43 @@
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/metadata.h>
 #include <google/protobuf/message.h>
-#include <google/protobuf/repeated_field.h>
-#include <google/protobuf/extension_set.h>
+#include <google/protobuf/repeated_field.h>  // IWYU pragma: export
+#include <google/protobuf/extension_set.h>  // IWYU pragma: export
 #include <google/protobuf/unknown_field_set.h>
 #include <google/protobuf/source_context.pb.h>
 #include <google/protobuf/type.pb.h>
 // @@protoc_insertion_point(includes)
+namespace google {
+namespace protobuf {
+class Api;
+class ApiDefaultTypeInternal;
+extern ApiDefaultTypeInternal _Api_default_instance_;
+class Enum;
+class EnumDefaultTypeInternal;
+extern EnumDefaultTypeInternal _Enum_default_instance_;
+class EnumValue;
+class EnumValueDefaultTypeInternal;
+extern EnumValueDefaultTypeInternal _EnumValue_default_instance_;
+class Field;
+class FieldDefaultTypeInternal;
+extern FieldDefaultTypeInternal _Field_default_instance_;
+class Method;
+class MethodDefaultTypeInternal;
+extern MethodDefaultTypeInternal _Method_default_instance_;
+class Mixin;
+class MixinDefaultTypeInternal;
+extern MixinDefaultTypeInternal _Mixin_default_instance_;
+class Option;
+class OptionDefaultTypeInternal;
+extern OptionDefaultTypeInternal _Option_default_instance_;
+class SourceContext;
+class SourceContextDefaultTypeInternal;
+extern SourceContextDefaultTypeInternal _SourceContext_default_instance_;
+class Type;
+class TypeDefaultTypeInternal;
+extern TypeDefaultTypeInternal _Type_default_instance_;
+}  // namespace protobuf
+}  // namespace google
 
 namespace google {
 namespace protobuf {
@@ -37,12 +68,6 @@ namespace protobuf {
 // Internal implementation detail -- do not call these.
 void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fapi_2eproto();
 void LIBPROTOBUF_EXPORT protobuf_InitDefaults_google_2fprotobuf_2fapi_2eproto();
-void protobuf_AssignDesc_google_2fprotobuf_2fapi_2eproto();
-void protobuf_ShutdownFile_google_2fprotobuf_2fapi_2eproto();
-
-class Api;
-class Method;
-class Mixin;
 
 // ===================================================================
 
@@ -61,55 +86,58 @@ class LIBPROTOBUF_EXPORT Api : public ::google::protobuf::Message /* @@protoc_in
   static const ::google::protobuf::Descriptor* descriptor();
   static const Api& default_instance();
 
-  static const Api* internal_default_instance();
+  static inline const Api* internal_default_instance() {
+    return reinterpret_cast<const Api*>(
+               &_Api_default_instance_);
+  }
 
   void Swap(Api* other);
 
   // implements Message ----------------------------------------------
 
-  inline Api* New() const { return New(NULL); }
+  inline Api* New() const PROTOBUF_FINAL { return New(NULL); }
 
-  Api* New(::google::protobuf::Arena* arena) const;
-  void CopyFrom(const ::google::protobuf::Message& from);
-  void MergeFrom(const ::google::protobuf::Message& from);
+  Api* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
+  void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
+  void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void CopyFrom(const Api& from);
   void MergeFrom(const Api& from);
-  void Clear();
-  bool IsInitialized() const;
+  void Clear() PROTOBUF_FINAL;
+  bool IsInitialized() const PROTOBUF_FINAL;
 
-  size_t ByteSizeLong() const;
+  size_t ByteSizeLong() const PROTOBUF_FINAL;
   bool MergePartialFromCodedStream(
-      ::google::protobuf::io::CodedInputStream* input);
+      ::google::protobuf::io::CodedInputStream* input) PROTOBUF_FINAL;
   void SerializeWithCachedSizes(
-      ::google::protobuf::io::CodedOutputStream* output) const;
+      ::google::protobuf::io::CodedOutputStream* output) const PROTOBUF_FINAL;
   ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
-      bool deterministic, ::google::protobuf::uint8* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+      bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output)
+      const PROTOBUF_FINAL {
     return InternalSerializeWithCachedSizesToArray(false, output);
   }
-  int GetCachedSize() const { return _cached_size_; }
+  int GetCachedSize() const PROTOBUF_FINAL { return _cached_size_; }
   private:
   void SharedCtor();
   void SharedDtor();
-  void SetCachedSize(int size) const;
+  void SetCachedSize(int size) const PROTOBUF_FINAL;
   void InternalSwap(Api* other);
-  void UnsafeMergeFrom(const Api& from);
   private:
   inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
-    return _internal_metadata_.arena();
+    return NULL;
   }
   inline void* MaybeArenaPtr() const {
-    return _internal_metadata_.raw_arena_ptr();
+    return NULL;
   }
   public:
 
-  ::google::protobuf::Metadata GetMetadata() const;
+  ::google::protobuf::Metadata GetMetadata() const PROTOBUF_FINAL;
 
   // nested types ----------------------------------------------------
 
   // accessors -------------------------------------------------------
 
-  // optional string name = 1;
+  // string name = 1;
   void clear_name();
   static const int kNameFieldNumber = 1;
   const ::std::string& name() const;
@@ -144,7 +172,7 @@ class LIBPROTOBUF_EXPORT Api : public ::google::protobuf::Message /* @@protoc_in
   const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
       options() const;
 
-  // optional string version = 4;
+  // string version = 4;
   void clear_version();
   static const int kVersionFieldNumber = 4;
   const ::std::string& version() const;
@@ -155,7 +183,7 @@ class LIBPROTOBUF_EXPORT Api : public ::google::protobuf::Message /* @@protoc_in
   ::std::string* release_version();
   void set_allocated_version(::std::string* version);
 
-  // optional .google.protobuf.SourceContext source_context = 5;
+  // .google.protobuf.SourceContext source_context = 5;
   bool has_source_context() const;
   void clear_source_context();
   static const int kSourceContextFieldNumber = 5;
@@ -176,7 +204,7 @@ class LIBPROTOBUF_EXPORT Api : public ::google::protobuf::Message /* @@protoc_in
   const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin >&
       mixins() const;
 
-  // optional .google.protobuf.Syntax syntax = 7;
+  // .google.protobuf.Syntax syntax = 7;
   void clear_syntax();
   static const int kSyntaxFieldNumber = 7;
   ::google::protobuf::Syntax syntax() const;
@@ -196,13 +224,10 @@ class LIBPROTOBUF_EXPORT Api : public ::google::protobuf::Message /* @@protoc_in
   mutable int _cached_size_;
   friend void LIBPROTOBUF_EXPORT protobuf_InitDefaults_google_2fprotobuf_2fapi_2eproto_impl();
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fapi_2eproto_impl();
-  friend void protobuf_AssignDesc_google_2fprotobuf_2fapi_2eproto();
+  friend const ::google::protobuf::uint32* protobuf_Offsets_google_2fprotobuf_2fapi_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fapi_2eproto();
 
-  void InitAsDefaultInstance();
 };
-extern ::google::protobuf::internal::ExplicitlyConstructed<Api> Api_default_instance_;
-
 // -------------------------------------------------------------------
 
 class LIBPROTOBUF_EXPORT Method : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Method) */ {
@@ -220,55 +245,58 @@ class LIBPROTOBUF_EXPORT Method : public ::google::protobuf::Message /* @@protoc
   static const ::google::protobuf::Descriptor* descriptor();
   static const Method& default_instance();
 
-  static const Method* internal_default_instance();
+  static inline const Method* internal_default_instance() {
+    return reinterpret_cast<const Method*>(
+               &_Method_default_instance_);
+  }
 
   void Swap(Method* other);
 
   // implements Message ----------------------------------------------
 
-  inline Method* New() const { return New(NULL); }
+  inline Method* New() const PROTOBUF_FINAL { return New(NULL); }
 
-  Method* New(::google::protobuf::Arena* arena) const;
-  void CopyFrom(const ::google::protobuf::Message& from);
-  void MergeFrom(const ::google::protobuf::Message& from);
+  Method* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
+  void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
+  void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void CopyFrom(const Method& from);
   void MergeFrom(const Method& from);
-  void Clear();
-  bool IsInitialized() const;
+  void Clear() PROTOBUF_FINAL;
+  bool IsInitialized() const PROTOBUF_FINAL;
 
-  size_t ByteSizeLong() const;
+  size_t ByteSizeLong() const PROTOBUF_FINAL;
   bool MergePartialFromCodedStream(
-      ::google::protobuf::io::CodedInputStream* input);
+      ::google::protobuf::io::CodedInputStream* input) PROTOBUF_FINAL;
   void SerializeWithCachedSizes(
-      ::google::protobuf::io::CodedOutputStream* output) const;
+      ::google::protobuf::io::CodedOutputStream* output) const PROTOBUF_FINAL;
   ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
-      bool deterministic, ::google::protobuf::uint8* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+      bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output)
+      const PROTOBUF_FINAL {
     return InternalSerializeWithCachedSizesToArray(false, output);
   }
-  int GetCachedSize() const { return _cached_size_; }
+  int GetCachedSize() const PROTOBUF_FINAL { return _cached_size_; }
   private:
   void SharedCtor();
   void SharedDtor();
-  void SetCachedSize(int size) const;
+  void SetCachedSize(int size) const PROTOBUF_FINAL;
   void InternalSwap(Method* other);
-  void UnsafeMergeFrom(const Method& from);
   private:
   inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
-    return _internal_metadata_.arena();
+    return NULL;
   }
   inline void* MaybeArenaPtr() const {
-    return _internal_metadata_.raw_arena_ptr();
+    return NULL;
   }
   public:
 
-  ::google::protobuf::Metadata GetMetadata() const;
+  ::google::protobuf::Metadata GetMetadata() const PROTOBUF_FINAL;
 
   // nested types ----------------------------------------------------
 
   // accessors -------------------------------------------------------
 
-  // optional string name = 1;
+  // string name = 1;
   void clear_name();
   static const int kNameFieldNumber = 1;
   const ::std::string& name() const;
@@ -279,7 +307,7 @@ class LIBPROTOBUF_EXPORT Method : public ::google::protobuf::Message /* @@protoc
   ::std::string* release_name();
   void set_allocated_name(::std::string* name);
 
-  // optional string request_type_url = 2;
+  // string request_type_url = 2;
   void clear_request_type_url();
   static const int kRequestTypeUrlFieldNumber = 2;
   const ::std::string& request_type_url() const;
@@ -290,13 +318,13 @@ class LIBPROTOBUF_EXPORT Method : public ::google::protobuf::Message /* @@protoc
   ::std::string* release_request_type_url();
   void set_allocated_request_type_url(::std::string* request_type_url);
 
-  // optional bool request_streaming = 3;
+  // bool request_streaming = 3;
   void clear_request_streaming();
   static const int kRequestStreamingFieldNumber = 3;
   bool request_streaming() const;
   void set_request_streaming(bool value);
 
-  // optional string response_type_url = 4;
+  // string response_type_url = 4;
   void clear_response_type_url();
   static const int kResponseTypeUrlFieldNumber = 4;
   const ::std::string& response_type_url() const;
@@ -307,7 +335,7 @@ class LIBPROTOBUF_EXPORT Method : public ::google::protobuf::Message /* @@protoc
   ::std::string* release_response_type_url();
   void set_allocated_response_type_url(::std::string* response_type_url);
 
-  // optional bool response_streaming = 5;
+  // bool response_streaming = 5;
   void clear_response_streaming();
   static const int kResponseStreamingFieldNumber = 5;
   bool response_streaming() const;
@@ -325,7 +353,7 @@ class LIBPROTOBUF_EXPORT Method : public ::google::protobuf::Message /* @@protoc
   const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
       options() const;
 
-  // optional .google.protobuf.Syntax syntax = 7;
+  // .google.protobuf.Syntax syntax = 7;
   void clear_syntax();
   static const int kSyntaxFieldNumber = 7;
   ::google::protobuf::Syntax syntax() const;
@@ -345,13 +373,10 @@ class LIBPROTOBUF_EXPORT Method : public ::google::protobuf::Message /* @@protoc
   mutable int _cached_size_;
   friend void LIBPROTOBUF_EXPORT protobuf_InitDefaults_google_2fprotobuf_2fapi_2eproto_impl();
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fapi_2eproto_impl();
-  friend void protobuf_AssignDesc_google_2fprotobuf_2fapi_2eproto();
+  friend const ::google::protobuf::uint32* protobuf_Offsets_google_2fprotobuf_2fapi_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fapi_2eproto();
 
-  void InitAsDefaultInstance();
 };
-extern ::google::protobuf::internal::ExplicitlyConstructed<Method> Method_default_instance_;
-
 // -------------------------------------------------------------------
 
 class LIBPROTOBUF_EXPORT Mixin : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Mixin) */ {
@@ -369,55 +394,58 @@ class LIBPROTOBUF_EXPORT Mixin : public ::google::protobuf::Message /* @@protoc_
   static const ::google::protobuf::Descriptor* descriptor();
   static const Mixin& default_instance();
 
-  static const Mixin* internal_default_instance();
+  static inline const Mixin* internal_default_instance() {
+    return reinterpret_cast<const Mixin*>(
+               &_Mixin_default_instance_);
+  }
 
   void Swap(Mixin* other);
 
   // implements Message ----------------------------------------------
 
-  inline Mixin* New() const { return New(NULL); }
+  inline Mixin* New() const PROTOBUF_FINAL { return New(NULL); }
 
-  Mixin* New(::google::protobuf::Arena* arena) const;
-  void CopyFrom(const ::google::protobuf::Message& from);
-  void MergeFrom(const ::google::protobuf::Message& from);
+  Mixin* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
+  void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
+  void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void CopyFrom(const Mixin& from);
   void MergeFrom(const Mixin& from);
-  void Clear();
-  bool IsInitialized() const;
+  void Clear() PROTOBUF_FINAL;
+  bool IsInitialized() const PROTOBUF_FINAL;
 
-  size_t ByteSizeLong() const;
+  size_t ByteSizeLong() const PROTOBUF_FINAL;
   bool MergePartialFromCodedStream(
-      ::google::protobuf::io::CodedInputStream* input);
+      ::google::protobuf::io::CodedInputStream* input) PROTOBUF_FINAL;
   void SerializeWithCachedSizes(
-      ::google::protobuf::io::CodedOutputStream* output) const;
+      ::google::protobuf::io::CodedOutputStream* output) const PROTOBUF_FINAL;
   ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
-      bool deterministic, ::google::protobuf::uint8* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+      bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output)
+      const PROTOBUF_FINAL {
     return InternalSerializeWithCachedSizesToArray(false, output);
   }
-  int GetCachedSize() const { return _cached_size_; }
+  int GetCachedSize() const PROTOBUF_FINAL { return _cached_size_; }
   private:
   void SharedCtor();
   void SharedDtor();
-  void SetCachedSize(int size) const;
+  void SetCachedSize(int size) const PROTOBUF_FINAL;
   void InternalSwap(Mixin* other);
-  void UnsafeMergeFrom(const Mixin& from);
   private:
   inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
-    return _internal_metadata_.arena();
+    return NULL;
   }
   inline void* MaybeArenaPtr() const {
-    return _internal_metadata_.raw_arena_ptr();
+    return NULL;
   }
   public:
 
-  ::google::protobuf::Metadata GetMetadata() const;
+  ::google::protobuf::Metadata GetMetadata() const PROTOBUF_FINAL;
 
   // nested types ----------------------------------------------------
 
   // accessors -------------------------------------------------------
 
-  // optional string name = 1;
+  // string name = 1;
   void clear_name();
   static const int kNameFieldNumber = 1;
   const ::std::string& name() const;
@@ -428,7 +456,7 @@ class LIBPROTOBUF_EXPORT Mixin : public ::google::protobuf::Message /* @@protoc_
   ::std::string* release_name();
   void set_allocated_name(::std::string* name);
 
-  // optional string root = 2;
+  // string root = 2;
   void clear_root();
   static const int kRootFieldNumber = 2;
   const ::std::string& root() const;
@@ -448,13 +476,10 @@ class LIBPROTOBUF_EXPORT Mixin : public ::google::protobuf::Message /* @@protoc_
   mutable int _cached_size_;
   friend void LIBPROTOBUF_EXPORT protobuf_InitDefaults_google_2fprotobuf_2fapi_2eproto_impl();
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fapi_2eproto_impl();
-  friend void protobuf_AssignDesc_google_2fprotobuf_2fapi_2eproto();
+  friend const ::google::protobuf::uint32* protobuf_Offsets_google_2fprotobuf_2fapi_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fapi_2eproto();
 
-  void InitAsDefaultInstance();
 };
-extern ::google::protobuf::internal::ExplicitlyConstructed<Mixin> Mixin_default_instance_;
-
 // ===================================================================
 
 
@@ -463,13 +488,13 @@ extern ::google::protobuf::internal::ExplicitlyConstructed<Mixin> Mixin_default_
 #if !PROTOBUF_INLINE_NOT_IN_HEADERS
 // Api
 
-// optional string name = 1;
+// string name = 1;
 inline void Api::clear_name() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline const ::std::string& Api::name() const {
   // @@protoc_insertion_point(field_get:google.protobuf.Api.name)
-  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  return name_.GetNoArena();
 }
 inline void Api::set_name(const ::std::string& value) {
   
@@ -567,13 +592,13 @@ Api::options() const {
   return options_;
 }
 
-// optional string version = 4;
+// string version = 4;
 inline void Api::clear_version() {
   version_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline const ::std::string& Api::version() const {
   // @@protoc_insertion_point(field_get:google.protobuf.Api.version)
-  return version_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  return version_.GetNoArena();
 }
 inline void Api::set_version(const ::std::string& value) {
   
@@ -611,7 +636,7 @@ inline void Api::set_allocated_version(::std::string* version) {
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.Api.version)
 }
 
-// optional .google.protobuf.SourceContext source_context = 5;
+// .google.protobuf.SourceContext source_context = 5;
 inline bool Api::has_source_context() const {
   return this != internal_default_instance() && source_context_ != NULL;
 }
@@ -680,7 +705,7 @@ Api::mixins() const {
   return mixins_;
 }
 
-// optional .google.protobuf.Syntax syntax = 7;
+// .google.protobuf.Syntax syntax = 7;
 inline void Api::clear_syntax() {
   syntax_ = 0;
 }
@@ -694,20 +719,17 @@ inline void Api::set_syntax(::google::protobuf::Syntax value) {
   // @@protoc_insertion_point(field_set:google.protobuf.Api.syntax)
 }
 
-inline const Api* Api::internal_default_instance() {
-  return &Api_default_instance_.get();
-}
 // -------------------------------------------------------------------
 
 // Method
 
-// optional string name = 1;
+// string name = 1;
 inline void Method::clear_name() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline const ::std::string& Method::name() const {
   // @@protoc_insertion_point(field_get:google.protobuf.Method.name)
-  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  return name_.GetNoArena();
 }
 inline void Method::set_name(const ::std::string& value) {
   
@@ -745,13 +767,13 @@ inline void Method::set_allocated_name(::std::string* name) {
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.Method.name)
 }
 
-// optional string request_type_url = 2;
+// string request_type_url = 2;
 inline void Method::clear_request_type_url() {
   request_type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 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(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  return request_type_url_.GetNoArena();
 }
 inline void Method::set_request_type_url(const ::std::string& value) {
   
@@ -789,7 +811,7 @@ inline void Method::set_allocated_request_type_url(::std::string* request_type_u
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.Method.request_type_url)
 }
 
-// optional bool request_streaming = 3;
+// bool request_streaming = 3;
 inline void Method::clear_request_streaming() {
   request_streaming_ = false;
 }
@@ -803,13 +825,13 @@ inline void Method::set_request_streaming(bool value) {
   // @@protoc_insertion_point(field_set:google.protobuf.Method.request_streaming)
 }
 
-// optional string response_type_url = 4;
+// string response_type_url = 4;
 inline void Method::clear_response_type_url() {
   response_type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 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(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  return response_type_url_.GetNoArena();
 }
 inline void Method::set_response_type_url(const ::std::string& value) {
   
@@ -847,7 +869,7 @@ inline void Method::set_allocated_response_type_url(::std::string* response_type
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.Method.response_type_url)
 }
 
-// optional bool response_streaming = 5;
+// bool response_streaming = 5;
 inline void Method::clear_response_streaming() {
   response_streaming_ = false;
 }
@@ -891,7 +913,7 @@ Method::options() const {
   return options_;
 }
 
-// optional .google.protobuf.Syntax syntax = 7;
+// .google.protobuf.Syntax syntax = 7;
 inline void Method::clear_syntax() {
   syntax_ = 0;
 }
@@ -905,20 +927,17 @@ inline void Method::set_syntax(::google::protobuf::Syntax value) {
   // @@protoc_insertion_point(field_set:google.protobuf.Method.syntax)
 }
 
-inline const Method* Method::internal_default_instance() {
-  return &Method_default_instance_.get();
-}
 // -------------------------------------------------------------------
 
 // Mixin
 
-// optional string name = 1;
+// string name = 1;
 inline void Mixin::clear_name() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline const ::std::string& Mixin::name() const {
   // @@protoc_insertion_point(field_get:google.protobuf.Mixin.name)
-  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  return name_.GetNoArena();
 }
 inline void Mixin::set_name(const ::std::string& value) {
   
@@ -956,13 +975,13 @@ inline void Mixin::set_allocated_name(::std::string* name) {
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.Mixin.name)
 }
 
-// optional string root = 2;
+// string root = 2;
 inline void Mixin::clear_root() {
   root_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline const ::std::string& Mixin::root() const {
   // @@protoc_insertion_point(field_get:google.protobuf.Mixin.root)
-  return root_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  return root_.GetNoArena();
 }
 inline void Mixin::set_root(const ::std::string& value) {
   
@@ -1000,9 +1019,6 @@ inline void Mixin::set_allocated_root(::std::string* root) {
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.Mixin.root)
 }
 
-inline const Mixin* Mixin::internal_default_instance() {
-  return &Mixin_default_instance_.get();
-}
 #endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
 // -------------------------------------------------------------------
 
@@ -1011,6 +1027,7 @@ inline const Mixin* Mixin::internal_default_instance() {
 
 // @@protoc_insertion_point(namespace_scope)
 
+
 }  // namespace protobuf
 }  // namespace google
 

+ 1 - 0
src/google/protobuf/api.proto

@@ -40,6 +40,7 @@ option java_package = "com.google.protobuf";
 option java_outer_classname = "ApiProto";
 option java_multiple_files = true;
 option objc_class_prefix = "GPB";
+option go_package = "google.golang.org/genproto/protobuf/api;api";
 
 // Api is a light-weight descriptor for a protocol buffer service.
 message Api {

+ 14 - 4
src/google/protobuf/arena.cc

@@ -36,7 +36,7 @@
 
 #ifdef ADDRESS_SANITIZER
 #include <sanitizer/asan_interface.h>
-#endif
+#endif  // ADDRESS_SANITIZER
 
 namespace google {
 namespace protobuf {
@@ -141,7 +141,7 @@ Arena::Block* Arena::NewBlock(void* me, Block* my_last_block, size_t n,
   // malloc but it's not yet usable until we return it as part of an allocation.
   ASAN_POISON_MEMORY_REGION(
       reinterpret_cast<char*>(b) + b->pos, b->size - b->pos);
-#endif
+#endif  // ADDRESS_SANITIZER
   return b;
 }
 
@@ -205,7 +205,7 @@ void* Arena::AllocFromBlock(Block* b, size_t n) {
   b->pos = p + n;
 #ifdef ADDRESS_SANITIZER
   ASAN_UNPOISON_MEMORY_REGION(reinterpret_cast<char*>(b) + p, n);
-#endif
+#endif  // ADDRESS_SANITIZER
   return reinterpret_cast<char*>(b) + p;
 }
 
@@ -244,7 +244,7 @@ uint64 Arena::SpaceUsed() const {
   return space_used;
 }
 
-pair<uint64, uint64> Arena::SpaceAllocatedAndUsed() const {
+std::pair<uint64, uint64> Arena::SpaceAllocatedAndUsed() const {
   uint64 allocated = 0;
   uint64 used = 0;
 
@@ -265,9 +265,19 @@ uint64 Arena::FreeBlocks() {
     space_allocated += (b->size);
     Block* next = b->next;
     if (next != NULL) {
+#ifdef ADDRESS_SANITIZER
+      // This memory was provided by the underlying allocator as unpoisoned, so
+      // return it in an unpoisoned state.
+      ASAN_UNPOISON_MEMORY_REGION(reinterpret_cast<char*>(b), b->size);
+#endif  // ADDRESS_SANITIZER
       options_.block_dealloc(b, b->size);
     } else {
       if (owns_first_block_) {
+#ifdef ADDRESS_SANITIZER
+        // This memory was provided by the underlying allocator as unpoisoned,
+        // so return it in an unpoisoned state.
+        ASAN_UNPOISON_MEMORY_REGION(reinterpret_cast<char*>(b), b->size);
+#endif  // ADDRESS_SANITIZER
         options_.block_dealloc(b, b->size);
       } else {
         // User passed in the first block, skip free'ing the memory.

+ 31 - 0
src/google/protobuf/arena_test_util.h

@@ -31,9 +31,40 @@
 #ifndef GOOGLE_PROTOBUF_ARENA_TEST_UTIL_H__
 #define GOOGLE_PROTOBUF_ARENA_TEST_UTIL_H__
 
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arena.h>
 
 namespace google {
 namespace protobuf {
+
+template <typename T, bool use_arena>
+void TestParseCorruptedString(const T& message) {
+  int success_count = 0;
+  string s = message.SerializeAsString();
+  const int kMaxIters = 900;
+  const int stride = s.size() <= kMaxIters ? 1 : s.size() / kMaxIters;
+  const int start = stride == 1 || use_arena ? 0 : (stride + 1) / 2;
+  for (int i = start; i < s.size(); i += stride) {
+    for (int c = 1 + (i % 17); c < 256; c += 2 * c + (i & 3)) {
+      s[i] ^= c;
+      google::protobuf::Arena arena;
+      T* message =
+          google::protobuf::Arena::CreateMessage<T>(use_arena ? &arena : NULL);
+      if (message->ParseFromString(s)) {
+        ++success_count;
+      }
+      if (!use_arena) {
+        delete message;
+      }
+      s[i] ^= c;  // Restore s to its original state.
+    }
+  }
+  // This next line is a low bar.  But getting through the test without crashing
+  // due to use-after-free or other bugs is a big part of what we're checking.
+  GOOGLE_CHECK_GT(success_count, 0);
+}
+
 namespace internal {
 
 class NoHeapChecker {

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

@@ -249,7 +249,7 @@ TEST(ArenaTest, Parsing) {
   arena_message->ParseFromString(original.SerializeAsString());
   TestUtil::ExpectAllFieldsSet(*arena_message);
 
-  // Test that string fields have null terminator bytes (earlier bug).
+  // Test that string fields have nul terminator bytes (earlier bug).
   EXPECT_EQ(strlen(original.optional_string().c_str()),
             strlen(arena_message->optional_string().c_str()));
 }
@@ -1154,6 +1154,13 @@ TEST(ArenaTest, NoHeapAllocationsTest) {
   arena.Reset();
 }
 
+TEST(ArenaTest, ParseCorruptedString) {
+  TestAllTypes message;
+  TestUtil::SetAllFields(&message);
+  TestParseCorruptedString<TestAllTypes, true>(message);
+  TestParseCorruptedString<TestAllTypes, false>(message);
+}
+
 #ifndef GOOGLE_PROTOBUF_NO_RTTI
 // Test construction on an arena via generic MessageLite interface. We should be
 // able to successfully deserialize on the arena without incurring heap

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

@@ -44,7 +44,7 @@ void ArenaStringPtr::AssignWithDefault(const ::std::string* default_value,
   const ::std::string* other = *value.UnsafeRawStringPointer();
   // If the pointers are the same then do nothing.
   if (me != other) {
-    SetNoArena(default_value, value.GetNoArena(default_value));
+    SetNoArena(default_value, value.GetNoArena());
   }
 }
 

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

@@ -37,7 +37,6 @@
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/fastmem.h>
 #include <google/protobuf/arena.h>
-#include <google/protobuf/generated_message_util.h>
 
 
 
@@ -64,9 +63,7 @@ struct LIBPROTOBUF_EXPORT ArenaStringPtr {
   }
 
   // Basic accessors.
-  inline const ::std::string& Get(const ::std::string* /* default_value */) const {
-    return *ptr_;
-  }
+  inline const ::std::string& Get() const { return *ptr_; }
 
   inline ::std::string* Mutable(const ::std::string* default_value,
                            ::google::protobuf::Arena* arena) {
@@ -150,13 +147,12 @@ struct LIBPROTOBUF_EXPORT ArenaStringPtr {
     std::swap(ptr_, other->ptr_);
   }
 
-  // Frees storage (if not on an arena) and sets field to default value.
+  // Frees storage (if not on an arena).
   inline void Destroy(const ::std::string* default_value,
                       ::google::protobuf::Arena* arena) {
     if (arena == NULL && ptr_ != default_value) {
       delete ptr_;
     }
-    ptr_ = const_cast< ::std::string* >(default_value);
   }
 
   // Clears content, but keeps allocated string if arena != NULL, to avoid the
@@ -216,9 +212,7 @@ struct LIBPROTOBUF_EXPORT ArenaStringPtr {
 
   void AssignWithDefault(const ::std::string* default_value, ArenaStringPtr value);
 
-  inline const ::std::string& GetNoArena(const ::std::string* /* default_value */) const {
-    return *ptr_;
-  }
+  inline const ::std::string& GetNoArena() const { return *ptr_; }
 
   inline ::std::string* MutableNoArena(const ::std::string* default_value) {
     if (ptr_ == default_value) {
@@ -253,7 +247,6 @@ struct LIBPROTOBUF_EXPORT ArenaStringPtr {
     if (ptr_ != default_value) {
       delete ptr_;
     }
-    ptr_ = NULL;
   }
 
   inline void ClearToEmptyNoArena(const ::std::string* default_value) {
@@ -281,6 +274,10 @@ struct LIBPROTOBUF_EXPORT ArenaStringPtr {
     return &ptr_;
   }
 
+  inline bool IsDefault(const ::std::string* default_value) const {
+    return ptr_ == default_value;
+  }
+
  private:
   ::std::string* ptr_;
 

+ 10 - 12
src/google/protobuf/arenastring_unittest.cc

@@ -59,11 +59,11 @@ TEST(ArenaStringPtrTest, ArenaStringPtrOnHeap) {
   ArenaStringPtr field;
   ::std::string default_value = "default";
   field.UnsafeSetDefault(&default_value);
-  EXPECT_EQ(string("default"), field.Get(&default_value));
+  EXPECT_EQ(string("default"), field.Get());
   field.Set(&default_value, WrapString("Test short"), NULL);
-  EXPECT_EQ(string("Test short"), field.Get(&default_value));
+  EXPECT_EQ(string("Test short"), field.Get());
   field.Set(&default_value, WrapString("Test long long long long value"), NULL);
-  EXPECT_EQ(string("Test long long long long value"), field.Get(&default_value));
+  EXPECT_EQ(string("Test long long long long value"), field.Get());
   field.Set(&default_value, string(""), NULL);
   field.Destroy(&default_value, NULL);
 
@@ -71,11 +71,11 @@ TEST(ArenaStringPtrTest, ArenaStringPtrOnHeap) {
   field2.UnsafeSetDefault(&default_value);
   ::std::string* mut = field2.Mutable(&default_value, NULL);
   EXPECT_EQ(mut, field2.Mutable(&default_value, NULL));
-  EXPECT_EQ(mut, &field2.Get(&default_value));
+  EXPECT_EQ(mut, &field2.Get());
   EXPECT_NE(&default_value, mut);
   EXPECT_EQ(string("default"), *mut);
   *mut = "Test long long long long value";  // ensure string allocates storage
-  EXPECT_EQ(string("Test long long long long value"), field2.Get(&default_value));
+  EXPECT_EQ(string("Test long long long long value"), field2.Get());
   field2.Destroy(&default_value, NULL);
 }
 
@@ -84,12 +84,11 @@ TEST(ArenaStringPtrTest, ArenaStringPtrOnArena) {
   ArenaStringPtr field;
   ::std::string default_value = "default";
   field.UnsafeSetDefault(&default_value);
-  EXPECT_EQ(string("default"), field.Get(&default_value));
+  EXPECT_EQ(string("default"), field.Get());
   field.Set(&default_value, WrapString("Test short"), &arena);
-  EXPECT_EQ(string("Test short"), field.Get(&default_value));
+  EXPECT_EQ(string("Test short"), field.Get());
   field.Set(&default_value, WrapString("Test long long long long value"), &arena);
-  EXPECT_EQ(string("Test long long long long value"),
-            field.Get(&default_value));
+  EXPECT_EQ(string("Test long long long long value"), field.Get());
   field.Set(&default_value, string(""), &arena);
   field.Destroy(&default_value, &arena);
 
@@ -97,12 +96,11 @@ TEST(ArenaStringPtrTest, ArenaStringPtrOnArena) {
   field2.UnsafeSetDefault(&default_value);
   ::std::string* mut = field2.Mutable(&default_value, &arena);
   EXPECT_EQ(mut, field2.Mutable(&default_value, &arena));
-  EXPECT_EQ(mut, &field2.Get(&default_value));
+  EXPECT_EQ(mut, &field2.Get());
   EXPECT_NE(&default_value, mut);
   EXPECT_EQ(string("default"), *mut);
   *mut = "Test long long long long value";  // ensure string allocates storage
-  EXPECT_EQ(string("Test long long long long value"),
-            field2.Get(&default_value));
+  EXPECT_EQ(string("Test long long long long value"), field2.Get());
   field2.Destroy(&default_value, &arena);
 }
 

+ 5 - 5
src/google/protobuf/compiler/code_generator.cc

@@ -46,7 +46,7 @@ namespace compiler {
 CodeGenerator::~CodeGenerator() {}
 
 bool CodeGenerator::GenerateAll(
-    const vector<const FileDescriptor*>& files,
+    const std::vector<const FileDescriptor*>& files,
     const string& parameter,
     GeneratorContext* generator_context,
     string* error) const {
@@ -85,18 +85,18 @@ io::ZeroCopyOutputStream* GeneratorContext::OpenForInsert(
 }
 
 void GeneratorContext::ListParsedFiles(
-    vector<const FileDescriptor*>* output) {
+    std::vector<const FileDescriptor*>* output) {
   GOOGLE_LOG(FATAL) << "This GeneratorContext does not support ListParsedFiles";
 }
 
 // Parses a set of comma-delimited name/value pairs.
 void ParseGeneratorParameter(const string& text,
-                             vector<pair<string, string> >* output) {
-  vector<string> parts = Split(text, ",", true);
+                             std::vector<std::pair<string, string> >* output) {
+  std::vector<string> parts = Split(text, ",", true);
 
   for (int i = 0; i < parts.size(); i++) {
     string::size_type equals_pos = parts[i].find_first_of('=');
-    pair<string, string> value;
+    std::pair<string, string> value;
     if (equals_pos == string::npos) {
       value.first = parts[i];
       value.second = "";

+ 3 - 3
src/google/protobuf/compiler/code_generator.h

@@ -90,7 +90,7 @@ class LIBPROTOC_EXPORT CodeGenerator {
   //
   // Returns true if successful.  Otherwise, sets *error to a description of
   // the problem (e.g. "invalid parameter") and returns false.
-  virtual bool GenerateAll(const vector<const FileDescriptor*>& files,
+  virtual bool GenerateAll(const std::vector<const FileDescriptor*>& files,
                            const string& parameter,
                            GeneratorContext* generator_context,
                            string* error) const;
@@ -141,7 +141,7 @@ class LIBPROTOC_EXPORT GeneratorContext {
   // Returns a vector of FileDescriptors for all the files being compiled
   // in this run.  Useful for languages, such as Go, that treat files
   // differently when compiled as a set rather than individually.
-  virtual void ListParsedFiles(vector<const FileDescriptor*>* output);
+  virtual void ListParsedFiles(std::vector<const FileDescriptor*>* output);
 
  private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GeneratorContext);
@@ -158,7 +158,7 @@ typedef GeneratorContext OutputDirectory;
 // parses to the pairs:
 //   ("foo", "bar"), ("baz", ""), ("qux", "corge")
 extern void ParseGeneratorParameter(const string&,
-            vector<pair<string, string> >*);
+            std::vector<std::pair<string, string> >*);
 
 }  // namespace compiler
 }  // namespace protobuf

+ 41 - 38
src/google/protobuf/compiler/command_line_interface.cc

@@ -173,7 +173,8 @@ bool VerifyDirectoryExists(const string& path) {
 // directories listed in |filename|.
 bool TryCreateParentDirectory(const string& prefix, const string& filename) {
   // Recursively create parent directories to the output file.
-  vector<string> parts = Split(filename, "/", true);
+  std::vector<string> parts =
+      Split(filename, "/", true);
   string path_so_far = prefix;
   for (int i = 0; i < parts.size() - 1; i++) {
     path_so_far += parts[i];
@@ -344,7 +345,7 @@ class CommandLineInterface::ErrorPrinter : public MultiFileErrorCollector,
 // them all to disk on demand.
 class CommandLineInterface::GeneratorContextImpl : public GeneratorContext {
  public:
-  GeneratorContextImpl(const vector<const FileDescriptor*>& parsed_files);
+  GeneratorContextImpl(const std::vector<const FileDescriptor*>& parsed_files);
   ~GeneratorContextImpl();
 
   // Write all files in the directory to disk at the given output location,
@@ -360,14 +361,14 @@ class CommandLineInterface::GeneratorContextImpl : public GeneratorContext {
   void AddJarManifest();
 
   // Get name of all output files.
-  void GetOutputFilenames(vector<string>* output_filenames);
+  void GetOutputFilenames(std::vector<string>* output_filenames);
 
   // implements GeneratorContext --------------------------------------
   io::ZeroCopyOutputStream* Open(const string& filename);
   io::ZeroCopyOutputStream* OpenForAppend(const string& filename);
   io::ZeroCopyOutputStream* OpenForInsert(
       const string& filename, const string& insertion_point);
-  void ListParsedFiles(vector<const FileDescriptor*>* output) {
+  void ListParsedFiles(std::vector<const FileDescriptor*>* output) {
     *output = parsed_files_;
   }
 
@@ -376,8 +377,8 @@ class CommandLineInterface::GeneratorContextImpl : public GeneratorContext {
 
   // map instead of hash_map so that files are written in order (good when
   // writing zips).
-  map<string, string*> files_;
-  const vector<const FileDescriptor*>& parsed_files_;
+  std::map<string, string*> files_;
+  const std::vector<const FileDescriptor*>& parsed_files_;
   bool had_error_;
 };
 
@@ -414,7 +415,7 @@ class CommandLineInterface::MemoryOutputStream
 // -------------------------------------------------------------------
 
 CommandLineInterface::GeneratorContextImpl::GeneratorContextImpl(
-    const vector<const FileDescriptor*>& parsed_files)
+    const std::vector<const FileDescriptor*>& parsed_files)
     : parsed_files_(parsed_files),
       had_error_(false) {
 }
@@ -433,7 +434,7 @@ bool CommandLineInterface::GeneratorContextImpl::WriteAllToDisk(
     return false;
   }
 
-  for (map<string, string*>::const_iterator iter = files_.begin();
+  for (std::map<string, string*>::const_iterator iter = files_.begin();
        iter != files_.end(); ++iter) {
     const string& relative_filename = iter->first;
     const char* data = iter->second->data();
@@ -521,7 +522,7 @@ bool CommandLineInterface::GeneratorContextImpl::WriteAllToZip(
   io::FileOutputStream stream(file_descriptor);
   ZipWriter zip_writer(&stream);
 
-  for (map<string, string*>::const_iterator iter = files_.begin();
+  for (std::map<string, string*>::const_iterator iter = files_.begin();
        iter != files_.end(); ++iter) {
     zip_writer.Write(iter->first, *iter->second);
   }
@@ -550,8 +551,8 @@ void CommandLineInterface::GeneratorContextImpl::AddJarManifest() {
 }
 
 void CommandLineInterface::GeneratorContextImpl::GetOutputFilenames(
-    vector<string>* output_filenames) {
-  for (map<string, string*>::iterator iter = files_.begin();
+    std::vector<string>* output_filenames) {
+  for (std::map<string, string*>::iterator iter = files_.begin();
        iter != files_.end(); ++iter) {
     output_filenames->push_back(iter->first);
   }
@@ -774,7 +775,7 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) {
   ErrorPrinter error_collector(error_format_, &source_tree);
   Importer importer(&source_tree, &error_collector);
 
-  vector<const FileDescriptor*> parsed_files;
+  std::vector<const FileDescriptor*> parsed_files;
 
   // Parse each file.
   for (int i = 0; i < input_files_.size(); i++) {
@@ -984,7 +985,7 @@ CommandLineInterface::ParseArgumentStatus
 CommandLineInterface::ParseArguments(int argc, const char* const argv[]) {
   executable_name_ = argv[0];
 
-  vector<string> arguments;
+  std::vector<string> arguments;
   for (int i = 1; i < argc; ++i) {
     arguments.push_back(argv[i]);
   }
@@ -1030,7 +1031,7 @@ CommandLineInterface::ParseArguments(int argc, const char* const argv[]) {
     // Don't use make_pair as the old/default standard library on Solaris
     // doesn't support it without explicit template parameters, which are
     // incompatible with C++0x's make_pair.
-    proto_path_.push_back(pair<string, string>("", "."));
+    proto_path_.push_back(std::pair<string, string>("", "."));
   }
 
   // Check some errror cases.
@@ -1153,7 +1154,7 @@ CommandLineInterface::InterpretArgument(const string& name,
     // Java's -classpath (and some other languages) delimits path components
     // with colons.  Let's accept that syntax too just to make things more
     // intuitive.
-    vector<string> parts = Split(
+    std::vector<string> parts = Split(
         value, kPathSeparator, true);
 
     for (int i = 0; i < parts.size(); i++) {
@@ -1190,19 +1191,21 @@ CommandLineInterface::InterpretArgument(const string& name,
       // Don't use make_pair as the old/default standard library on Solaris
       // doesn't support it without explicit template parameters, which are
       // incompatible with C++0x's make_pair.
-      proto_path_.push_back(pair<string, string>(virtual_path, disk_path));
+      proto_path_.push_back(std::pair<string, string>(virtual_path, disk_path));
     }
 
   } else if (name == "--direct_dependencies") {
     if (direct_dependencies_explicitly_set_) {
       std::cerr << name << " may only be passed once. To specify multiple "
                            "direct dependencies, pass them all as a single "
-                           "parameter separated by ':'." << std::endl;
+                           "parameter separated by ':'."
+                << std::endl;
       return PARSE_ARGUMENT_FAIL;
     }
 
     direct_dependencies_explicitly_set_ = true;
-    vector<string> direct = Split(value, ":", true);
+    std::vector<string> direct = Split(
+        value, ":", true);
     GOOGLE_DCHECK(direct_dependencies_.empty());
     direct_dependencies_.insert(direct.begin(), direct.end());
 
@@ -1476,7 +1479,7 @@ void CommandLineInterface::PrintHelpText() {
 }
 
 bool CommandLineInterface::GenerateOutput(
-    const vector<const FileDescriptor*>& parsed_files,
+    const std::vector<const FileDescriptor*>& parsed_files,
     const OutputDirective& output_directive,
     GeneratorContext* generator_context) {
   // Call the generator.
@@ -1522,12 +1525,12 @@ bool CommandLineInterface::GenerateOutput(
 }
 
 bool CommandLineInterface::GenerateDependencyManifestFile(
-    const vector<const FileDescriptor*>& parsed_files,
+    const std::vector<const FileDescriptor*>& parsed_files,
     const GeneratorContextMap& output_directories,
     DiskSourceTree* source_tree) {
   FileDescriptorSet file_set;
 
-  set<const FileDescriptor*> already_seen;
+  std::set<const FileDescriptor*> already_seen;
   for (int i = 0; i < parsed_files.size(); i++) {
     GetTransitiveDependencies(parsed_files[i],
                               false,
@@ -1536,12 +1539,12 @@ bool CommandLineInterface::GenerateDependencyManifestFile(
                               file_set.mutable_file());
   }
 
-  vector<string> output_filenames;
+  std::vector<string> output_filenames;
   for (GeneratorContextMap::const_iterator iter = output_directories.begin();
        iter != output_directories.end(); ++iter) {
     const string& location = iter->first;
     GeneratorContextImpl* directory = iter->second;
-    vector<string> relative_output_filenames;
+    std::vector<string> relative_output_filenames;
     directory->GetOutputFilenames(&relative_output_filenames);
     for (int i = 0; i < relative_output_filenames.size(); i++) {
       string output_filename = location + relative_output_filenames[i];
@@ -1594,7 +1597,7 @@ bool CommandLineInterface::GenerateDependencyManifestFile(
 }
 
 bool CommandLineInterface::GeneratePluginOutput(
-    const vector<const FileDescriptor*>& parsed_files,
+    const std::vector<const FileDescriptor*>& parsed_files,
     const string& plugin_name,
     const string& parameter,
     GeneratorContext* generator_context,
@@ -1607,7 +1610,7 @@ bool CommandLineInterface::GeneratePluginOutput(
     request.set_parameter(parameter);
   }
 
-  set<const FileDescriptor*> already_seen;
+  std::set<const FileDescriptor*> already_seen;
   for (int i = 0; i < parsed_files.size(); i++) {
     request.add_file_to_generate(parsed_files[i]->name());
     GetTransitiveDependencies(parsed_files[i],
@@ -1737,11 +1740,11 @@ bool CommandLineInterface::EncodeOrDecode(const DescriptorPool* pool) {
 }
 
 bool CommandLineInterface::WriteDescriptorSet(
-    const vector<const FileDescriptor*> parsed_files) {
+    const std::vector<const FileDescriptor*> parsed_files) {
   FileDescriptorSet file_set;
 
   if (imports_in_descriptor_set_) {
-    set<const FileDescriptor*> already_seen;
+    std::set<const FileDescriptor*> already_seen;
     for (int i = 0; i < parsed_files.size(); i++) {
       GetTransitiveDependencies(parsed_files[i],
                                 true,  // Include json_name
@@ -1749,7 +1752,7 @@ bool CommandLineInterface::WriteDescriptorSet(
                                 &already_seen, file_set.mutable_file());
     }
   } else {
-    set<const FileDescriptor*> already_seen;
+    std::set<const FileDescriptor*> already_seen;
     for (int i = 0; i < parsed_files.size(); i++) {
       if (!already_seen.insert(parsed_files[i]).second) {
         continue;
@@ -1794,7 +1797,7 @@ void CommandLineInterface::GetTransitiveDependencies(
     const FileDescriptor* file,
     bool include_json_name,
     bool include_source_code_info,
-    set<const FileDescriptor*>* already_seen,
+    std::set<const FileDescriptor*>* already_seen,
     RepeatedPtrField<FileDescriptorProto>* output) {
   if (!already_seen->insert(file).second) {
     // Already saw this file.  Skip.
@@ -1853,11 +1856,11 @@ namespace {
 // parameter will contain the direct children (when groups are ignored in the
 // tree) of the given descriptor for the caller to traverse. The declaration
 // order of the nested messages is also preserved.
-typedef pair<int, int> FieldRange;
-void GatherOccupiedFieldRanges(const Descriptor* descriptor,
-                               set<FieldRange>* ranges,
-                               vector<const Descriptor*>* nested_messages) {
-  set<const Descriptor*> groups;
+typedef std::pair<int, int> FieldRange;
+void GatherOccupiedFieldRanges(
+    const Descriptor* descriptor, std::set<FieldRange>* ranges,
+    std::vector<const Descriptor*>* nested_messages) {
+  std::set<const Descriptor*> groups;
   for (int i = 0; i < descriptor->field_count(); ++i) {
     const FieldDescriptor* fd = descriptor->field(i);
     ranges->insert(FieldRange(fd->number(), fd->number() + 1));
@@ -1889,11 +1892,11 @@ void GatherOccupiedFieldRanges(const Descriptor* descriptor,
 // Actually prints the formatted free field numbers for given message name and
 // occupied ranges.
 void FormatFreeFieldNumbers(const string& name,
-                            const set<FieldRange>& ranges) {
+                            const std::set<FieldRange>& ranges) {
   string output;
   StringAppendF(&output, "%-35s free:", name.c_str());
   int next_free_number = 1;
-  for (set<FieldRange>::const_iterator i = ranges.begin();
+  for (std::set<FieldRange>::const_iterator i = ranges.begin();
        i != ranges.end(); ++i) {
     // This happens when groups re-use parent field numbers, in which
     // case we skip the FieldRange entirely.
@@ -1920,8 +1923,8 @@ void FormatFreeFieldNumbers(const string& name,
 
 void CommandLineInterface::PrintFreeFieldNumbers(
     const Descriptor* descriptor) {
-  set<FieldRange> ranges;
-  vector<const Descriptor*> nested_messages;
+  std::set<FieldRange> ranges;
+  std::vector<const Descriptor*> nested_messages;
   GatherOccupiedFieldRanges(descriptor, &ranges, &nested_messages);
 
   for (int i = 0; i < nested_messages.size(); ++i) {

+ 18 - 19
src/google/protobuf/compiler/command_line_interface.h

@@ -56,9 +56,7 @@ class FileDescriptorProto;   // descriptor.pb.h
 template<typename T> class RepeatedPtrField;  // repeated_field.h
 
 }  // namespace protobuf
-}  // namespace google
 
-namespace google {
 namespace protobuf {
 namespace compiler {
 
@@ -247,24 +245,24 @@ class LIBPROTOC_EXPORT CommandLineInterface {
 
   // Generate the given output file from the given input.
   struct OutputDirective;  // see below
-  bool GenerateOutput(const vector<const FileDescriptor*>& parsed_files,
+  bool GenerateOutput(const std::vector<const FileDescriptor*>& parsed_files,
                       const OutputDirective& output_directive,
                       GeneratorContext* generator_context);
-  bool GeneratePluginOutput(const vector<const FileDescriptor*>& parsed_files,
-                            const string& plugin_name,
-                            const string& parameter,
-                            GeneratorContext* generator_context,
-                            string* error);
+  bool GeneratePluginOutput(
+      const std::vector<const FileDescriptor*>& parsed_files,
+      const string& plugin_name, const string& parameter,
+      GeneratorContext* generator_context, string* error);
 
   // Implements --encode and --decode.
   bool EncodeOrDecode(const DescriptorPool* pool);
 
   // Implements the --descriptor_set_out option.
-  bool WriteDescriptorSet(const vector<const FileDescriptor*> parsed_files);
+  bool WriteDescriptorSet(
+      const std::vector<const FileDescriptor*> parsed_files);
 
   // Implements the --dependency_out option
   bool GenerateDependencyManifestFile(
-      const vector<const FileDescriptor*>& parsed_files,
+      const std::vector<const FileDescriptor*>& parsed_files,
       const GeneratorContextMap& output_directories,
       DiskSourceTree* source_tree);
 
@@ -281,7 +279,7 @@ class LIBPROTOC_EXPORT CommandLineInterface {
       const FileDescriptor* file,
       bool include_json_name,
       bool include_source_code_info,
-      set<const FileDescriptor*>* already_seen,
+      std::set<const FileDescriptor*>* already_seen,
       RepeatedPtrField<FileDescriptorProto>* output);
 
   // Implements the --print_free_field_numbers. This function prints free field
@@ -315,16 +313,16 @@ class LIBPROTOC_EXPORT CommandLineInterface {
     CodeGenerator* generator;
     string help_text;
   };
-  typedef map<string, GeneratorInfo> GeneratorMap;
+  typedef std::map<string, GeneratorInfo> GeneratorMap;
   GeneratorMap generators_by_flag_name_;
   GeneratorMap generators_by_option_name_;
   // A map from generator names to the parameters specified using the option
   // flag. For example, if the user invokes the compiler with:
   //   protoc --foo_out=outputdir --foo_opt=enable_bar ...
   // Then there will be an entry ("--foo_out", "enable_bar") in this map.
-  map<string, string> generator_parameters_;
+  std::map<string, string> generator_parameters_;
   // Similar to generator_parameters_, but stores the parameters for plugins.
-  map<string, string> plugin_parameters_;
+  std::map<string, string> plugin_parameters_;
 
   // See AllowPlugins().  If this is empty, plugins aren't allowed.
   string plugin_prefix_;
@@ -332,7 +330,7 @@ class LIBPROTOC_EXPORT CommandLineInterface {
   // Maps specific plugin names to files.  When executing a plugin, this map
   // is searched first to find the plugin executable.  If not found here, the
   // PATH (or other OS-specific search strategy) is searched.
-  map<string, string> plugins_;
+  std::map<string, string> plugins_;
 
   // Stuff parsed from command line.
   enum Mode {
@@ -358,12 +356,13 @@ class LIBPROTOC_EXPORT CommandLineInterface {
 
   ErrorFormat error_format_;
 
-  vector<pair<string, string> > proto_path_;  // Search path for proto files.
-  vector<string> input_files_;                // Names of the input proto files.
+  std::vector<std::pair<string, string> >
+      proto_path_;                   // Search path for proto files.
+  std::vector<string> input_files_;  // Names of the input proto files.
 
   // Names of proto files which are allowed to be imported. Used by build
   // systems to enforce depend-on-what-you-import.
-  set<string> direct_dependencies_;
+  std::set<string> direct_dependencies_;
   bool direct_dependencies_explicitly_set_;
 
   // output_directives_ lists all the files we are supposed to output and what
@@ -374,7 +373,7 @@ class LIBPROTOC_EXPORT CommandLineInterface {
     string parameter;
     string output_location;
   };
-  vector<OutputDirective> output_directives_;
+  std::vector<OutputDirective> output_directives_;
 
   // When using --encode or --decode, this names the type we are encoding or
   // decoding.  (Empty string indicates --decode_raw.)

+ 4 - 4
src/google/protobuf/compiler/command_line_interface_unittest.cc

@@ -217,7 +217,7 @@ class CommandLineInterfaceTest : public testing::Test {
   string captured_stdout_;
 
   // Pointers which need to be deleted later.
-  vector<CodeGenerator*> mock_generators_to_delete_;
+  std::vector<CodeGenerator*> mock_generators_to_delete_;
 
   NullCodeGenerator* null_generator_;
 };
@@ -291,7 +291,7 @@ void CommandLineInterfaceTest::TearDown() {
 }
 
 void CommandLineInterfaceTest::Run(const string& command) {
-  vector<string> args = Split(command, " ", true);
+  std::vector<string> args = Split(command, " ", true);
 
   if (!disallow_plugins_) {
     cli_.AllowPlugins("prefix-");
@@ -759,7 +759,7 @@ TEST_F(CommandLineInterfaceTest, TrailingBackslash) {
 
 TEST_F(CommandLineInterfaceTest, Win32ErrorMessage) {
   EXPECT_EQ("The system cannot find the file specified.\r\n",
-    Subprocess::Win32ErrorMessage(ERROR_FILE_NOT_FOUND));
+            Subprocess::Win32ErrorMessage(ERROR_FILE_NOT_FOUND));
 }
 
 #endif  // defined(_WIN32) || defined(__CYGWIN__)
@@ -1856,7 +1856,7 @@ class EncodeDecodeTest : public testing::Test {
   enum ReturnCode { SUCCESS, ERROR };
 
   bool Run(const string& command) {
-    vector<string> args;
+    std::vector<string> args;
     args.push_back("protoc");
     SplitStringUsing(command, " ", &args);
     args.push_back("--proto_path=" + TestSourceDir());

+ 1 - 1
src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc

@@ -114,7 +114,7 @@ class MockGeneratorContext : public GeneratorContext {
   }
 
  private:
-  map<string, string*> files_;
+  std::map<string, string*> files_;
 };
 
 TEST(BootstrapTest, GeneratedDescriptorMatches) {

+ 21 - 18
src/google/protobuf/compiler/cpp/cpp_enum.cc

@@ -70,7 +70,7 @@ EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor,
 EnumGenerator::~EnumGenerator() {}
 
 void EnumGenerator::FillForwardDeclaration(
-    map<string, const EnumDescriptor*>* enum_names) {
+    std::map<string, const EnumDescriptor*>* enum_names) {
   if (!options_.proto_h) {
     return;
   }
@@ -78,7 +78,7 @@ void EnumGenerator::FillForwardDeclaration(
 }
 
 void EnumGenerator::GenerateDefinition(io::Printer* printer) {
-  map<string, string> vars;
+  std::map<string, string> vars;
   vars["classname"] = classname_;
   vars["short_name"] = descriptor_->name();
   vars["enumbase"] = classname_ + (options_.proto_h ? " : int" : "");
@@ -180,7 +180,7 @@ GenerateGetEnumDescriptorSpecializations(io::Printer* printer) {
 }
 
 void EnumGenerator::GenerateSymbolImports(io::Printer* printer) {
-  map<string, string> vars;
+  std::map<string, string> vars;
   vars["nested_name"] = descriptor_->name();
   vars["classname"] = classname_;
   vars["constexpr"] = options_.proto_h ? "constexpr " : "";
@@ -229,33 +229,36 @@ void EnumGenerator::GenerateSymbolImports(io::Printer* printer) {
   }
 }
 
-void EnumGenerator::GenerateDescriptorInitializer(
-    io::Printer* printer, int index) {
-  map<string, string> vars;
-  vars["classname"] = classname_;
-  vars["index"] = SimpleItoa(index);
+void EnumGenerator::GenerateDescriptorInitializer(io::Printer* printer) {
+  std::map<string, string> vars;
+  vars["index"] = SimpleItoa(descriptor_->index());
+  vars["index_in_metadata"] = SimpleItoa(index_in_metadata_);
 
   if (descriptor_->containing_type() == NULL) {
     printer->Print(vars,
-      "$classname$_descriptor_ = file->enum_type($index$);\n");
+                   "file_level_enum_descriptors[$index_in_metadata$] = "
+                   "file->enum_type($index$);\n");
   } else {
     vars["parent"] = ClassName(descriptor_->containing_type(), false);
     printer->Print(vars,
-      "$classname$_descriptor_ = $parent$_descriptor_->enum_type($index$);\n");
+                   "file_level_enum_descriptors[$index_in_metadata$] = "
+                   "$parent$_descriptor->enum_type($index$);\n");
   }
 }
 
 void EnumGenerator::GenerateMethods(io::Printer* printer) {
-  map<string, string> vars;
+  std::map<string, string> vars;
   vars["classname"] = classname_;
+  vars["index_in_metadata"] = SimpleItoa(index_in_metadata_);
   vars["constexpr"] = options_.proto_h ? "constexpr " : "";
 
   if (HasDescriptorMethods(descriptor_->file(), options_)) {
-    printer->Print(vars,
-      "const ::google::protobuf::EnumDescriptor* $classname$_descriptor() {\n"
-      "  protobuf_AssignDescriptorsOnce();\n"
-      "  return $classname$_descriptor_;\n"
-      "}\n");
+    printer->Print(
+        vars,
+        "const ::google::protobuf::EnumDescriptor* $classname$_descriptor() {\n"
+        "  protobuf_AssignDescriptorsOnce();\n"
+        "  return file_level_enum_descriptors[$index_in_metadata$];\n"
+        "}\n");
   }
 
   printer->Print(vars,
@@ -266,13 +269,13 @@ void EnumGenerator::GenerateMethods(io::Printer* printer) {
   // each number once by first constructing a set containing all valid
   // numbers, then printing a case statement for each element.
 
-  set<int> numbers;
+  std::set<int> numbers;
   for (int j = 0; j < descriptor_->value_count(); j++) {
     const EnumValueDescriptor* value = descriptor_->value(j);
     numbers.insert(value->number());
   }
 
-  for (set<int>::iterator iter = numbers.begin();
+  for (std::set<int>::iterator iter = numbers.begin();
        iter != numbers.end(); ++iter) {
     printer->Print(
       "    case $number$:\n",

+ 6 - 2
src/google/protobuf/compiler/cpp/cpp_enum.h

@@ -66,7 +66,8 @@ class EnumGenerator {
   // enums. A given key in enum_names will map from an enum class name to the
   // EnumDescriptor that was responsible for its inclusion in the map. This can
   // be used to associate the descriptor with the code generated for it.
-  void FillForwardDeclaration(map<string, const EnumDescriptor*>* enum_names);
+  void FillForwardDeclaration(
+      std::map<string, const EnumDescriptor*>* enum_names);
 
   // Generate header code defining the enum.  This code should be placed
   // within the enum's package namespace, but NOT within any class, even for
@@ -87,7 +88,7 @@ class EnumGenerator {
 
   // Generate code that initializes the global variable storing the enum's
   // descriptor.
-  void GenerateDescriptorInitializer(io::Printer* printer, int index);
+  void GenerateDescriptorInitializer(io::Printer* printer);
 
   // Generate non-inline methods related to the enum, such as IsValidValue().
   // Goes in the .cc file.
@@ -100,6 +101,9 @@ class EnumGenerator {
   // whether to generate the *_ARRAYSIZE constant.
   const bool generate_array_size_;
 
+  int index_in_metadata_;
+
+  friend class FileGenerator;
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator);
 };
 

+ 13 - 12
src/google/protobuf/compiler/cpp/cpp_enum_field.cc

@@ -46,7 +46,7 @@ namespace cpp {
 namespace {
 
 void SetEnumVariables(const FieldDescriptor* descriptor,
-                      map<string, string>* variables,
+                      std::map<string, string>* variables,
                       const Options& options) {
   SetCommonFieldVariables(descriptor, variables, options);
   const EnumValueDescriptor* default_value = descriptor->default_value_enum();
@@ -82,7 +82,7 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
 void EnumFieldGenerator::
 GenerateInlineAccessorDefinitions(io::Printer* printer,
                                   bool is_inline) const {
-  map<string, string> variables(variables_);
+  std::map<string, string> variables(variables_);
   variables["inline"] = is_inline ? "inline " : "";
   printer->Print(variables,
     "$inline$$type$ $classname$::$name$() const {\n"
@@ -121,6 +121,11 @@ GenerateConstructorCode(io::Printer* printer) const {
   printer->Print(variables_, "$name$_ = $default$;\n");
 }
 
+void EnumFieldGenerator::
+GenerateCopyConstructorCode(io::Printer* printer) const {
+  printer->Print(variables_, "$name$_ = from.$name$_;\n");
+}
+
 void EnumFieldGenerator::
 GenerateMergeFromCodedStream(io::Printer* printer) const {
   printer->Print(variables_,
@@ -142,7 +147,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
     } else {
       printer->Print(
         "} else {\n"
-        "  unknown_fields_stream.WriteVarint32($tag$);\n"
+        "  unknown_fields_stream.WriteVarint32($tag$u);\n"
         "  unknown_fields_stream.WriteVarint32(value);\n",
         "tag", SimpleItoa(internal::WireFormat::MakeTag(descriptor_)));
     }
@@ -186,7 +191,7 @@ EnumOneofFieldGenerator::~EnumOneofFieldGenerator() {}
 void EnumOneofFieldGenerator::
 GenerateInlineAccessorDefinitions(io::Printer* printer,
                                   bool is_inline) const {
-  map<string, string> variables(variables_);
+  std::map<string, string> variables(variables_);
   variables["inline"] = is_inline ? "inline " : "";
   printer->Print(variables,
     "$inline$$type$ $classname$::$name$() const {\n"
@@ -223,8 +228,9 @@ GenerateSwappingCode(io::Printer* printer) const {
 
 void EnumOneofFieldGenerator::
 GenerateConstructorCode(io::Printer* printer) const {
-  printer->Print(variables_,
-    "  $classname$_default_oneof_instance_->$name$_ = $default$;\n");
+  printer->Print(
+      variables_,
+      "  $classname$_default_oneof_instance_.$name$_ = $default$;\n");
 }
 
 // ===================================================================
@@ -262,7 +268,7 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
 void RepeatedEnumFieldGenerator::
 GenerateInlineAccessorDefinitions(io::Printer* printer,
                                   bool is_inline) const {
-  map<string, string> variables(variables_);
+  std::map<string, string> variables(variables_);
   variables["inline"] = is_inline ? "inline " : "";
   printer->Print(variables,
     "$inline$$type$ $classname$::$name$(int index) const {\n"
@@ -310,11 +316,6 @@ GenerateMergingCode(io::Printer* printer) const {
   printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
 }
 
-void RepeatedEnumFieldGenerator::
-GenerateUnsafeMergingCode(io::Printer* printer) const {
-  printer->Print(variables_, "$name$_.UnsafeMergeFrom(from.$name$_);\n");
-}
-
 void RepeatedEnumFieldGenerator::
 GenerateSwappingCode(io::Printer* printer) const {
   printer->Print(variables_, "$name$_.UnsafeArenaSwap(&other->$name$_);\n");

Some files were not shown because too many files changed in this diff