فهرست منبع

Down integrate from Google internal branch for C++ and Java.

- Maps for C++ lite
- C++ Arena optimizations.
- Java Lite runtime code size optimization.

Change-Id: I7537a4357c1cb385d23f9e8aa7ffdfeefe079f13
Jisi Liu 10 سال پیش
والد
کامیت
885b612f74
100فایلهای تغییر یافته به همراه5034 افزوده شده و 1785 حذف شده
  1. 35 3
      generate_descriptor_proto.sh
  2. 3 3
      java/src/main/java/com/google/protobuf/AbstractMessage.java
  3. 1 1
      java/src/main/java/com/google/protobuf/BoundedByteString.java
  4. 5 2
      java/src/main/java/com/google/protobuf/ByteString.java
  5. 1 1
      java/src/main/java/com/google/protobuf/Descriptors.java
  6. 7 4
      java/src/main/java/com/google/protobuf/DynamicMessage.java
  7. 19 37
      java/src/main/java/com/google/protobuf/FieldSet.java
  8. 199 13
      java/src/main/java/com/google/protobuf/GeneratedMessage.java
  9. 129 16
      java/src/main/java/com/google/protobuf/GeneratedMessageLite.java
  10. 206 43
      java/src/main/java/com/google/protobuf/LazyFieldLite.java
  11. 5 1
      java/src/main/java/com/google/protobuf/LiteralByteString.java
  12. 2 2
      java/src/main/java/com/google/protobuf/Message.java
  13. 36 24
      java/src/main/java/com/google/protobuf/MessageReflection.java
  14. 6 2
      java/src/main/java/com/google/protobuf/RopeByteString.java
  15. 63 56
      java/src/main/java/com/google/protobuf/TextFormat.java
  16. 82 0
      java/src/main/java/com/google/protobuf/WireFormat.java
  17. 1 1
      java/src/test/java/com/google/protobuf/GeneratedMessageTest.java
  18. 138 1
      java/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
  19. 19 0
      java/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
  20. 22 2
      java/src/test/java/com/google/protobuf/LiteralByteStringTest.java
  21. 14 0
      java/src/test/java/com/google/protobuf/MapForProto2Test.java
  22. 0 1
      java/src/test/java/com/google/protobuf/MapTest.java
  23. 28 0
      java/src/test/java/com/google/protobuf/RopeByteStringTest.java
  24. 9 0
      java/src/test/java/com/google/protobuf/lazy_fields_lite.proto
  25. 7 0
      java/src/test/java/com/google/protobuf/map_for_proto2_lite_test.proto
  26. 7 0
      java/src/test/java/com/google/protobuf/map_for_proto2_test.proto
  27. 1 0
      java/src/test/java/com/google/protobuf/map_test.proto
  28. 1 0
      java/src/test/java/com/google/protobuf/test_bad_identifiers.proto
  29. 2 1
      python/google/protobuf/internal/message_test.py
  30. 1 1
      python/google/protobuf/internal/text_format_test.py
  31. 9 6
      python/google/protobuf/pyext/descriptor.cc
  32. 3 2
      python/google/protobuf/pyext/message.cc
  33. 4 3
      python/google/protobuf/pyext/repeated_composite_container.cc
  34. 3 2
      python/google/protobuf/pyext/repeated_scalar_container.cc
  35. 16 3
      src/Makefile.am
  36. 47 20
      src/google/protobuf/arena.cc
  37. 136 20
      src/google/protobuf/arena.h
  38. 49 0
      src/google/protobuf/arena_test_util.cc
  39. 59 0
      src/google/protobuf/arena_test_util.h
  40. 196 31
      src/google/protobuf/arena_unittest.cc
  41. 112 91
      src/google/protobuf/compiler/command_line_interface.cc
  42. 2 3
      src/google/protobuf/compiler/command_line_interface_unittest.cc
  43. 2 1
      src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
  44. 6 3
      src/google/protobuf/compiler/cpp/cpp_enum.cc
  45. 73 40
      src/google/protobuf/compiler/cpp/cpp_enum_field.cc
  46. 6 3
      src/google/protobuf/compiler/cpp/cpp_enum_field.h
  47. 1 1
      src/google/protobuf/compiler/cpp/cpp_field.h
  48. 32 10
      src/google/protobuf/compiler/cpp/cpp_file.cc
  49. 8 3
      src/google/protobuf/compiler/cpp/cpp_helpers.cc
  50. 4 0
      src/google/protobuf/compiler/cpp/cpp_helpers.h
  51. 117 27
      src/google/protobuf/compiler/cpp/cpp_map_field.cc
  52. 2 1
      src/google/protobuf/compiler/cpp/cpp_map_field.h
  53. 50 45
      src/google/protobuf/compiler/cpp/cpp_message.cc
  54. 2 2
      src/google/protobuf/compiler/cpp/cpp_message.h
  55. 157 113
      src/google/protobuf/compiler/cpp/cpp_message_field.cc
  56. 8 3
      src/google/protobuf/compiler/cpp/cpp_message_field.h
  57. 29 23
      src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
  58. 6 3
      src/google/protobuf/compiler/cpp/cpp_primitive_field.h
  59. 92 76
      src/google/protobuf/compiler/cpp/cpp_string_field.cc
  60. 6 3
      src/google/protobuf/compiler/cpp/cpp_string_field.h
  61. 1 0
      src/google/protobuf/compiler/java/java_field.h
  62. 2 2
      src/google/protobuf/compiler/java/java_helpers.cc
  63. 10 0
      src/google/protobuf/compiler/java/java_helpers.h
  64. 4 6
      src/google/protobuf/compiler/java/java_lazy_message_field.cc
  65. 65 36
      src/google/protobuf/compiler/java/java_map_field.cc
  66. 1 0
      src/google/protobuf/compiler/java/java_map_field.h
  67. 201 83
      src/google/protobuf/compiler/java/java_message.cc
  68. 1 1
      src/google/protobuf/compiler/java/java_message.h
  69. 3 0
      src/google/protobuf/compiler/java/java_primitive_field.cc
  70. 1 1
      src/google/protobuf/compiler/java/java_shared_code_generator.cc
  71. 1 1
      src/google/protobuf/compiler/java/java_string_field.cc
  72. 4 4
      src/google/protobuf/compiler/mock_code_generator.cc
  73. 64 30
      src/google/protobuf/compiler/parser.cc
  74. 24 13
      src/google/protobuf/compiler/parser.h
  75. 165 41
      src/google/protobuf/compiler/parser_unittest.cc
  76. 7 6
      src/google/protobuf/compiler/plugin.cc
  77. 393 2
      src/google/protobuf/compiler/plugin.pb.cc
  78. 74 81
      src/google/protobuf/compiler/plugin.pb.h
  79. 2 0
      src/google/protobuf/compiler/plugin.proto
  80. 60 28
      src/google/protobuf/descriptor.cc
  81. 12 12
      src/google/protobuf/descriptor.h
  82. 905 54
      src/google/protobuf/descriptor.pb.cc
  83. 419 407
      src/google/protobuf/descriptor.pb.h
  84. 19 4
      src/google/protobuf/descriptor.proto
  85. 14 14
      src/google/protobuf/descriptor_database.cc
  86. 3 3
      src/google/protobuf/descriptor_database_unittest.cc
  87. 0 54
      src/google/protobuf/descriptor_pb2_test.py
  88. 2 2
      src/google/protobuf/descriptor_unittest.cc
  89. 10 6
      src/google/protobuf/extension_set.cc
  90. 4 3
      src/google/protobuf/extension_set_heavy.cc
  91. 1 4
      src/google/protobuf/generated_enum_reflection.h
  92. 46 0
      src/google/protobuf/generated_enum_util.h
  93. 23 18
      src/google/protobuf/generated_message_reflection.cc
  94. 15 62
      src/google/protobuf/io/coded_stream.cc
  95. 34 22
      src/google/protobuf/io/coded_stream.h
  96. 2 2
      src/google/protobuf/io/coded_stream_unittest.cc
  97. 1 0
      src/google/protobuf/io/gzip_stream.cc
  98. 1 1
      src/google/protobuf/io/zero_copy_stream_impl_lite.h
  99. 1 1
      src/google/protobuf/lite_unittest.cc
  100. 153 28
      src/google/protobuf/map.h

+ 35 - 3
generate_descriptor_proto.sh

@@ -27,7 +27,39 @@ __EOF__
 fi
 fi
 
 
 cd src
 cd src
-make $@ protoc &&
-  ./protoc --cpp_out=dllexport_decl=LIBPROTOBUF_EXPORT:. google/protobuf/descriptor.proto && \
-  ./protoc --cpp_out=dllexport_decl=LIBPROTOC_EXPORT:. google/protobuf/compiler/plugin.proto
+CORE_PROTO_IS_CORRECT=0
+while [ $CORE_PROTO_IS_CORRECT -ne 1 ]
+do
+  CORE_PROTO_IS_CORRECT=1
+  cp google/protobuf/descriptor.pb.h google/protobuf/descriptor.pb.h.tmp
+  cp google/protobuf/descriptor.pb.cc google/protobuf/descriptor.pb.cc.tmp
+  cp google/protobuf/compiler/plugin.pb.h google/protobuf/compiler/plugin.pb.h.tmp
+  cp google/protobuf/compiler/plugin.pb.cc google/protobuf/compiler/plugin.pb.cc.tmp
+
+  make -j8 $@ protoc &&
+    ./protoc --cpp_out=dllexport_decl=LIBPROTOBUF_EXPORT:. google/protobuf/descriptor.proto && \
+    ./protoc --cpp_out=dllexport_decl=LIBPROTOC_EXPORT:. google/protobuf/compiler/plugin.proto
+
+  diff google/protobuf/descriptor.pb.h google/protobuf/descriptor.pb.h.tmp > /dev/null
+  if test $? -ne 0; then
+    CORE_PROTO_IS_CORRECT=0
+  fi
+  diff google/protobuf/descriptor.pb.cc google/protobuf/descriptor.pb.cc.tmp > /dev/null
+  if test $? -ne 0; then
+    CORE_PROTO_IS_CORRECT=0
+  fi
+  diff google/protobuf/compiler/plugin.pb.h google/protobuf/compiler/plugin.pb.h.tmp > /dev/null
+  if test $? -ne 0; then
+    CORE_PROTO_IS_CORRECT=0
+  fi
+  diff google/protobuf/compiler/plugin.pb.cc google/protobuf/compiler/plugin.pb.cc.tmp > /dev/null
+  if test $? -ne 0; then
+    CORE_PROTO_IS_CORRECT=0
+  fi
+
+  rm google/protobuf/descriptor.pb.h.tmp
+  rm google/protobuf/descriptor.pb.cc.tmp
+  rm google/protobuf/compiler/plugin.pb.h.tmp
+  rm google/protobuf/compiler/plugin.pb.cc.tmp
+done
 cd ..
 cd ..

+ 3 - 3
java/src/main/java/com/google/protobuf/AbstractMessage.java

@@ -83,10 +83,10 @@ public abstract class AbstractMessage extends AbstractMessageLite
   }
   }
 
 
   public void writeTo(final CodedOutputStream output) throws IOException {
   public void writeTo(final CodedOutputStream output) throws IOException {
-    MessageReflection.writeMessageTo(this, output, false);
+    MessageReflection.writeMessageTo(this, getAllFields(), output, false);
   }
   }
 
 
-  private int memoizedSize = -1;
+  protected int memoizedSize = -1;
 
 
   public int getSerializedSize() {
   public int getSerializedSize() {
     int size = memoizedSize;
     int size = memoizedSize;
@@ -94,7 +94,7 @@ public abstract class AbstractMessage extends AbstractMessageLite
       return size;
       return size;
     }
     }
 
 
-    memoizedSize = MessageReflection.getSerializedSize(this);
+    memoizedSize = MessageReflection.getSerializedSize(this, getAllFields());
     return memoizedSize;
     return memoizedSize;
   }
   }
 
 

+ 1 - 1
java/src/main/java/com/google/protobuf/BoundedByteString.java

@@ -30,8 +30,8 @@
 
 
 package com.google.protobuf;
 package com.google.protobuf;
 
 
-import java.io.InvalidObjectException;
 import java.io.IOException;
 import java.io.IOException;
+import java.io.InvalidObjectException;
 import java.io.ObjectInputStream;
 import java.io.ObjectInputStream;
 import java.util.NoSuchElementException;
 import java.util.NoSuchElementException;
 
 

+ 5 - 2
java/src/main/java/com/google/protobuf/ByteString.java

@@ -76,6 +76,9 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
   static final int MIN_READ_FROM_CHUNK_SIZE = 0x100;  // 256b
   static final int MIN_READ_FROM_CHUNK_SIZE = 0x100;  // 256b
   static final int MAX_READ_FROM_CHUNK_SIZE = 0x2000;  // 8k
   static final int MAX_READ_FROM_CHUNK_SIZE = 0x2000;  // 8k
 
 
+  // Defined by java.nio.charset.Charset
+  protected static final String UTF_8 = "UTF-8";
+
   /**
   /**
    * Empty {@code ByteString}.
    * Empty {@code ByteString}.
    */
    */
@@ -267,7 +270,7 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
    */
    */
   public static ByteString copyFromUtf8(String text) {
   public static ByteString copyFromUtf8(String text) {
     try {
     try {
-      return new LiteralByteString(text.getBytes("UTF-8"));
+      return new LiteralByteString(text.getBytes(UTF_8));
     } catch (UnsupportedEncodingException e) {
     } catch (UnsupportedEncodingException e) {
       throw new RuntimeException("UTF-8 not supported?", e);
       throw new RuntimeException("UTF-8 not supported?", e);
     }
     }
@@ -622,7 +625,7 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
    */
    */
   public String toStringUtf8() {
   public String toStringUtf8() {
     try {
     try {
-      return toString("UTF-8");
+      return toString(UTF_8);
     } catch (UnsupportedEncodingException e) {
     } catch (UnsupportedEncodingException e) {
       throw new RuntimeException("UTF-8 not supported?", e);
       throw new RuntimeException("UTF-8 not supported?", e);
     }
     }

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

@@ -897,7 +897,7 @@ public final class Descriptors {
       return (type == Type.STRING) && (getFile().getOptions().getJavaStringCheckUtf8());
       return (type == Type.STRING) && (getFile().getOptions().getJavaStringCheckUtf8());
     }
     }
 
 
-    boolean isMapField() {
+    public boolean isMapField() {
       return getType() == Type.MESSAGE && isRepeated()
       return getType() == Type.MESSAGE && isRepeated()
           && getMessageType().getOptions().getMapEntry();
           && getMessageType().getOptions().getMapEntry();
     }
     }

+ 7 - 4
java/src/main/java/com/google/protobuf/DynamicMessage.java

@@ -35,8 +35,8 @@ import com.google.protobuf.Descriptors.EnumValueDescriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import com.google.protobuf.Descriptors.OneofDescriptor;
 import com.google.protobuf.Descriptors.OneofDescriptor;
 
 
-import java.io.InputStream;
 import java.io.IOException;
 import java.io.IOException;
+import java.io.InputStream;
 import java.util.Collections;
 import java.util.Collections;
 import java.util.List;
 import java.util.List;
 import java.util.Map;
 import java.util.Map;
@@ -600,9 +600,12 @@ public final class DynamicMessage extends AbstractMessage {
       }
       }
       // TODO(xiaofeng): Re-enable this check after Orgstore is fixed to not
       // TODO(xiaofeng): Re-enable this check after Orgstore is fixed to not
       // set incorrect EnumValueDescriptors.
       // set incorrect EnumValueDescriptors.
-      // if (field.getEnumType() != ((EnumValueDescriptor) value).getType()) {
-      //   throw new IllegalArgumentException(
-      //     "EnumValueDescriptor doesn't match Enum Field.");
+      // EnumDescriptor fieldType = field.getEnumType();
+      // EnumDescriptor fieldValueType = ((EnumValueDescriptor) value).getType();
+      // if (fieldType != fieldValueType) {
+      //  throw new IllegalArgumentException(String.format(
+      //      "EnumDescriptor %s of field doesn't match EnumDescriptor %s of field value",
+      //      fieldType.getFullName(), fieldValueType.getFullName()));
       // }
       // }
     }
     }
 
 

+ 19 - 37
java/src/main/java/com/google/protobuf/FieldSet.java

@@ -553,42 +553,13 @@ final class FieldSet<FieldDescriptorType extends
       CodedInputStream input,
       CodedInputStream input,
       final WireFormat.FieldType type,
       final WireFormat.FieldType type,
       boolean checkUtf8) throws IOException {
       boolean checkUtf8) throws IOException {
-    switch (type) {
-      case DOUBLE  : return input.readDouble  ();
-      case FLOAT   : return input.readFloat   ();
-      case INT64   : return input.readInt64   ();
-      case UINT64  : return input.readUInt64  ();
-      case INT32   : return input.readInt32   ();
-      case FIXED64 : return input.readFixed64 ();
-      case FIXED32 : return input.readFixed32 ();
-      case BOOL    : return input.readBool    ();
-      case STRING  : if (checkUtf8) {
-                       return input.readStringRequireUtf8();
-                     } else {
-                       return input.readString();
-                     }
-      case BYTES   : return input.readBytes   ();
-      case UINT32  : return input.readUInt32  ();
-      case SFIXED32: return input.readSFixed32();
-      case SFIXED64: return input.readSFixed64();
-      case SINT32  : return input.readSInt32  ();
-      case SINT64  : return input.readSInt64  ();
-
-      case GROUP:
-        throw new IllegalArgumentException(
-          "readPrimitiveField() cannot handle nested groups.");
-      case MESSAGE:
-        throw new IllegalArgumentException(
-          "readPrimitiveField() cannot handle embedded messages.");
-      case ENUM:
-        // We don't handle enums because we don't know what to do if the
-        // value is not recognized.
-        throw new IllegalArgumentException(
-          "readPrimitiveField() cannot handle enums.");
+    if (checkUtf8) {
+      return WireFormat.readPrimitiveField(input, type,
+          WireFormat.Utf8Validation.STRICT);
+    } else {
+      return WireFormat.readPrimitiveField(input, type,
+          WireFormat.Utf8Validation.LOOSE);
     }
     }
-
-    throw new RuntimeException(
-      "There is no way to get here, but the compiler thinks otherwise.");
   }
   }
 
 
 
 
@@ -685,9 +656,15 @@ final class FieldSet<FieldDescriptorType extends
       case FIXED64 : output.writeFixed64NoTag ((Long       ) value); break;
       case FIXED64 : output.writeFixed64NoTag ((Long       ) value); break;
       case FIXED32 : output.writeFixed32NoTag ((Integer    ) value); break;
       case FIXED32 : output.writeFixed32NoTag ((Integer    ) value); break;
       case BOOL    : output.writeBoolNoTag    ((Boolean    ) value); break;
       case BOOL    : output.writeBoolNoTag    ((Boolean    ) value); break;
-      case STRING  : output.writeStringNoTag  ((String     ) value); break;
       case GROUP   : output.writeGroupNoTag   ((MessageLite) value); break;
       case GROUP   : output.writeGroupNoTag   ((MessageLite) value); break;
       case MESSAGE : output.writeMessageNoTag ((MessageLite) value); break;
       case MESSAGE : output.writeMessageNoTag ((MessageLite) value); break;
+      case STRING:
+        if (value instanceof ByteString) {
+          output.writeBytesNoTag((ByteString) value);
+        } else {
+          output.writeStringNoTag((String) value);
+        }
+        break;
       case BYTES:
       case BYTES:
         if (value instanceof ByteString) {
         if (value instanceof ByteString) {
           output.writeBytesNoTag((ByteString) value);
           output.writeBytesNoTag((ByteString) value);
@@ -843,7 +820,6 @@ final class FieldSet<FieldDescriptorType extends
       case FIXED64 : return CodedOutputStream.computeFixed64SizeNoTag ((Long       )value);
       case FIXED64 : return CodedOutputStream.computeFixed64SizeNoTag ((Long       )value);
       case FIXED32 : return CodedOutputStream.computeFixed32SizeNoTag ((Integer    )value);
       case FIXED32 : return CodedOutputStream.computeFixed32SizeNoTag ((Integer    )value);
       case BOOL    : return CodedOutputStream.computeBoolSizeNoTag    ((Boolean    )value);
       case BOOL    : return CodedOutputStream.computeBoolSizeNoTag    ((Boolean    )value);
-      case STRING  : return CodedOutputStream.computeStringSizeNoTag  ((String     )value);
       case GROUP   : return CodedOutputStream.computeGroupSizeNoTag   ((MessageLite)value);
       case GROUP   : return CodedOutputStream.computeGroupSizeNoTag   ((MessageLite)value);
       case BYTES   :
       case BYTES   :
         if (value instanceof ByteString) {
         if (value instanceof ByteString) {
@@ -851,6 +827,12 @@ final class FieldSet<FieldDescriptorType extends
         } else {
         } else {
           return CodedOutputStream.computeByteArraySizeNoTag((byte[]) value);
           return CodedOutputStream.computeByteArraySizeNoTag((byte[]) value);
         }
         }
+      case STRING  :
+        if (value instanceof ByteString) {
+          return CodedOutputStream.computeBytesSizeNoTag((ByteString) value);
+        } else {
+          return CodedOutputStream.computeStringSizeNoTag((String) value);
+        }
       case UINT32  : return CodedOutputStream.computeUInt32SizeNoTag  ((Integer    )value);
       case UINT32  : return CodedOutputStream.computeUInt32SizeNoTag  ((Integer    )value);
       case SFIXED32: return CodedOutputStream.computeSFixed32SizeNoTag((Integer    )value);
       case SFIXED32: return CodedOutputStream.computeSFixed32SizeNoTag((Integer    )value);
       case SFIXED64: return CodedOutputStream.computeSFixed64SizeNoTag((Long       )value);
       case SFIXED64: return CodedOutputStream.computeSFixed64SizeNoTag((Long       )value);

+ 199 - 13
java/src/main/java/com/google/protobuf/GeneratedMessage.java

@@ -109,8 +109,15 @@ public abstract class GeneratedMessage extends AbstractMessage
     return internalGetFieldAccessorTable().descriptor;
     return internalGetFieldAccessorTable().descriptor;
   }
   }
 
 
-  /** Internal helper which returns a mutable map. */
-  private Map<FieldDescriptor, Object> getAllFieldsMutable() {
+  /**
+   * Internal helper to return a modifiable map containing all the fields.
+   * The returned Map is modifialbe so that the caller can add additional
+   * extension fields to implement {@link #getAllFields()}.
+   *
+   * @param getBytesForString whether to generate ByteString for string fields
+   */
+  private Map<FieldDescriptor, Object> getAllFieldsMutable(
+      boolean getBytesForString) {
     final TreeMap<FieldDescriptor, Object> result =
     final TreeMap<FieldDescriptor, Object> result =
       new TreeMap<FieldDescriptor, Object>();
       new TreeMap<FieldDescriptor, Object>();
     final Descriptor descriptor = internalGetFieldAccessorTable().descriptor;
     final Descriptor descriptor = internalGetFieldAccessorTable().descriptor;
@@ -122,7 +129,12 @@ public abstract class GeneratedMessage extends AbstractMessage
         }
         }
       } else {
       } else {
         if (hasField(field)) {
         if (hasField(field)) {
-          result.put(field, getField(field));
+          if (getBytesForString
+              && field.getJavaType() == FieldDescriptor.JavaType.STRING) {
+            result.put(field, getFieldRaw(field));
+          } else {
+            result.put(field, getField(field));
+          }
         }
         }
       }
       }
     }
     }
@@ -161,7 +173,23 @@ public abstract class GeneratedMessage extends AbstractMessage
 
 
   //@Override (Java 1.6 override semantics, but we must support 1.5)
   //@Override (Java 1.6 override semantics, but we must support 1.5)
   public Map<FieldDescriptor, Object> getAllFields() {
   public Map<FieldDescriptor, Object> getAllFields() {
-    return Collections.unmodifiableMap(getAllFieldsMutable());
+    return Collections.unmodifiableMap(
+        getAllFieldsMutable(/* getBytesForString = */ false));
+  }
+
+  /**
+   * Returns a collection of all the fields in this message which are set
+   * and their corresponding values.  A singular ("required" or "optional")
+   * field is set iff hasField() returns true for that field.  A "repeated"
+   * field is set iff getRepeatedFieldCount() is greater than zero.  The
+   * values are exactly what would be returned by calling
+   * {@link #getFieldRaw(Descriptors.FieldDescriptor)} for each field.  The map
+   * is guaranteed to be a sorted map, so iterating over it will return fields
+   * in order by field number.
+   */
+  Map<FieldDescriptor, Object> getAllFieldsRaw() {
+    return Collections.unmodifiableMap(
+        getAllFieldsMutable(/* getBytesForString = */ true));
   }
   }
 
 
   //@Override (Java 1.6 override semantics, but we must support 1.5)
   //@Override (Java 1.6 override semantics, but we must support 1.5)
@@ -184,6 +212,18 @@ public abstract class GeneratedMessage extends AbstractMessage
     return internalGetFieldAccessorTable().getField(field).get(this);
     return internalGetFieldAccessorTable().getField(field).get(this);
   }
   }
 
 
+  /**
+   * Obtains the value of the given field, or the default value if it is
+   * not set.  For primitive fields, the boxed primitive value is returned.
+   * For enum fields, the EnumValueDescriptor for the value is returned. For
+   * embedded message fields, the sub-message is returned.  For repeated
+   * fields, a java.util.List is returned. For present string fields, a
+   * ByteString is returned representing the bytes that the field contains.
+   */
+  Object getFieldRaw(final FieldDescriptor field) {
+    return internalGetFieldAccessorTable().getField(field).getRaw(this);
+  }
+
   //@Override (Java 1.6 override semantics, but we must support 1.5)
   //@Override (Java 1.6 override semantics, but we must support 1.5)
   public int getRepeatedFieldCount(final FieldDescriptor field) {
   public int getRepeatedFieldCount(final FieldDescriptor field) {
     return internalGetFieldAccessorTable().getField(field)
     return internalGetFieldAccessorTable().getField(field)
@@ -214,6 +254,24 @@ public abstract class GeneratedMessage extends AbstractMessage
     return unknownFields.mergeFieldFrom(tag, input);
     return unknownFields.mergeFieldFrom(tag, input);
   }
   }
 
 
+  @Override
+  public void writeTo(final CodedOutputStream output) throws IOException {
+    MessageReflection.writeMessageTo(this, getAllFieldsRaw(), output, false);
+  }
+
+  @Override
+  public int getSerializedSize() {
+    int size = memoizedSize;
+    if (size != -1) {
+      return size;
+    }
+
+    memoizedSize = MessageReflection.getSerializedSize(
+        this, getAllFieldsRaw());
+    return memoizedSize;
+  }
+
+
 
 
   /**
   /**
    * Used by parsing constructors in generated classes.
    * Used by parsing constructors in generated classes.
@@ -563,6 +621,15 @@ public abstract class GeneratedMessage extends AbstractMessage
       throw new RuntimeException(
       throw new RuntimeException(
           "No map fields found in " + getClass().getName());
           "No map fields found in " + getClass().getName());
     }
     }
+
+    /** Like {@link internalGetMapField} but return a mutable version. */
+    @SuppressWarnings({"unused", "rawtypes"})
+    protected MapField internalGetMutableMapField(int fieldNumber) {
+      // Note that we can't use descriptor names here because this method will
+      // be called when descriptor is being initialized.
+      throw new RuntimeException(
+          "No map fields found in " + getClass().getName());
+    }
   }
   }
 
 
   // =================================================================
   // =================================================================
@@ -825,7 +892,16 @@ public abstract class GeneratedMessage extends AbstractMessage
 
 
     @Override
     @Override
     public Map<FieldDescriptor, Object> getAllFields() {
     public Map<FieldDescriptor, Object> getAllFields() {
-      final Map<FieldDescriptor, Object> result = super.getAllFieldsMutable();
+      final Map<FieldDescriptor, Object> result =
+          super.getAllFieldsMutable(/* getBytesForString = */ false);
+      result.putAll(getExtensionFields());
+      return Collections.unmodifiableMap(result);
+    }
+
+    @Override
+    public Map<FieldDescriptor, Object> getAllFieldsRaw() {
+      final Map<FieldDescriptor, Object> result =
+          super.getAllFieldsMutable(/* getBytesForString = */ false);
       result.putAll(getExtensionFields());
       result.putAll(getExtensionFields());
       return Collections.unmodifiableMap(result);
       return Collections.unmodifiableMap(result);
     }
     }
@@ -1761,6 +1837,10 @@ public abstract class GeneratedMessage extends AbstractMessage
               fields[i] = new SingularEnumFieldAccessor(
               fields[i] = new SingularEnumFieldAccessor(
                   field, camelCaseNames[i], messageClass, builderClass,
                   field, camelCaseNames[i], messageClass, builderClass,
                   containingOneofCamelCaseName);
                   containingOneofCamelCaseName);
+            } else if (field.getJavaType() == FieldDescriptor.JavaType.STRING) {
+              fields[i] = new SingularStringFieldAccessor(
+                  field, camelCaseNames[i], messageClass, builderClass,
+                  containingOneofCamelCaseName);
             } else {
             } else {
               fields[i] = new SingularFieldAccessor(
               fields[i] = new SingularFieldAccessor(
                   field, camelCaseNames[i], messageClass, builderClass,
                   field, camelCaseNames[i], messageClass, builderClass,
@@ -1817,9 +1897,13 @@ public abstract class GeneratedMessage extends AbstractMessage
     private interface FieldAccessor {
     private interface FieldAccessor {
       Object get(GeneratedMessage message);
       Object get(GeneratedMessage message);
       Object get(GeneratedMessage.Builder builder);
       Object get(GeneratedMessage.Builder builder);
+      Object getRaw(GeneratedMessage message);
+      Object getRaw(GeneratedMessage.Builder builder);
       void set(Builder builder, Object value);
       void set(Builder builder, Object value);
       Object getRepeated(GeneratedMessage message, int index);
       Object getRepeated(GeneratedMessage message, int index);
       Object getRepeated(GeneratedMessage.Builder builder, int index);
       Object getRepeated(GeneratedMessage.Builder builder, int index);
+      Object getRepeatedRaw(GeneratedMessage message, int index);
+      Object getRepeatedRaw(GeneratedMessage.Builder builder, int index);
       void setRepeated(Builder builder,
       void setRepeated(Builder builder,
                        int index, Object value);
                        int index, Object value);
       void addRepeated(Builder builder, Object value);
       void addRepeated(Builder builder, Object value);
@@ -1949,6 +2033,12 @@ public abstract class GeneratedMessage extends AbstractMessage
       public Object get(GeneratedMessage.Builder builder) {
       public Object get(GeneratedMessage.Builder builder) {
         return invokeOrDie(getMethodBuilder, builder);
         return invokeOrDie(getMethodBuilder, builder);
       }
       }
+      public Object getRaw(final GeneratedMessage message) {
+        return get(message);
+      }
+      public Object getRaw(GeneratedMessage.Builder builder) {
+        return get(builder);
+      }
       public void set(final Builder builder, final Object value) {
       public void set(final Builder builder, final Object value) {
         invokeOrDie(setMethod, builder, value);
         invokeOrDie(setMethod, builder, value);
       }
       }
@@ -1957,12 +2047,22 @@ public abstract class GeneratedMessage extends AbstractMessage
         throw new UnsupportedOperationException(
         throw new UnsupportedOperationException(
           "getRepeatedField() called on a singular field.");
           "getRepeatedField() called on a singular field.");
       }
       }
+      public Object getRepeatedRaw(final GeneratedMessage message,
+                                final int index) {
+        throw new UnsupportedOperationException(
+          "getRepeatedFieldRaw() called on a singular field.");
+      }
       public Object getRepeated(GeneratedMessage.Builder builder, int index) {
       public Object getRepeated(GeneratedMessage.Builder builder, int index) {
         throw new UnsupportedOperationException(
         throw new UnsupportedOperationException(
           "getRepeatedField() called on a singular field.");
           "getRepeatedField() called on a singular field.");
       }
       }
-      public void setRepeated(final Builder builder,
-                              final int index, final Object value) {
+      public Object getRepeatedRaw(GeneratedMessage.Builder builder,
+          int index) {
+        throw new UnsupportedOperationException(
+          "getRepeatedFieldRaw() called on a singular field.");
+      }
+      public void setRepeated(final Builder builder, final int index,
+          final Object value) {
         throw new UnsupportedOperationException(
         throw new UnsupportedOperationException(
           "setRepeatedField() called on a singular field.");
           "setRepeatedField() called on a singular field.");
       }
       }
@@ -2058,6 +2158,12 @@ public abstract class GeneratedMessage extends AbstractMessage
       public Object get(GeneratedMessage.Builder builder) {
       public Object get(GeneratedMessage.Builder builder) {
         return invokeOrDie(getMethodBuilder, builder);
         return invokeOrDie(getMethodBuilder, builder);
       }
       }
+      public Object getRaw(final GeneratedMessage message) {
+        return get(message);
+      }
+      public Object getRaw(GeneratedMessage.Builder builder) {
+        return get(builder);
+      }
       public void set(final Builder builder, final Object value) {
       public void set(final Builder builder, final Object value) {
         // Add all the elements individually.  This serves two purposes:
         // Add all the elements individually.  This serves two purposes:
         // 1) Verifies that each element has the correct type.
         // 1) Verifies that each element has the correct type.
@@ -2075,6 +2181,13 @@ public abstract class GeneratedMessage extends AbstractMessage
       public Object getRepeated(GeneratedMessage.Builder builder, int index) {
       public Object getRepeated(GeneratedMessage.Builder builder, int index) {
         return invokeOrDie(getRepeatedMethodBuilder, builder, index);
         return invokeOrDie(getRepeatedMethodBuilder, builder, index);
       }
       }
+      public Object getRepeatedRaw(GeneratedMessage message, int index) {
+        return getRepeated(message, index);
+      }
+      public Object getRepeatedRaw(GeneratedMessage.Builder builder,
+          int index) {
+        return getRepeated(builder, index);
+      }
       public void setRepeated(final Builder builder,
       public void setRepeated(final Builder builder,
                               final int index, final Object value) {
                               final int index, final Object value) {
         invokeOrDie(setRepeatedMethod, builder, index, value);
         invokeOrDie(setRepeatedMethod, builder, index, value);
@@ -2139,6 +2252,12 @@ public abstract class GeneratedMessage extends AbstractMessage
         return (MapField<?, ?>) builder.internalGetMapField(field.getNumber());
         return (MapField<?, ?>) builder.internalGetMapField(field.getNumber());
       }
       }
 
 
+      private MapField<?, ?> getMutableMapField(
+          GeneratedMessage.Builder builder) {
+        return (MapField<?, ?>) builder.internalGetMutableMapField(
+            field.getNumber());
+      }
+
       public Object get(GeneratedMessage message) {
       public Object get(GeneratedMessage message) {
         List result = new ArrayList();
         List result = new ArrayList();
         for (int i = 0; i < getRepeatedCount(message); i++) {
         for (int i = 0; i < getRepeatedCount(message); i++) {
@@ -2155,6 +2274,14 @@ public abstract class GeneratedMessage extends AbstractMessage
         return Collections.unmodifiableList(result);
         return Collections.unmodifiableList(result);
       }
       }
 
 
+      public Object getRaw(GeneratedMessage message) {
+        return get(message);
+      }
+
+      public Object getRaw(GeneratedMessage.Builder builder) {
+        return get(builder);
+      }
+
       public void set(Builder builder, Object value) {
       public void set(Builder builder, Object value) {
         clear(builder);
         clear(builder);
         for (Object entry : (List) value) {
         for (Object entry : (List) value) {
@@ -2170,14 +2297,20 @@ public abstract class GeneratedMessage extends AbstractMessage
         return getMapField(builder).getList().get(index);
         return getMapField(builder).getList().get(index);
       }
       }
 
 
+      public Object getRepeatedRaw(GeneratedMessage message, int index) {
+        return getRepeated(message, index);
+      }
+
+      public Object getRepeatedRaw(Builder builder, int index) {
+        return getRepeated(builder, index);
+      }
+
       public void setRepeated(Builder builder, int index, Object value) {
       public void setRepeated(Builder builder, int index, Object value) {
-        builder.onChanged();
-        getMapField(builder).getMutableList().set(index, (Message) value);
+        getMutableMapField(builder).getMutableList().set(index, (Message) value);
       }
       }
 
 
       public void addRepeated(Builder builder, Object value) {
       public void addRepeated(Builder builder, Object value) {
-        builder.onChanged();
-        getMapField(builder).getMutableList().add((Message) value);
+        getMutableMapField(builder).getMutableList().add((Message) value);
       }
       }
 
 
       public boolean has(GeneratedMessage message) {
       public boolean has(GeneratedMessage message) {
@@ -2199,8 +2332,7 @@ public abstract class GeneratedMessage extends AbstractMessage
       }
       }
 
 
       public void clear(Builder builder) {
       public void clear(Builder builder) {
-        builder.onChanged();
-        getMapField(builder).getMutableList().clear();
+        getMutableMapField(builder).getMutableList().clear();
       }
       }
 
 
       public com.google.protobuf.Message.Builder newBuilder() {
       public com.google.protobuf.Message.Builder newBuilder() {
@@ -2391,6 +2523,60 @@ public abstract class GeneratedMessage extends AbstractMessage
 
 
     // ---------------------------------------------------------------
     // ---------------------------------------------------------------
 
 
+    /**
+     * Field accessor for string fields.
+     *
+     * <p>This class makes getFooBytes() and setFooBytes() available for
+     * reflection API so that reflection based serialize/parse functions can
+     * access the raw bytes of the field to preserve non-UTF8 bytes in the
+     * string.
+     *
+     * <p>This ensures the serialize/parse round-trip safety, which is important
+     * for servers which forward messages.
+     */
+    private static final class SingularStringFieldAccessor
+        extends SingularFieldAccessor {
+      SingularStringFieldAccessor(
+          final FieldDescriptor descriptor, final String camelCaseName,
+          final Class<? extends GeneratedMessage> messageClass,
+          final Class<? extends Builder> builderClass,
+          final String containingOneofCamelCaseName) {
+        super(descriptor, camelCaseName, messageClass, builderClass,
+            containingOneofCamelCaseName);
+        getBytesMethod = getMethodOrDie(messageClass,
+            "get" + camelCaseName + "Bytes");
+        getBytesMethodBuilder = getMethodOrDie(builderClass,
+            "get" + camelCaseName + "Bytes");
+        setBytesMethodBuilder = getMethodOrDie(builderClass,
+            "set" + camelCaseName + "Bytes", ByteString.class);
+      }
+
+      private final Method getBytesMethod;
+      private final Method getBytesMethodBuilder;
+      private final Method setBytesMethodBuilder;
+
+      @Override
+      public Object getRaw(final GeneratedMessage message) {
+        return invokeOrDie(getBytesMethod, message);
+      }
+
+      @Override
+      public Object getRaw(GeneratedMessage.Builder builder) {
+        return invokeOrDie(getBytesMethodBuilder, builder);
+      }
+
+      @Override
+      public void set(GeneratedMessage.Builder builder, Object value) {
+        if (value instanceof ByteString) {
+          invokeOrDie(setBytesMethodBuilder, builder, value);
+        } else {
+          super.set(builder, value);
+        }
+      }
+    }
+
+    // ---------------------------------------------------------------
+
     private static final class SingularMessageFieldAccessor
     private static final class SingularMessageFieldAccessor
         extends SingularFieldAccessor {
         extends SingularFieldAccessor {
       SingularMessageFieldAccessor(
       SingularMessageFieldAccessor(

+ 129 - 16
java/src/main/java/com/google/protobuf/GeneratedMessageLite.java

@@ -42,22 +42,58 @@ import java.util.Collections;
 import java.util.Iterator;
 import java.util.Iterator;
 import java.util.List;
 import java.util.List;
 import java.util.Map;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 
 /**
 /**
  * Lite version of {@link GeneratedMessage}.
  * Lite version of {@link GeneratedMessage}.
  *
  *
  * @author kenton@google.com Kenton Varda
  * @author kenton@google.com Kenton Varda
  */
  */
-public abstract class GeneratedMessageLite extends AbstractMessageLite
-    implements Serializable {
+public abstract class GeneratedMessageLite<
+    MessageType extends GeneratedMessageLite<MessageType, BuilderType>,
+    BuilderType extends GeneratedMessageLite.Builder<MessageType, BuilderType>> 
+        extends AbstractMessageLite
+        implements Serializable {
+  
+  /**
+   * Holds all the {@link PrototypeHolder}s for loaded classes.
+   */
+  // TODO(dweis): Consider different concurrency values.
+  // TODO(dweis): This will prevent garbage collection of the class loader.
+  //     Ideally we'd use something like ClassValue but that's Java 7 only.
+  private static final Map<Class<?>, PrototypeHolder<?, ?>> PROTOTYPE_MAP =
+      new ConcurrentHashMap<Class<?>, PrototypeHolder<?, ?>>();
+  
+  // For use by generated code only.
+  protected static <
+      MessageType extends GeneratedMessageLite<MessageType, BuilderType>,
+      BuilderType extends GeneratedMessageLite.Builder<
+          MessageType, BuilderType>> void onLoad(Class<MessageType> clazz,
+              PrototypeHolder<MessageType, BuilderType> protoTypeHolder) {
+    PROTOTYPE_MAP.put(clazz, protoTypeHolder);
+  }
+
   private static final long serialVersionUID = 1L;
   private static final long serialVersionUID = 1L;
 
 
   /** For use by generated code only.  */
   /** For use by generated code only.  */
   protected UnknownFieldSetLite unknownFields;
   protected UnknownFieldSetLite unknownFields;
   
   
-  public Parser<? extends MessageLite> getParserForType() {
-    throw new UnsupportedOperationException(
-        "This is supposed to be overridden by subclasses.");
+  @SuppressWarnings("unchecked") // Guaranteed by runtime.
+  public final Parser<MessageType> getParserForType() {
+    return (Parser<MessageType>) PROTOTYPE_MAP
+        .get(getClass()).getParserForType();
+  }
+
+  @SuppressWarnings("unchecked") // Guaranteed by runtime.
+  public final MessageType getDefaultInstanceForType() {
+    return (MessageType) PROTOTYPE_MAP
+        .get(getClass()).getDefaultInstanceForType();
+  }
+
+  @SuppressWarnings("unchecked") // Guaranteed by runtime.
+  public final BuilderType newBuilderForType() {
+    return (BuilderType) PROTOTYPE_MAP
+        .get(getClass()).newBuilderForType();
   }
   }
 
 
   /**
   /**
@@ -73,10 +109,17 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
     return unknownFields.mergeFieldFrom(tag, input);
     return unknownFields.mergeFieldFrom(tag, input);
   }
   }
 
 
+  // The default behavior. If a message has required fields in its subtree, the
+  // generated code will override.
+  public boolean isInitialized() {
+    return true;
+  }
+
   @SuppressWarnings("unchecked")
   @SuppressWarnings("unchecked")
-  public abstract static class Builder<MessageType extends GeneratedMessageLite,
-                                       BuilderType extends Builder>
-      extends AbstractMessageLite.Builder<BuilderType> {
+  public abstract static class Builder<
+      MessageType extends GeneratedMessageLite<MessageType, BuilderType>,
+      BuilderType extends Builder<MessageType, BuilderType>>
+          extends AbstractMessageLite.Builder<BuilderType> {
 
 
     private final MessageType defaultInstance;
     private final MessageType defaultInstance;
 
 
@@ -88,6 +131,12 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
       this.defaultInstance = defaultInstance;
       this.defaultInstance = defaultInstance;
     }
     }
 
 
+    // The default behavior. If a message has required fields in its subtree,
+    // the generated code will override.
+    public boolean isInitialized() {
+      return true;
+    }
+
     //@Override (Java 1.6 override semantics, but we must support 1.5)
     //@Override (Java 1.6 override semantics, but we must support 1.5)
     public BuilderType clear() {
     public BuilderType clear() {
       unknownFields = UnknownFieldSetLite.getDefaultInstance();
       unknownFields = UnknownFieldSetLite.getDefaultInstance();
@@ -174,7 +223,9 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
    * Lite equivalent of {@link com.google.protobuf.GeneratedMessage.ExtendableMessageOrBuilder}.
    * Lite equivalent of {@link com.google.protobuf.GeneratedMessage.ExtendableMessageOrBuilder}.
    */
    */
   public interface ExtendableMessageOrBuilder<
   public interface ExtendableMessageOrBuilder<
-      MessageType extends ExtendableMessage> extends MessageLiteOrBuilder {
+      MessageType extends ExtendableMessage<MessageType, BuilderType>,
+      BuilderType extends ExtendableBuilder<MessageType, BuilderType>>
+          extends MessageLiteOrBuilder {
 
 
     /** Check if a singular extension is present. */
     /** Check if a singular extension is present. */
     <Type> boolean hasExtension(
     <Type> boolean hasExtension(
@@ -197,16 +248,30 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
    * Lite equivalent of {@link GeneratedMessage.ExtendableMessage}.
    * Lite equivalent of {@link GeneratedMessage.ExtendableMessage}.
    */
    */
   public abstract static class ExtendableMessage<
   public abstract static class ExtendableMessage<
-        MessageType extends ExtendableMessage<MessageType>>
-      extends GeneratedMessageLite
-      implements ExtendableMessageOrBuilder<MessageType> {
+        MessageType extends ExtendableMessage<MessageType, BuilderType>,
+        BuilderType extends ExtendableBuilder<MessageType, BuilderType>>
+            extends GeneratedMessageLite<MessageType, BuilderType>
+            implements ExtendableMessageOrBuilder<MessageType, BuilderType> {
 
 
     /**
     /**
      * Represents the set of extensions on this message. For use by generated
      * Represents the set of extensions on this message. For use by generated
      * code only.
      * code only.
      */
      */
     protected FieldSet<ExtensionDescriptor> extensions = FieldSet.newFieldSet();
     protected FieldSet<ExtensionDescriptor> extensions = FieldSet.newFieldSet();
-    
+
+    // -1 => not memoized, 0 => false, 1 => true.
+    private byte memoizedIsInitialized = -1;
+
+    // The default behavior. If a message has required fields in its subtree,
+    // the generated code will override.
+    public boolean isInitialized() {
+      if (memoizedIsInitialized == -1) {
+        memoizedIsInitialized = (byte) (extensions.isInitialized() ? 1 : 0);
+      }
+
+      return memoizedIsInitialized == 1;
+    }
+
     private void verifyExtensionContainingType(
     private void verifyExtensionContainingType(
         final GeneratedExtension<MessageType, ?> extension) {
         final GeneratedExtension<MessageType, ?> extension) {
       if (extension.getContainingTypeDefaultInstance() !=
       if (extension.getContainingTypeDefaultInstance() !=
@@ -349,10 +414,10 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
    */
    */
   @SuppressWarnings("unchecked")
   @SuppressWarnings("unchecked")
   public abstract static class ExtendableBuilder<
   public abstract static class ExtendableBuilder<
-        MessageType extends ExtendableMessage<MessageType>,
+        MessageType extends ExtendableMessage<MessageType, BuilderType>,
         BuilderType extends ExtendableBuilder<MessageType, BuilderType>>
         BuilderType extends ExtendableBuilder<MessageType, BuilderType>>
       extends Builder<MessageType, BuilderType>
       extends Builder<MessageType, BuilderType>
-      implements ExtendableMessageOrBuilder<MessageType> {
+      implements ExtendableMessageOrBuilder<MessageType, BuilderType> {
     protected ExtendableBuilder(MessageType defaultInstance) {
     protected ExtendableBuilder(MessageType defaultInstance) {
       super(defaultInstance);
       super(defaultInstance);
     }
     }
@@ -360,6 +425,12 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
     private FieldSet<ExtensionDescriptor> extensions = FieldSet.emptySet();
     private FieldSet<ExtensionDescriptor> extensions = FieldSet.emptySet();
     private boolean extensionsIsMutable;
     private boolean extensionsIsMutable;
 
 
+    // The default behavior. If a message has required fields in its subtree,
+    // the generated code will override.
+    public boolean isInitialized() {
+      return extensions.isInitialized();
+    }
+
     // For immutable message conversion.
     // For immutable message conversion.
     void internalSetExtensionSet(FieldSet<ExtensionDescriptor> extensions) {
     void internalSetExtensionSet(FieldSet<ExtensionDescriptor> extensions) {
       this.extensions = extensions;
       this.extensions = extensions;
@@ -991,7 +1062,10 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
    * Checks that the {@link Extension} is Lite and returns it as a
    * Checks that the {@link Extension} is Lite and returns it as a
    * {@link GeneratedExtension}.
    * {@link GeneratedExtension}.
    */
    */
-  private static <MessageType extends ExtendableMessage<MessageType>, T>
+  private static <
+      MessageType extends ExtendableMessage<MessageType, BuilderType>,
+      BuilderType extends ExtendableBuilder<MessageType, BuilderType>,
+      T>
     GeneratedExtension<MessageType, T> checkIsLite(
     GeneratedExtension<MessageType, T> checkIsLite(
         ExtensionLite<MessageType, T> extension) {
         ExtensionLite<MessageType, T> extension) {
     if (!extension.isLite()) {
     if (!extension.isLite()) {
@@ -1000,4 +1074,43 @@ public abstract class GeneratedMessageLite extends AbstractMessageLite
     
     
     return (GeneratedExtension<MessageType, T>) extension;
     return (GeneratedExtension<MessageType, T>) extension;
   }
   }
+  
+  /**
+   * Represents the state needed to implement *ForType methods. Generated code
+   * must provide a static singleton instance by adding it with
+   * {@link GeneratedMessageLite#onLoad(Class, PrototypeHolder)} on class load.
+   * <ul>
+   * <li>{@link #getDefaultInstanceForType()}
+   * <li>{@link #getParserForType()}
+   * <li>{@link #newBuilderForType()}
+   * </ul>
+   * This allows us to trade three generated methods for a static Map.
+   */
+  protected static class PrototypeHolder<
+      MessageType extends GeneratedMessageLite<MessageType, BuilderType>,
+      BuilderType extends GeneratedMessageLite.Builder<
+          MessageType, BuilderType>> {
+    
+    private final MessageType defaultInstance;
+    private final Parser<MessageType> parser;
+    
+    public PrototypeHolder(
+        MessageType defaultInstance, Parser<MessageType> parser) {
+      this.defaultInstance = defaultInstance;
+      this.parser = parser;
+    }
+    
+    public MessageType getDefaultInstanceForType() {
+      return defaultInstance;
+    }
+
+    public Parser<MessageType> getParserForType() {
+      return parser;
+    }
+
+    @SuppressWarnings("unchecked") // Guaranteed by runtime.
+    public BuilderType newBuilderForType() {
+      return (BuilderType) defaultInstance.toBuilder();
+    }
+  }
 }
 }

+ 206 - 43
java/src/main/java/com/google/protobuf/LazyFieldLite.java

@@ -30,8 +30,6 @@
 
 
 package com.google.protobuf;
 package com.google.protobuf;
 
 
-import java.io.IOException;
-
 /**
 /**
  * LazyFieldLite encapsulates the logic of lazily parsing message fields. It stores
  * LazyFieldLite encapsulates the logic of lazily parsing message fields. It stores
  * the message in a ByteString initially and then parse it on-demand.
  * the message in a ByteString initially and then parse it on-demand.
@@ -44,40 +42,102 @@ import java.io.IOException;
  * @author xiangl@google.com (Xiang Li)
  * @author xiangl@google.com (Xiang Li)
  */
  */
 public class LazyFieldLite {
 public class LazyFieldLite {
-  private ByteString bytes;
+  private static final ExtensionRegistryLite EMPTY_REGISTRY =
+      ExtensionRegistryLite.getEmptyRegistry();
+
+  /**
+   * A delayed-parsed version of the bytes. When this is non-null then {@code extensionRegistry } is
+   * also non-null and {@code value} and {@code memoizedBytes} are null.
+   */
+  private ByteString delayedBytes;
+
+  /**
+   * An {@code ExtensionRegistryLite} for parsing bytes. It is non-null on a best-effort basis. It
+   * is only guaranteed to be non-null if this message was initialized using bytes and an
+   * {@code ExtensionRegistry}. If it directly had a value set then it will be null, unless it has
+   * been merged with another {@code LazyFieldLite} that had an {@code ExtensionRegistry}.
+   */
   private ExtensionRegistryLite extensionRegistry;
   private ExtensionRegistryLite extensionRegistry;
-  private volatile boolean isDirty = false;
 
 
+  /**
+   * The parsed value. When this is non-null then {@code delayedBytes} will be null.
+   */
   protected volatile MessageLite value;
   protected volatile MessageLite value;
 
 
+  /**
+   * The memoized bytes for {@code value}. Will be null when {@code value} is null.
+   */
+  private volatile ByteString memoizedBytes;
+
+  /**
+   * Constructs a LazyFieldLite with bytes that will be parsed lazily.
+   */
   public LazyFieldLite(ExtensionRegistryLite extensionRegistry, ByteString bytes) {
   public LazyFieldLite(ExtensionRegistryLite extensionRegistry, ByteString bytes) {
+    checkArguments(extensionRegistry, bytes);
     this.extensionRegistry = extensionRegistry;
     this.extensionRegistry = extensionRegistry;
-    this.bytes = bytes;
+    this.delayedBytes = bytes;
   }
   }
 
 
+  /**
+   * Constructs a LazyFieldLite with no contents, and no ability to parse extensions.
+   */
   public LazyFieldLite() {
   public LazyFieldLite() {
   }
   }
 
 
+  /**
+   * Constructs a LazyFieldLite instance with a value. The LazyFieldLite may not be able to parse
+   * the extensions in the value as it has no ExtensionRegistry.
+   */
   public static LazyFieldLite fromValue(MessageLite value) {
   public static LazyFieldLite fromValue(MessageLite value) {
     LazyFieldLite lf = new LazyFieldLite();
     LazyFieldLite lf = new LazyFieldLite();
     lf.setValue(value);
     lf.setValue(value);
     return lf;
     return lf;
   }
   }
 
 
+  /**
+   * Determines whether this LazyFieldLite instance represents the default instance of this type.
+   */
   public boolean containsDefaultInstance() {
   public boolean containsDefaultInstance() {
-    return value == null && bytes == null;
+    return memoizedBytes == ByteString.EMPTY
+        || value == null && (delayedBytes == null || delayedBytes == ByteString.EMPTY);
   }
   }
 
 
+  /**
+   * Clears the value state of this instance.
+   *
+   * <p>LazyField is not thread-safe for write access. Synchronizations are needed
+   * under read/write situations.
+   */
   public void clear() {
   public void clear() {
-    bytes = null;
+    // Don't clear the ExtensionRegistry. It might prove useful later on when merging in another
+    // value, but there is no guarantee that it will contain all extensions that were directly set
+    // on the values that need to be merged.
+    delayedBytes = null;
     value = null;
     value = null;
-    extensionRegistry = null;
-    isDirty = true;
+    memoizedBytes = null;
+  }
+
+  /**
+   * Overrides the contents of this LazyField.
+   *
+   * <p>LazyField is not thread-safe for write access. Synchronizations are needed
+   * under read/write situations.
+   */
+  public void set(LazyFieldLite other) {
+    this.delayedBytes = other.delayedBytes;
+    this.value = other.value;
+    this.memoizedBytes = other.memoizedBytes;
+    // If the other LazyFieldLite was created by directly setting the value rather than first by
+    // parsing, then it will not have an extensionRegistry. In this case we hold on to the existing
+    // extensionRegistry, which has no guarantees that it has all the extensions that will be
+    // directly set on the value.
+    if (other.extensionRegistry != null) {
+      this.extensionRegistry = other.extensionRegistry;
+    }
   }
   }
 
 
   /**
   /**
-   * Returns message instance. At first time, serialized data is parsed by
-   * {@code defaultInstance.getParserForType()}.
+   * Returns message instance. It may do some thread-safe delayed parsing of bytes.
    *
    *
    * @param defaultInstance its message's default instance. It's also used to get parser for the
    * @param defaultInstance its message's default instance. It's also used to get parser for the
    * message type.
    * message type.
@@ -88,38 +148,109 @@ public class LazyFieldLite {
   }
   }
 
 
   /**
   /**
-   * LazyField is not thread-safe for write access. Synchronizations are needed
+   * Sets the value of the instance and returns the old value without delay parsing anything.
+   *
+   * <p>LazyField is not thread-safe for write access. Synchronizations are needed
    * under read/write situations.
    * under read/write situations.
    */
    */
   public MessageLite setValue(MessageLite value) {
   public MessageLite setValue(MessageLite value) {
     MessageLite originalValue = this.value;
     MessageLite originalValue = this.value;
+    this.delayedBytes = null;
+    this.memoizedBytes = null;
     this.value = value;
     this.value = value;
-    bytes = null;
-    isDirty = true;
     return originalValue;
     return originalValue;
   }
   }
 
 
-  public void merge(LazyFieldLite value) {
-    if (value.containsDefaultInstance()) {
+  /**
+   * Merges another instance's contents. In some cases may drop some extensions if both fields
+   * contain data. If the other field has an {@code ExtensionRegistry} but this does not, then this
+   * field will copy over that {@code ExtensionRegistry}.
+   *
+   * <p>LazyField is not thread-safe for write access. Synchronizations are needed
+   * under read/write situations.
+   */
+  public void merge(LazyFieldLite other) {
+    if (other.containsDefaultInstance()) {
       return;
       return;
     }
     }
 
 
-    if (bytes == null) {
-      this.bytes = value.bytes;
+    if (this.containsDefaultInstance()) {
+      set(other);
+      return;
+    }
+
+    // If the other field has an extension registry but this does not, copy over the other extension
+    // registry.
+    if (this.extensionRegistry == null) {
+      this.extensionRegistry = other.extensionRegistry;
+    }
+
+    // In the case that both of them are not parsed we simply concatenate the bytes to save time. In
+    // the (probably rare) case that they have different extension registries there is a chance that
+    // some of the extensions may be dropped, but the tradeoff of making this operation fast seems
+    // to outway the benefits of combining the extension registries, which is not normally done for
+    // lite protos anyways.
+    if (this.delayedBytes != null && other.delayedBytes != null) {
+      this.delayedBytes = this.delayedBytes.concat(other.delayedBytes);
+      return;
+    }
+
+    // At least one is parsed and both contain data. We won't drop any extensions here directly, but
+    // in the case that the extension registries are not the same then we might in the future if we
+    // need to serialze and parse a message again.
+    if (this.value == null && other.value != null) {
+      setValue(mergeValueAndBytes(other.value, this.delayedBytes, this.extensionRegistry));
+      return;
+    } else if (this.value != null && other.value == null) {
+      setValue(mergeValueAndBytes(this.value, other.delayedBytes, other.extensionRegistry));
+      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 {
     } else {
-      this.bytes.concat(value.toByteString());
+      // All extensions from the other message will be dropped because we have no registry.
+      setValue(mergeValueAndBytes(this.value, other.toByteString(), EMPTY_REGISTRY));
+      return;
     }
     }
-    isDirty = false;
   }
   }
 
 
-  public void setByteString(ByteString bytes, ExtensionRegistryLite extensionRegistry) {
-    this.bytes = bytes;
-    this.extensionRegistry = extensionRegistry;
-    isDirty = false;
+  private static MessageLite mergeValueAndBytes(
+      MessageLite value, ByteString otherBytes, ExtensionRegistryLite extensionRegistry) {
+    try {
+      return value.toBuilder().mergeFrom(otherBytes, extensionRegistry).build();
+    } catch (InvalidProtocolBufferException e) {
+      // Nothing is logged and no exceptions are thrown. Clients will be unaware that a proto
+      // was invalid.
+      return value;
+    }
   }
   }
 
 
-  public ExtensionRegistryLite getExtensionRegistry() {
-    return extensionRegistry;
+  /**
+   * Sets this field with bytes to delay-parse.
+   */
+  public void setByteString(ByteString bytes, ExtensionRegistryLite extensionRegistry) {
+    checkArguments(extensionRegistry, bytes);
+    this.delayedBytes = bytes;
+    this.extensionRegistry = extensionRegistry;
+    this.value = null;
+    this.memoizedBytes = null;
   }
   }
 
 
   /**
   /**
@@ -128,30 +259,43 @@ public class LazyFieldLite {
    * parsed. Be careful when using this method.
    * parsed. Be careful when using this method.
    */
    */
   public int getSerializedSize() {
   public int getSerializedSize() {
-    if (isDirty) {
+    if (delayedBytes != null) {
+      return delayedBytes.size();
+    } else if (memoizedBytes != null) {
+      return memoizedBytes.size();
+    } else if (value != null) {
       return value.getSerializedSize();
       return value.getSerializedSize();
+    } else {
+      return 0;
     }
     }
-    return bytes.size();
   }
   }
 
 
+  /**
+   * Returns a BytesString for this field in a thread-safe way.
+   */
   public ByteString toByteString() {
   public ByteString toByteString() {
-    if (!isDirty) {
-      return bytes;
+    if (delayedBytes != null) {
+      return delayedBytes;
+    }
+    if (memoizedBytes != null) {
+      return memoizedBytes;
     }
     }
     synchronized (this) {
     synchronized (this) {
-      if (!isDirty) {
-        return bytes;
+      if (memoizedBytes != null) {
+        return memoizedBytes;
       }
       }
       if (value == null) {
       if (value == null) {
-        bytes = ByteString.EMPTY;
+        memoizedBytes = ByteString.EMPTY;
       } else {
       } else {
-        bytes = value.toByteString();
+        memoizedBytes = value.toByteString();
       }
       }
-      isDirty = false;
-      return bytes;
+      return memoizedBytes;
     }
     }
   }
   }
 
 
+  /**
+   * Might lazily parse the bytes that were previously passed in. Is thread-safe.
+   */
   protected void ensureInitialized(MessageLite defaultInstance) {
   protected void ensureInitialized(MessageLite defaultInstance) {
     if (value != null) {
     if (value != null) {
       return;
       return;
@@ -161,16 +305,35 @@ public class LazyFieldLite {
         return;
         return;
       }
       }
       try {
       try {
-        if (bytes != null) {
-          value = defaultInstance.getParserForType()
-              .parseFrom(bytes, extensionRegistry);
+        if (delayedBytes != null) {
+          // The extensionRegistry shouldn't be null here since we have delayedBytes.
+          MessageLite parsedValue = defaultInstance.getParserForType()
+              .parseFrom(delayedBytes, extensionRegistry);
+          this.value = parsedValue;
+          this.memoizedBytes = delayedBytes;
+          this.delayedBytes = null;
         } else {
         } else {
-          value = defaultInstance;
+          this.value = defaultInstance;
+          this.memoizedBytes = ByteString.EMPTY;
+          this.delayedBytes = null;
         }
         }
-      } catch (IOException e) {
-        // TODO(xiangl): Refactory the API to support the exception thrown from
-        // lazily load messages.
+      } catch (InvalidProtocolBufferException e) {
+        // Nothing is logged and no exceptions are thrown. Clients will be unaware that this proto
+        // was invalid.
+        this.value = defaultInstance;
+        this.memoizedBytes = ByteString.EMPTY;
+        this.delayedBytes = null;
       }
       }
     }
     }
   }
   }
+
+
+  private static void checkArguments(ExtensionRegistryLite extensionRegistry, ByteString bytes) {
+    if (extensionRegistry == null) {
+      throw new NullPointerException("found null ExtensionRegistry");
+    }
+    if (bytes == null) {
+      throw new NullPointerException("found null ByteString");
+    }
+  }
 }
 }

+ 5 - 1
java/src/main/java/com/google/protobuf/LiteralByteString.java

@@ -154,7 +154,11 @@ class LiteralByteString extends ByteString {
   @Override
   @Override
   public String toString(String charsetName)
   public String toString(String charsetName)
       throws UnsupportedEncodingException {
       throws UnsupportedEncodingException {
-    return new String(bytes, getOffsetIntoBytes(), size(), charsetName);
+    // Optimize for empty strings, but ensure we don't silently ignore invalid
+    // encodings.
+    return size() == 0 && UTF_8.equals(charsetName)
+        ? ""
+        : new String(bytes, getOffsetIntoBytes(), size(), charsetName);
   }
   }
 
 
   // =================================================================
   // =================================================================

+ 2 - 2
java/src/main/java/com/google/protobuf/Message.java

@@ -163,7 +163,7 @@ public interface Message extends MessageLite, MessageOrBuilder {
      * field builder, which will then be nested into its parent builder.
      * field builder, which will then be nested into its parent builder.
      * <p>
      * <p>
      * NOTE: implementations that do not support nested builders will throw
      * NOTE: implementations that do not support nested builders will throw
-     * <code>UnsupportedException</code>.
+     * <code>UnsupportedOperationException</code>.
      */
      */
     Builder getFieldBuilder(Descriptors.FieldDescriptor field);
     Builder getFieldBuilder(Descriptors.FieldDescriptor field);
 
 
@@ -181,7 +181,7 @@ public interface Message extends MessageLite, MessageOrBuilder {
      * field builder, which will then be nested into its parent builder.
      * field builder, which will then be nested into its parent builder.
      * <p>
      * <p>
      * NOTE: implementations that do not support nested builders will throw
      * NOTE: implementations that do not support nested builders will throw
-     * <code>UnsupportedException</code>.
+     * <code>UnsupportedOperationException</code>.
      */
      */
     Builder getRepeatedFieldBuilder(Descriptors.FieldDescriptor field,
     Builder getRepeatedFieldBuilder(Descriptors.FieldDescriptor field,
                                     int index);
                                     int index);

+ 36 - 24
java/src/main/java/com/google/protobuf/MessageReflection.java

@@ -45,13 +45,14 @@ import java.util.TreeMap;
  */
  */
 class MessageReflection {
 class MessageReflection {
 
 
-  static void writeMessageTo(Message message, CodedOutputStream output,
+  static void writeMessageTo(
+      Message message,
+      Map<FieldDescriptor, Object> fields,
+      CodedOutputStream output,
       boolean alwaysWriteRequiredFields)
       boolean alwaysWriteRequiredFields)
       throws IOException {
       throws IOException {
     final boolean isMessageSet =
     final boolean isMessageSet =
         message.getDescriptorForType().getOptions().getMessageSetWireFormat();
         message.getDescriptorForType().getOptions().getMessageSetWireFormat();
-
-    Map<FieldDescriptor, Object> fields = message.getAllFields();
     if (alwaysWriteRequiredFields) {
     if (alwaysWriteRequiredFields) {
       fields = new TreeMap<FieldDescriptor, Object>(fields);
       fields = new TreeMap<FieldDescriptor, Object>(fields);
       for (final FieldDescriptor field :
       for (final FieldDescriptor field :
@@ -82,13 +83,15 @@ class MessageReflection {
     }
     }
   }
   }
 
 
-  static int getSerializedSize(Message message) {
+  static int getSerializedSize(
+      Message message,
+      Map<FieldDescriptor, Object> fields) {
     int size = 0;
     int size = 0;
     final boolean isMessageSet =
     final boolean isMessageSet =
         message.getDescriptorForType().getOptions().getMessageSetWireFormat();
         message.getDescriptorForType().getOptions().getMessageSetWireFormat();
 
 
     for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry :
     for (final Map.Entry<Descriptors.FieldDescriptor, Object> entry :
-        message.getAllFields().entrySet()) {
+        fields.entrySet()) {
       final Descriptors.FieldDescriptor field = entry.getKey();
       final Descriptors.FieldDescriptor field = entry.getKey();
       final Object value = entry.getValue();
       final Object value = entry.getValue();
       if (isMessageSet && field.isExtension() &&
       if (isMessageSet && field.isExtension() &&
@@ -340,14 +343,12 @@ class MessageReflection {
         ByteString bytes, ExtensionRegistryLite registry,
         ByteString bytes, ExtensionRegistryLite registry,
         Descriptors.FieldDescriptor descriptor, Message defaultInstance)
         Descriptors.FieldDescriptor descriptor, Message defaultInstance)
         throws IOException;
         throws IOException;
-    
+
     /**
     /**
-     * Read a primitive field from input. Note that builders and mutable
-     * messages may use different Java types to represent a primtive field.
+     * Returns the UTF8 validation level for the field.
      */
      */
-    Object readPrimitiveField(
-        CodedInputStream input, WireFormat.FieldType type,
-        boolean checkUtf8) throws IOException;
+    WireFormat.Utf8Validation getUtf8Validation(Descriptors.FieldDescriptor
+        descriptor);
 
 
     /**
     /**
      * Returns a new merge target for a sub-field. When defaultInstance is
      * Returns a new merge target for a sub-field. When defaultInstance is
@@ -513,11 +514,18 @@ class MessageReflection {
         return new BuilderAdapter(builder.newBuilderForField(field));
         return new BuilderAdapter(builder.newBuilderForField(field));
       }
       }
     }
     }
-    
-    public Object readPrimitiveField(
-        CodedInputStream input, WireFormat.FieldType type,
-        boolean checkUtf8) throws IOException {
-      return FieldSet.readPrimitiveField(input, type, checkUtf8);
+
+    public WireFormat.Utf8Validation
+        getUtf8Validation(Descriptors.FieldDescriptor descriptor) {
+      if (descriptor.needsUtf8Check()) {
+        return WireFormat.Utf8Validation.STRICT;
+      }
+      // TODO(liujisi): support lazy strings for repeated fields.
+      if (!descriptor.isRepeated()
+          && builder instanceof GeneratedMessage.Builder) {
+        return WireFormat.Utf8Validation.LAZY;
+      }
+      return WireFormat.Utf8Validation.LOOSE;
     }
     }
 
 
     public Object finish() {
     public Object finish() {
@@ -651,11 +659,14 @@ class MessageReflection {
       throw new UnsupportedOperationException(
       throw new UnsupportedOperationException(
           "newMergeTargetForField() called on FieldSet object");
           "newMergeTargetForField() called on FieldSet object");
     }
     }
-    
-    public Object readPrimitiveField(
-        CodedInputStream input, WireFormat.FieldType type,
-        boolean checkUtf8) throws IOException {
-      return FieldSet.readPrimitiveField(input, type, checkUtf8);
+
+    public WireFormat.Utf8Validation
+        getUtf8Validation(Descriptors.FieldDescriptor descriptor) {
+      if (descriptor.needsUtf8Check()) {
+        return WireFormat.Utf8Validation.STRICT;
+      }
+      // TODO(liujisi): support lazy strings for ExtesnsionSet.
+      return WireFormat.Utf8Validation.LOOSE;
     }
     }
 
 
     public Object finish() {
     public Object finish() {
@@ -767,8 +778,8 @@ class MessageReflection {
         }
         }
       } else {
       } else {
         while (input.getBytesUntilLimit() > 0) {
         while (input.getBytesUntilLimit() > 0) {
-          final Object value =
-              target.readPrimitiveField(input, field.getLiteType(), field.needsUtf8Check());
+          final Object value = WireFormat.readPrimitiveField(
+              input, field.getLiteType(), target.getUtf8Validation(field));
           target.addRepeatedField(field, value);
           target.addRepeatedField(field, value);
         }
         }
       }
       }
@@ -801,7 +812,8 @@ class MessageReflection {
           }
           }
           break;
           break;
         default:
         default:
-          value = target.readPrimitiveField(input, field.getLiteType(), field.needsUtf8Check());
+          value = WireFormat.readPrimitiveField(
+              input, field.getLiteType(), target.getUtf8Validation(field));
           break;
           break;
       }
       }
 
 

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

@@ -30,9 +30,9 @@
 
 
 package com.google.protobuf;
 package com.google.protobuf;
 
 
-import java.io.InvalidObjectException;
 import java.io.IOException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStream;
+import java.io.InvalidObjectException;
 import java.io.ObjectInputStream;
 import java.io.ObjectInputStream;
 import java.io.OutputStream;
 import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
 import java.io.UnsupportedEncodingException;
@@ -420,7 +420,11 @@ class RopeByteString extends ByteString {
   @Override
   @Override
   public String toString(String charsetName)
   public String toString(String charsetName)
       throws UnsupportedEncodingException {
       throws UnsupportedEncodingException {
-    return new String(toByteArray(), charsetName);
+    // Optimize for empty strings, but ensure we don't silently ignore invalid
+    // encodings.
+    return size() == 0 && UTF_8.equals(charsetName)
+        ? ""
+        : new String(toByteArray(), charsetName);
   }
   }
 
 
   // =================================================================
   // =================================================================

+ 63 - 56
java/src/main/java/com/google/protobuf/TextFormat.java

@@ -409,9 +409,9 @@ public final class TextFormat {
 
 
         case STRING:
         case STRING:
           generator.print("\"");
           generator.print("\"");
-          generator.print(escapeNonAscii ?
-              escapeText((String) value) :
-              escapeDoubleQuotesAndBackslashes((String) value)
+          generator.print(escapeNonAscii
+              ? escapeText((String) value)
+              : escapeDoubleQuotesAndBackslashes((String) value)
                   .replace("\n", "\\n"));
                   .replace("\n", "\\n"));
           generator.print("\"");
           generator.print("\"");
           break;
           break;
@@ -730,8 +730,8 @@ public final class TextFormat {
       }
       }
 
 
       final char c = currentToken.charAt(0);
       final char c = currentToken.charAt(0);
-      return ('0' <= c && c <= '9') ||
-             c == '-' || c == '+';
+      return ('0' <= c && c <= '9')
+          || c == '-' || c == '+';
     }
     }
 
 
     /**
     /**
@@ -749,10 +749,10 @@ public final class TextFormat {
     public String consumeIdentifier() throws ParseException {
     public String consumeIdentifier() throws ParseException {
       for (int i = 0; i < currentToken.length(); i++) {
       for (int i = 0; i < currentToken.length(); i++) {
         final char c = currentToken.charAt(i);
         final char c = currentToken.charAt(i);
-        if (('a' <= c && c <= 'z') ||
-            ('A' <= c && c <= 'Z') ||
-            ('0' <= c && c <= '9') ||
-            (c == '_') || (c == '.')) {
+        if (('a' <= c && c <= 'z')
+            || ('A' <= c && c <= 'Z')
+            || ('0' <= c && c <= '9')
+            || (c == '_') || (c == '.')) {
           // OK
           // OK
         } else {
         } else {
           throw parseException(
           throw parseException(
@@ -941,14 +941,14 @@ public final class TextFormat {
      * Otherwise, throw a {@link ParseException}.
      * Otherwise, throw a {@link ParseException}.
      */
      */
     public boolean consumeBoolean() throws ParseException {
     public boolean consumeBoolean() throws ParseException {
-      if (currentToken.equals("true") ||
-          currentToken.equals("t") ||
-          currentToken.equals("1")) {
+      if (currentToken.equals("true")
+          || currentToken.equals("t")
+          || currentToken.equals("1")) {
         nextToken();
         nextToken();
         return true;
         return true;
-      } else if (currentToken.equals("false") ||
-                 currentToken.equals("f") ||
-                 currentToken.equals("0")) {
+      } else if (currentToken.equals("false")
+          || currentToken.equals("f")
+          || currentToken.equals("0")) {
         nextToken();
         nextToken();
         return false;
         return false;
       } else {
       } else {
@@ -999,14 +999,15 @@ public final class TextFormat {
      */
      */
     private void consumeByteString(List<ByteString> list)
     private void consumeByteString(List<ByteString> list)
         throws ParseException {
         throws ParseException {
-      final char quote = currentToken.length() > 0 ? currentToken.charAt(0)
-                                                   : '\0';
+      final char quote = currentToken.length() > 0
+          ? currentToken.charAt(0)
+          : '\0';
       if (quote != '\"' && quote != '\'') {
       if (quote != '\"' && quote != '\'') {
         throw parseException("Expected string.");
         throw parseException("Expected string.");
       }
       }
 
 
-      if (currentToken.length() < 2 ||
-          currentToken.charAt(currentToken.length() - 1) != quote) {
+      if (currentToken.length() < 2
+          || currentToken.charAt(currentToken.length() - 1) != quote) {
         throw parseException("String missing ending quote.");
         throw parseException("String missing ending quote.");
       }
       }
 
 
@@ -1340,8 +1341,8 @@ public final class TextFormat {
         } else {
         } else {
           if (extension.descriptor.getContainingType() != type) {
           if (extension.descriptor.getContainingType() != type) {
             throw tokenizer.parseExceptionPreviousToken(
             throw tokenizer.parseExceptionPreviousToken(
-              "Extension \"" + name + "\" does not extend message type \"" +
-              type.getFullName() + "\".");
+              "Extension \"" + name + "\" does not extend message type \""
+              + type.getFullName() + "\".");
           }
           }
           field = extension.descriptor;
           field = extension.descriptor;
         }
         }
@@ -1365,20 +1366,20 @@ public final class TextFormat {
           }
           }
         }
         }
         // Again, special-case group names as described above.
         // Again, special-case group names as described above.
-        if (field != null && field.getType() == FieldDescriptor.Type.GROUP &&
-            !field.getMessageType().getName().equals(name)) {
+        if (field != null && field.getType() == FieldDescriptor.Type.GROUP
+            && !field.getMessageType().getName().equals(name)) {
           field = null;
           field = null;
         }
         }
 
 
         if (field == null) {
         if (field == null) {
           if (!allowUnknownFields) {
           if (!allowUnknownFields) {
             throw tokenizer.parseExceptionPreviousToken(
             throw tokenizer.parseExceptionPreviousToken(
-              "Message type \"" + type.getFullName() +
-              "\" has no field named \"" + name + "\".");
+              "Message type \"" + type.getFullName()
+              + "\" has no field named \"" + name + "\".");
           } else {
           } else {
             logger.warning(
             logger.warning(
-              "Message type \"" + type.getFullName() +
-              "\" has no field named \"" + name + "\".");
+              "Message type \"" + type.getFullName()
+              + "\" has no field named \"" + name + "\".");
           }
           }
         }
         }
       }
       }
@@ -1391,8 +1392,9 @@ public final class TextFormat {
         // start with "{" or "<" which indicates the beginning of a message body.
         // start with "{" or "<" which indicates the beginning of a message body.
         // If there is no ":" or there is a "{" or "<" after ":", this field has
         // If there is no ":" or there is a "{" or "<" after ":", this field has
         // to be a message or the input is ill-formed.
         // to be a message or the input is ill-formed.
-        if (tokenizer.tryConsume(":") && !tokenizer.lookingAt("{") &&
-            !tokenizer.lookingAt("<")) {
+        if (tokenizer.tryConsume(":")
+            && !tokenizer.lookingAt("{")
+            && !tokenizer.lookingAt("<")) {
           skipFieldValue(tokenizer);
           skipFieldValue(tokenizer);
         } else {
         } else {
           skipFieldMessage(tokenizer);
           skipFieldMessage(tokenizer);
@@ -1516,16 +1518,16 @@ public final class TextFormat {
               value = enumType.findValueByNumber(number);
               value = enumType.findValueByNumber(number);
               if (value == null) {
               if (value == null) {
                 throw tokenizer.parseExceptionPreviousToken(
                 throw tokenizer.parseExceptionPreviousToken(
-                  "Enum type \"" + enumType.getFullName() +
-                  "\" has no value with number " + number + '.');
+                  "Enum type \"" + enumType.getFullName()
+                  + "\" has no value with number " + number + '.');
               }
               }
             } else {
             } else {
               final String id = tokenizer.consumeIdentifier();
               final String id = tokenizer.consumeIdentifier();
               value = enumType.findValueByName(id);
               value = enumType.findValueByName(id);
               if (value == null) {
               if (value == null) {
                 throw tokenizer.parseExceptionPreviousToken(
                 throw tokenizer.parseExceptionPreviousToken(
-                  "Enum type \"" + enumType.getFullName() +
-                  "\" has no value named \"" + id + "\".");
+                  "Enum type \"" + enumType.getFullName()
+                  + "\" has no value named \"" + id + "\".");
               }
               }
             }
             }
 
 
@@ -1578,8 +1580,9 @@ public final class TextFormat {
       // start with "{" or "<" which indicates the beginning of a message body.
       // start with "{" or "<" which indicates the beginning of a message body.
       // If there is no ":" or there is a "{" or "<" after ":", this field has
       // If there is no ":" or there is a "{" or "<" after ":", this field has
       // to be a message or the input is ill-formed.
       // to be a message or the input is ill-formed.
-      if (tokenizer.tryConsume(":") && !tokenizer.lookingAt("<") &&
-          !tokenizer.lookingAt("{")) {
+      if (tokenizer.tryConsume(":")
+          && !tokenizer.lookingAt("<")
+          && !tokenizer.lookingAt("{")) {
         skipFieldValue(tokenizer);
         skipFieldValue(tokenizer);
       } else {
       } else {
         skipFieldMessage(tokenizer);
         skipFieldMessage(tokenizer);
@@ -1617,11 +1620,11 @@ public final class TextFormat {
         while (tokenizer.tryConsumeString()) {}
         while (tokenizer.tryConsumeString()) {}
         return;
         return;
       }
       }
-      if (!tokenizer.tryConsumeIdentifier() &&  // includes enum & boolean
-          !tokenizer.tryConsumeInt64() &&       // includes int32
-          !tokenizer.tryConsumeUInt64() &&      // includes uint32
-          !tokenizer.tryConsumeDouble() &&
-          !tokenizer.tryConsumeFloat()) {
+      if (!tokenizer.tryConsumeIdentifier()   // includes enum & boolean
+          && !tokenizer.tryConsumeInt64()     // includes int32
+          && !tokenizer.tryConsumeUInt64()    // includes uint32
+          && !tokenizer.tryConsumeDouble()
+          && !tokenizer.tryConsumeFloat()) {
         throw tokenizer.parseException(
         throw tokenizer.parseException(
             "Invalid field value: " + tokenizer.currentToken);
             "Invalid field value: " + tokenizer.currentToken);
       }
       }
@@ -1647,19 +1650,19 @@ public final class TextFormat {
    * which no defined short-hand escape sequence is defined will be escaped
    * which no defined short-hand escape sequence is defined will be escaped
    * using 3-digit octal sequences.
    * using 3-digit octal sequences.
    */
    */
-  private static String escapeBytes(final ByteSequence input) {
+  public static String escapeBytes(final ByteSequence input) {
     final StringBuilder builder = new StringBuilder(input.size());
     final StringBuilder builder = new StringBuilder(input.size());
     for (int i = 0; i < input.size(); i++) {
     for (int i = 0; i < input.size(); i++) {
       final byte b = input.byteAt(i);
       final byte b = input.byteAt(i);
       switch (b) {
       switch (b) {
         // Java does not recognize \a or \v, apparently.
         // Java does not recognize \a or \v, apparently.
-        case 0x07: builder.append("\\a" ); break;
-        case '\b': builder.append("\\b" ); break;
-        case '\f': builder.append("\\f" ); break;
-        case '\n': builder.append("\\n" ); break;
-        case '\r': builder.append("\\r" ); break;
-        case '\t': builder.append("\\t" ); break;
-        case 0x0b: builder.append("\\v" ); break;
+        case 0x07: builder.append("\\a"); break;
+        case '\b': builder.append("\\b"); break;
+        case '\f': builder.append("\\f"); break;
+        case '\n': builder.append("\\n"); break;
+        case '\r': builder.append("\\r"); break;
+        case '\t': builder.append("\\t"); break;
+        case 0x0b: builder.append("\\v"); break;
         case '\\': builder.append("\\\\"); break;
         case '\\': builder.append("\\\\"); break;
         case '\'': builder.append("\\\'"); break;
         case '\'': builder.append("\\\'"); break;
         case '"' : builder.append("\\\""); break;
         case '"' : builder.append("\\\""); break;
@@ -1688,11 +1691,13 @@ public final class TextFormat {
    * which no defined short-hand escape sequence is defined will be escaped
    * which no defined short-hand escape sequence is defined will be escaped
    * using 3-digit octal sequences.
    * using 3-digit octal sequences.
    */
    */
-  static String escapeBytes(final ByteString input) {
+  public static String escapeBytes(final ByteString input) {
     return escapeBytes(new ByteSequence() {
     return escapeBytes(new ByteSequence() {
+      @Override
       public int size() {
       public int size() {
         return input.size();
         return input.size();
       }
       }
+      @Override
       public byte byteAt(int offset) {
       public byte byteAt(int offset) {
         return input.byteAt(offset);
         return input.byteAt(offset);
       }
       }
@@ -1702,11 +1707,13 @@ public final class TextFormat {
   /**
   /**
    * Like {@link #escapeBytes(ByteString)}, but used for byte array.
    * Like {@link #escapeBytes(ByteString)}, but used for byte array.
    */
    */
-  static String escapeBytes(final byte[] input) {
+  public static String escapeBytes(final byte[] input) {
     return escapeBytes(new ByteSequence() {
     return escapeBytes(new ByteSequence() {
+      @Override
       public int size() {
       public int size() {
         return input.length;
         return input.length;
       }
       }
+      @Override
       public byte byteAt(int offset) {
       public byte byteAt(int offset) {
         return input[offset];
         return input[offset];
       }
       }
@@ -1749,7 +1756,7 @@ public final class TextFormat {
               code = code * 8 + digitValue(input.byteAt(i));
               code = code * 8 + digitValue(input.byteAt(i));
             }
             }
             // TODO: Check that 0 <= code && code <= 0xFF.
             // TODO: Check that 0 <= code && code <= 0xFF.
-            result[pos++] = (byte)code;
+            result[pos++] = (byte) code;
           } else {
           } else {
             switch (c) {
             switch (c) {
               case 'a' : result[pos++] = 0x07; break;
               case 'a' : result[pos++] = 0x07; break;
@@ -1777,12 +1784,12 @@ public final class TextFormat {
                   ++i;
                   ++i;
                   code = code * 16 + digitValue(input.byteAt(i));
                   code = code * 16 + digitValue(input.byteAt(i));
                 }
                 }
-                result[pos++] = (byte)code;
+                result[pos++] = (byte) code;
                 break;
                 break;
 
 
               default:
               default:
                 throw new InvalidEscapeSequenceException(
                 throw new InvalidEscapeSequenceException(
-                    "Invalid escape sequence: '\\" + (char)c + '\'');
+                    "Invalid escape sequence: '\\" + (char) c + '\'');
             }
             }
           }
           }
         } else {
         } else {
@@ -1841,9 +1848,9 @@ public final class TextFormat {
 
 
   /** Is this a hex digit? */
   /** Is this a hex digit? */
   private static boolean isHex(final byte c) {
   private static boolean isHex(final byte c) {
-    return ('0' <= c && c <= '9') ||
-           ('a' <= c && c <= 'f') ||
-           ('A' <= c && c <= 'F');
+    return ('0' <= c && c <= '9')
+        || ('a' <= c && c <= 'f')
+        || ('A' <= c && c <= 'F');
   }
   }
 
 
   /**
   /**

+ 82 - 0
java/src/main/java/com/google/protobuf/WireFormat.java

@@ -30,6 +30,8 @@
 
 
 package com.google.protobuf;
 package com.google.protobuf;
 
 
+import java.io.IOException;
+
 /**
 /**
  * This class is used internally by the Protocol Buffer library and generated
  * This class is used internally by the Protocol Buffer library and generated
  * message implementations.  It is public only because those generated messages
  * message implementations.  It is public only because those generated messages
@@ -160,4 +162,84 @@ public final class WireFormat {
     makeTag(MESSAGE_SET_TYPE_ID, WIRETYPE_VARINT);
     makeTag(MESSAGE_SET_TYPE_ID, WIRETYPE_VARINT);
   static final int MESSAGE_SET_MESSAGE_TAG =
   static final int MESSAGE_SET_MESSAGE_TAG =
     makeTag(MESSAGE_SET_MESSAGE, WIRETYPE_LENGTH_DELIMITED);
     makeTag(MESSAGE_SET_MESSAGE, WIRETYPE_LENGTH_DELIMITED);
+
+  /**
+   * Validation level for handling incoming string field data which potentially
+   * contain non-UTF8 bytes.
+   */
+  enum Utf8Validation {
+    /** Eagerly parses to String; silently accepts invalid UTF8 bytes. */
+    LOOSE {
+      Object readString(CodedInputStream input) throws IOException {
+        return input.readString();
+      }
+    },
+    /** Eagerly parses to String; throws an IOException on invalid bytes. */
+    STRICT {
+      Object readString(CodedInputStream input) throws IOException {
+        return input.readStringRequireUtf8();
+      }
+    },
+    /** Keep data as ByteString; validation/conversion to String is lazy. */
+    LAZY {
+      Object readString(CodedInputStream input) throws IOException {
+        return input.readBytes();
+      }
+    };
+
+    /** Read a string field from the input with the proper UTF8 validation. */
+    abstract Object readString(CodedInputStream input) throws IOException;
+  }
+
+  /**
+   * Read a field of any primitive type for immutable messages from a
+   * CodedInputStream. Enums, groups, and embedded messages are not handled by
+   * this method.
+   *
+   * @param input The stream from which to read.
+   * @param type Declared type of the field.
+   * @param utf8Validation Different string UTF8 validation level for handling
+   *                       string fields.
+   * @return An object representing the field's value, of the exact
+   *         type which would be returned by
+   *         {@link Message#getField(Descriptors.FieldDescriptor)} for
+   *         this field.
+   */
+  static Object readPrimitiveField(
+      CodedInputStream input,
+      FieldType type,
+      Utf8Validation utf8Validation) throws IOException {
+    switch (type) {
+      case DOUBLE  : return input.readDouble  ();
+      case FLOAT   : return input.readFloat   ();
+      case INT64   : return input.readInt64   ();
+      case UINT64  : return input.readUInt64  ();
+      case INT32   : return input.readInt32   ();
+      case FIXED64 : return input.readFixed64 ();
+      case FIXED32 : return input.readFixed32 ();
+      case BOOL    : return input.readBool    ();
+      case BYTES   : return input.readBytes   ();
+      case UINT32  : return input.readUInt32  ();
+      case SFIXED32: return input.readSFixed32();
+      case SFIXED64: return input.readSFixed64();
+      case SINT32  : return input.readSInt32  ();
+      case SINT64  : return input.readSInt64  ();
+
+      case STRING  : return utf8Validation.readString(input);
+      case GROUP:
+        throw new IllegalArgumentException(
+          "readPrimitiveField() cannot handle nested groups.");
+      case MESSAGE:
+        throw new IllegalArgumentException(
+          "readPrimitiveField() cannot handle embedded messages.");
+      case ENUM:
+        // We don't handle enums because we don't know what to do if the
+        // value is not recognized.
+        throw new IllegalArgumentException(
+          "readPrimitiveField() cannot handle enums.");
+    }
+
+    throw new RuntimeException(
+      "There is no way to get here, but the compiler thinks otherwise.");
+  }
 }
 }

+ 1 - 1
java/src/test/java/com/google/protobuf/GeneratedMessageTest.java

@@ -58,8 +58,8 @@ import protobuf_unittest.UnittestProto.ForeignMessage;
 import protobuf_unittest.UnittestProto.ForeignMessageOrBuilder;
 import protobuf_unittest.UnittestProto.ForeignMessageOrBuilder;
 import protobuf_unittest.UnittestProto.NestedTestAllTypes;
 import protobuf_unittest.UnittestProto.NestedTestAllTypes;
 import protobuf_unittest.UnittestProto.TestAllExtensions;
 import protobuf_unittest.UnittestProto.TestAllExtensions;
-import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
 import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
 import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder;
 import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder;
 import protobuf_unittest.UnittestProto.TestExtremeDefaultValues;
 import protobuf_unittest.UnittestProto.TestExtremeDefaultValues;
 import protobuf_unittest.UnittestProto.TestOneof2;
 import protobuf_unittest.UnittestProto.TestOneof2;

+ 138 - 1
java/src/test/java/com/google/protobuf/LazyFieldLiteTest.java

@@ -30,6 +30,9 @@
 
 
 package com.google.protobuf;
 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.TestAllExtensions;
 import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestAllTypes;
 
 
@@ -111,12 +114,146 @@ public class LazyFieldLiteTest extends TestCase {
     assertNotEqual(message.toByteString(), lazyField.toByteString());
     assertNotEqual(message.toByteString(), lazyField.toByteString());
   }
   }
 
 
+  public void testMergeExtensions() throws Exception {
+    TestAllExtensions message = TestUtil.getAllExtensionsSet();
+    LazyFieldLite original = createLazyFieldLiteFromMessage(message);
+    LazyFieldLite merged = new LazyFieldLite();
+    merged.merge(original);
+    TestAllExtensions value = (TestAllExtensions) merged.getValue(
+        TestAllExtensions.getDefaultInstance());
+    assertEquals(message, value);
+  }
+
+  public void testEmptyLazyField() throws Exception {
+    LazyFieldLite field = new LazyFieldLite();
+    assertEquals(0, field.getSerializedSize());
+    assertEquals(ByteString.EMPTY, field.toByteString());
+  }
+
+  public void testInvalidProto() throws Exception {
+    // Silently fails and uses the default instance.
+    LazyFieldLite field = new LazyFieldLite(
+        TestUtil.getExtensionRegistry(), ByteString.copyFromUtf8("invalid"));
+    assertEquals(
+        TestAllTypes.getDefaultInstance(), field.getValue(TestAllTypes.getDefaultInstance()));
+    assertEquals(0, field.getSerializedSize());
+    assertEquals(ByteString.EMPTY, field.toByteString());
+  }
+
+  public void testMergeBeforeParsing() throws Exception {
+    TestAllTypes message1 = TestAllTypes.newBuilder().setOptionalInt32(1).build();
+    LazyFieldLite field1 = createLazyFieldLiteFromMessage(message1);
+    TestAllTypes message2 = TestAllTypes.newBuilder().setOptionalInt64(2).build();
+    LazyFieldLite field2 = createLazyFieldLiteFromMessage(message2);
+
+    field1.merge(field2);
+    TestAllTypes expected =
+        TestAllTypes.newBuilder().setOptionalInt32(1).setOptionalInt64(2).build();
+    assertEquals(expected, field1.getValue(TestAllTypes.getDefaultInstance()));
+  }
+
+  public void testMergeOneNotParsed() throws Exception {
+    // Test a few different paths that involve one message that was not parsed.
+    TestAllTypes message1 = TestAllTypes.newBuilder().setOptionalInt32(1).build();
+    TestAllTypes message2 = TestAllTypes.newBuilder().setOptionalInt64(2).build();
+    TestAllTypes expected =
+        TestAllTypes.newBuilder().setOptionalInt32(1).setOptionalInt64(2).build();
+
+    LazyFieldLite field1 = LazyFieldLite.fromValue(message1);
+    field1.getValue(TestAllTypes.getDefaultInstance());  // Force parsing.
+    LazyFieldLite field2 = createLazyFieldLiteFromMessage(message2);
+    field1.merge(field2);
+    assertEquals(expected, field1.getValue(TestAllTypes.getDefaultInstance()));
+
+    // Now reverse which one is parsed first.
+    field1 = LazyFieldLite.fromValue(message1);
+    field2 = createLazyFieldLiteFromMessage(message2);
+    field2.getValue(TestAllTypes.getDefaultInstance());  // Force parsing.
+    field1.merge(field2);
+    assertEquals(expected, field1.getValue(TestAllTypes.getDefaultInstance()));
+  }
+
+  public void testMergeInvalid() throws Exception {
+    // Test a few different paths that involve one message that was not parsed.
+    TestAllTypes message = TestAllTypes.newBuilder().setOptionalInt32(1).build();
+    LazyFieldLite valid = LazyFieldLite.fromValue(message);
+    LazyFieldLite invalid = new LazyFieldLite(
+        TestUtil.getExtensionRegistry(), ByteString.copyFromUtf8("invalid"));
+    invalid.merge(valid);
+
+    // We swallow the exception and just use the set field.
+    assertEquals(message, invalid.getValue(TestAllTypes.getDefaultInstance()));
+  }
+
+  public void testMergeKeepsExtensionsWhenPossible() throws Exception {
+    // In this test we attempt to only use the empty registry, which will strip out all extensions
+    // when serializing and then parsing. We verify that each code path will attempt to not
+    // serialize and parse a message that was set directly without going through the
+    // extensionRegistry.
+    TestAllExtensions messageWithExtensions =
+        TestAllExtensions.newBuilder().setExtension(optionalInt32Extension, 42).build();
+    TestAllExtensions emptyMessage = TestAllExtensions.newBuilder().build();
+
+    ExtensionRegistryLite emptyRegistry = ExtensionRegistryLite.getEmptyRegistry();
+
+    LazyFieldLite field = LazyFieldLite.fromValue(messageWithExtensions);
+    field.merge(createLazyFieldLiteFromMessage(emptyRegistry, emptyMessage));
+    assertEquals(messageWithExtensions, field.getValue(TestAllExtensions.getDefaultInstance()));
+
+    // Now reverse the order of the merging.
+    field = createLazyFieldLiteFromMessage(emptyRegistry, emptyMessage);
+    field.merge(LazyFieldLite.fromValue(messageWithExtensions));
+    assertEquals(messageWithExtensions, field.getValue(TestAllExtensions.getDefaultInstance()));
+
+    // Now try parsing the empty field first.
+    field = LazyFieldLite.fromValue(messageWithExtensions);
+    LazyFieldLite other = createLazyFieldLiteFromMessage(emptyRegistry, emptyMessage);
+    other.getValue(TestAllExtensions.getDefaultInstance());  // Force parsing.
+    field.merge(other);
+    assertEquals(messageWithExtensions, field.getValue(TestAllExtensions.getDefaultInstance()));
+
+    // And again reverse.
+    field = createLazyFieldLiteFromMessage(emptyRegistry, emptyMessage);
+    field.getValue(TestAllExtensions.getDefaultInstance());  // Force parsing.
+    other = LazyFieldLite.fromValue(messageWithExtensions);
+    field.merge(other);
+    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.
   // Help methods.
 
 
   private LazyFieldLite createLazyFieldLiteFromMessage(MessageLite message) {
   private LazyFieldLite createLazyFieldLiteFromMessage(MessageLite message) {
+    return createLazyFieldLiteFromMessage(TestUtil.getExtensionRegistry(), message);
+  }
+
+  private LazyFieldLite createLazyFieldLiteFromMessage(
+      ExtensionRegistryLite extensionRegistry, MessageLite message) {
     ByteString bytes = message.toByteString();
     ByteString bytes = message.toByteString();
-    return new LazyFieldLite(TestUtil.getExtensionRegistry(), bytes);
+    return new LazyFieldLite(extensionRegistry, bytes);
   }
   }
 
 
   private void changeValue(LazyFieldLite lazyField) {
   private void changeValue(LazyFieldLite lazyField) {

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

@@ -30,6 +30,7 @@
 
 
 package com.google.protobuf;
 package com.google.protobuf;
 
 
+import protobuf_unittest.LazyFieldsLite.LazyExtension;
 import protobuf_unittest.LazyFieldsLite.LazyInnerMessageLite;
 import protobuf_unittest.LazyFieldsLite.LazyInnerMessageLite;
 import protobuf_unittest.LazyFieldsLite.LazyMessageLite;
 import protobuf_unittest.LazyFieldsLite.LazyMessageLite;
 import protobuf_unittest.LazyFieldsLite.LazyNestedInnerMessageLite;
 import protobuf_unittest.LazyFieldsLite.LazyNestedInnerMessageLite;
@@ -285,4 +286,22 @@ public class LazyMessageLiteTest extends TestCase {
 
 
     assertEquals(bytes, deserialized.toByteString());
     assertEquals(bytes, deserialized.toByteString());
   }
   }
+
+  public void testExtensions() throws Exception {
+    LazyInnerMessageLite.Builder innerBuilder = LazyInnerMessageLite.newBuilder();
+    innerBuilder.setExtension(
+        LazyExtension.extension, LazyExtension.newBuilder()
+        .setName("name").build());
+    assertTrue(innerBuilder.hasExtension(LazyExtension.extension));
+    assertEquals("name", innerBuilder.getExtension(LazyExtension.extension).getName());
+
+    LazyInnerMessageLite innerMessage = innerBuilder.build();
+    assertTrue(innerMessage.hasExtension(LazyExtension.extension));
+    assertEquals("name", innerMessage.getExtension(LazyExtension.extension).getName());
+
+    LazyMessageLite lite = LazyMessageLite.newBuilder()
+        .setInner(innerMessage).build();
+    assertTrue(lite.getInner().hasExtension(LazyExtension.extension));
+    assertEquals("name", lite.getInner().getExtension(LazyExtension.extension).getName());
+  }
 }
 }

+ 22 - 2
java/src/test/java/com/google/protobuf/LiteralByteStringTest.java

@@ -289,7 +289,6 @@ public class LiteralByteStringTest extends TestCase {
     assertEquals("Output.reset() resets the output", 0, output.size());
     assertEquals("Output.reset() resets the output", 0, output.size());
     assertEquals("Output.reset() resets the output",
     assertEquals("Output.reset() resets the output",
         ByteString.EMPTY, output.toByteString());
         ByteString.EMPTY, output.toByteString());
-    
   }
   }
 
 
   public void testToString() throws UnsupportedEncodingException {
   public void testToString() throws UnsupportedEncodingException {
@@ -299,6 +298,27 @@ public class LiteralByteStringTest extends TestCase {
     assertEquals(classUnderTest + " unicode must match", testString, roundTripString);
     assertEquals(classUnderTest + " unicode must match", testString, roundTripString);
   }
   }
 
 
+  public void testToString_returnsCanonicalEmptyString() throws UnsupportedEncodingException{
+    assertSame(classUnderTest + " must be the same string references",
+        ByteString.EMPTY.toString(UTF_8), new LiteralByteString(new byte[]{}).toString(UTF_8));
+  }
+
+  public void testToString_raisesException() throws UnsupportedEncodingException{
+    try {
+      ByteString.EMPTY.toString("invalid");
+      fail("Should have thrown an exception.");
+    } catch (UnsupportedEncodingException expected) {
+      // This is success
+    }
+
+    try {
+      new LiteralByteString(referenceBytes).toString("invalid");
+      fail("Should have thrown an exception.");
+    } catch (UnsupportedEncodingException expected) {
+      // This is success
+    }
+  }
+
   public void testEquals() {
   public void testEquals() {
     assertEquals(classUnderTest + " must not equal null", false, stringUnderTest.equals(null));
     assertEquals(classUnderTest + " must not equal null", false, stringUnderTest.equals(null));
     assertEquals(classUnderTest + " must equal self", stringUnderTest, stringUnderTest);
     assertEquals(classUnderTest + " must equal self", stringUnderTest, stringUnderTest);
@@ -311,7 +331,7 @@ public class LiteralByteStringTest extends TestCase {
 
 
     byte[] mungedBytes = new byte[referenceBytes.length];
     byte[] mungedBytes = new byte[referenceBytes.length];
     System.arraycopy(referenceBytes, 0, mungedBytes, 0, referenceBytes.length);
     System.arraycopy(referenceBytes, 0, mungedBytes, 0, referenceBytes.length);
-    mungedBytes[mungedBytes.length - 5] ^= 0xFF;
+    mungedBytes[mungedBytes.length - 5] = (byte) (mungedBytes[mungedBytes.length - 5] ^ 0xFF);
     assertFalse(classUnderTest + " must not equal every string with the same length",
     assertFalse(classUnderTest + " must not equal every string with the same length",
         stringUnderTest.equals(new LiteralByteString(mungedBytes)));
         stringUnderTest.equals(new LiteralByteString(mungedBytes)));
   }
   }

+ 14 - 0
java/src/test/java/com/google/protobuf/MapForProto2Test.java

@@ -34,6 +34,7 @@ import com.google.protobuf.Descriptors.FieldDescriptor;
 import map_test.MapForProto2TestProto.TestMap;
 import map_test.MapForProto2TestProto.TestMap;
 import map_test.MapForProto2TestProto.TestMap.MessageValue;
 import map_test.MapForProto2TestProto.TestMap.MessageValue;
 import map_test.MapForProto2TestProto.TestMap.MessageWithRequiredFields;
 import map_test.MapForProto2TestProto.TestMap.MessageWithRequiredFields;
+import map_test.MapForProto2TestProto.TestRecursiveMap;
 import map_test.MapForProto2TestProto.TestUnknownEnumValue;
 import map_test.MapForProto2TestProto.TestUnknownEnumValue;
 
 
 import junit.framework.TestCase;
 import junit.framework.TestCase;
@@ -499,4 +500,17 @@ public class MapForProto2Test extends TestCase {
     message = builder.build();
     message = builder.build();
     assertTrue(message.isInitialized());
     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());
+    ByteString data = builder.build().toByteString();
+
+    TestRecursiveMap message = TestRecursiveMap.parseFrom(data);
+    assertEquals(2, message.getRecursiveMapField().get(1).getValue());
+    assertEquals(4, message.getRecursiveMapField().get(3).getValue());
+  }
 }
 }

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

@@ -269,7 +269,6 @@ public class MapTest extends TestCase {
     assertFalse(m2.equals(m1));
     assertFalse(m2.equals(m1));
   }
   }
 
 
-
   public void testNestedBuilderOnChangeEventPropagation() {
   public void testNestedBuilderOnChangeEventPropagation() {
     TestOnChangeEventPropagation.Builder parent =
     TestOnChangeEventPropagation.Builder parent =
         TestOnChangeEventPropagation.newBuilder();
         TestOnChangeEventPropagation.newBuilder();

+ 28 - 0
java/src/test/java/com/google/protobuf/RopeByteStringTest.java

@@ -118,6 +118,34 @@ public class RopeByteStringTest extends LiteralByteStringTest {
         flatString.hashCode(), unicode.hashCode());
         flatString.hashCode(), unicode.hashCode());
   }
   }
 
 
+  @Override
+  public void testToString_returnsCanonicalEmptyString() throws UnsupportedEncodingException {
+    RopeByteString ropeByteString =
+        RopeByteString.newInstanceForTest(ByteString.EMPTY, ByteString.EMPTY);
+    assertSame(classUnderTest + " must be the same string references",
+        ByteString.EMPTY.toString(UTF_8), ropeByteString.toString(UTF_8));
+  }
+
+  public void testToString_raisesException() throws UnsupportedEncodingException{
+    try {
+      ByteString byteString =
+          RopeByteString.newInstanceForTest(ByteString.EMPTY, ByteString.EMPTY);
+      byteString.toString("invalid");
+      fail("Should have thrown an exception.");
+    } catch (UnsupportedEncodingException expected) {
+      // This is success
+    }
+
+    try {
+      ByteString byteString = RopeByteString.concatenate(ByteString.copyFromUtf8("foo"),
+          ByteString.copyFromUtf8("bar"));
+      byteString.toString("invalid");
+      fail("Should have thrown an exception.");
+    } catch (UnsupportedEncodingException expected) {
+      // This is success
+    }
+  }
+
   public void testJavaSerialization() throws Exception {
   public void testJavaSerialization() throws Exception {
     ByteArrayOutputStream out = new ByteArrayOutputStream();
     ByteArrayOutputStream out = new ByteArrayOutputStream();
     ObjectOutputStream oos = new ObjectOutputStream(out);
     ObjectOutputStream oos = new ObjectOutputStream(out);

+ 9 - 0
java/src/test/java/com/google/protobuf/lazy_fields_lite.proto

@@ -54,6 +54,15 @@ message LazyInnerMessageLite {
   optional int32 num = 1;
   optional int32 num = 1;
   optional int32 num_with_default = 2 [default = 42];
   optional int32 num_with_default = 2 [default = 42];
   optional LazyNestedInnerMessageLite nested = 3 [lazy = true];
   optional LazyNestedInnerMessageLite nested = 3 [lazy = true];
+
+  extensions 1000 to max;
+}
+
+message LazyExtension {
+  extend LazyInnerMessageLite {
+    optional LazyExtension extension = 1000;
+  }
+  optional string name = 1;
 }
 }
 
 
 message LazyNestedInnerMessageLite {
 message LazyNestedInnerMessageLite {

+ 7 - 0
java/src/test/java/com/google/protobuf/map_for_proto2_lite_test.proto

@@ -63,6 +63,13 @@ message TestUnknownEnumValue {
   // parsing behavior of TestMap regarding unknown enum values.
   // parsing behavior of TestMap regarding unknown enum values.
   map<int32, int32> int32_to_int32_field = 4;
   map<int32, int32> int32_to_int32_field = 4;
 }
 }
+
+// Test that the maps initialization code works correctly when the map field
+// references the containing message.
+message TestRecursiveMap {
+  optional int32 value = 1;
+  map<int32, TestRecursiveMap> recursive_map_field = 2;
+}
 package map_for_proto2_lite_test;
 package map_for_proto2_lite_test;
 option java_package = "map_lite_test";
 option java_package = "map_lite_test";
 option optimize_for = LITE_RUNTIME;
 option optimize_for = LITE_RUNTIME;

+ 7 - 0
java/src/test/java/com/google/protobuf/map_for_proto2_test.proto

@@ -65,3 +65,10 @@ message TestUnknownEnumValue {
   // parsing behavior of TestMap regarding unknown enum values.
   // parsing behavior of TestMap regarding unknown enum values.
   map<int32, int32> int32_to_int32_field = 4;
   map<int32, int32> int32_to_int32_field = 4;
 }
 }
+
+// Test that the maps initialization code works correctly when the map field
+// references the containing message.
+message TestRecursiveMap {
+  optional int32 value = 1;
+  map<int32, TestRecursiveMap> recursive_map_field = 2;
+}

+ 1 - 0
java/src/test/java/com/google/protobuf/map_test.proto

@@ -36,6 +36,7 @@ option java_package = "map_test";
 option java_outer_classname = "MapTestProto";
 option java_outer_classname = "MapTestProto";
 option java_generate_equals_and_hash = true;
 option java_generate_equals_and_hash = true;
 
 
+
 message TestMap {
 message TestMap {
   message MessageValue {
   message MessageValue {
     optional int32 value = 1;
     optional int32 value = 1;

+ 1 - 0
java/src/test/java/com/google/protobuf/test_bad_identifiers.proto

@@ -45,6 +45,7 @@ option java_package = "com.google.protobuf";
 option java_outer_classname = "TestBadIdentifiersProto";
 option java_outer_classname = "TestBadIdentifiersProto";
 option java_generate_equals_and_hash = true;
 option java_generate_equals_and_hash = true;
 
 
+
 message TestMessage {
 message TestMessage {
   optional string cached_size = 1;
   optional string cached_size = 1;
   optional string serialized_size = 2;
   optional string serialized_size = 2;

+ 2 - 1
python/google/protobuf/internal/message_test.py

@@ -51,10 +51,10 @@ import sys
 import unittest
 import unittest
 
 
 from google.apputils import basetest
 from google.apputils import basetest
+from google.protobuf.internal import _parameterized
 from google.protobuf import unittest_pb2
 from google.protobuf import unittest_pb2
 from google.protobuf import unittest_proto3_arena_pb2
 from google.protobuf import unittest_proto3_arena_pb2
 from google.protobuf.internal import api_implementation
 from google.protobuf.internal import api_implementation
-from google.protobuf.internal import _parameterized
 from google.protobuf.internal import test_util
 from google.protobuf.internal import test_util
 from google.protobuf import message
 from google.protobuf import message
 
 
@@ -982,6 +982,7 @@ class Proto2Test(basetest.TestCase):
     # This is still an incomplete proto - so serializing should fail
     # This is still an incomplete proto - so serializing should fail
     self.assertRaises(message.EncodeError, unpickled_message.SerializeToString)
     self.assertRaises(message.EncodeError, unpickled_message.SerializeToString)
 
 
+
   # TODO(haberman): this isn't really a proto2-specific test except that this
   # TODO(haberman): this isn't really a proto2-specific test except that this
   # message has a required field in it.  Should probably be factored out so
   # message has a required field in it.  Should probably be factored out so
   # that we can test the other parts with proto3.
   # that we can test the other parts with proto3.

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

@@ -37,12 +37,12 @@ __author__ = 'kenton@google.com (Kenton Varda)'
 import re
 import re
 
 
 from google.apputils import basetest
 from google.apputils import basetest
+from google.protobuf.internal import _parameterized
 
 
 from google.protobuf import unittest_mset_pb2
 from google.protobuf import unittest_mset_pb2
 from google.protobuf import unittest_pb2
 from google.protobuf import unittest_pb2
 from google.protobuf import unittest_proto3_arena_pb2
 from google.protobuf import unittest_proto3_arena_pb2
 from google.protobuf.internal import api_implementation
 from google.protobuf.internal import api_implementation
-from google.protobuf.internal import _parameterized
 from google.protobuf.internal import test_util
 from google.protobuf.internal import test_util
 from google.protobuf import text_format
 from google.protobuf import text_format
 
 

+ 9 - 6
python/google/protobuf/pyext/descriptor.cc

@@ -298,8 +298,9 @@ static PyGetSetDef Getters[] = {
 
 
 PyTypeObject PyBaseDescriptor_Type = {
 PyTypeObject PyBaseDescriptor_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  "google.protobuf.internal."
-    "_message.DescriptorBase",          // tp_name
+  // Keep the fully qualified _message symbol in a line for opensource.
+  "google.protobuf.internal._message."
+  "DescriptorBase",                     // tp_name
   sizeof(PyBaseDescriptor),             // tp_basicsize
   sizeof(PyBaseDescriptor),             // tp_basicsize
   0,                                    // tp_itemsize
   0,                                    // tp_itemsize
   (destructor)Dealloc,                  // tp_dealloc
   (destructor)Dealloc,                  // tp_dealloc
@@ -551,8 +552,9 @@ static PyMethodDef Methods[] = {
 
 
 PyTypeObject PyMessageDescriptor_Type = {
 PyTypeObject PyMessageDescriptor_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  C("google.protobuf.internal."
-    "_message.MessageDescriptor"),      // tp_name
+  // Keep the fully qualified _message symbol in a line for opensource.
+  C("google.protobuf.internal._message."
+    "MessageDescriptor"),      // tp_name
   sizeof(PyBaseDescriptor),             // tp_basicsize
   sizeof(PyBaseDescriptor),             // tp_basicsize
   0,                                    // tp_itemsize
   0,                                    // tp_itemsize
   0,                                    // tp_dealloc
   0,                                    // tp_dealloc
@@ -979,8 +981,9 @@ static PyGetSetDef Getters[] = {
 
 
 PyTypeObject PyEnumDescriptor_Type = {
 PyTypeObject PyEnumDescriptor_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  C("google.protobuf.internal."
-    "_message.EnumDescriptor"),         // tp_name
+  // Keep the fully qualified _message symbol in a line for opensource.
+  C("google.protobuf.internal._message."
+    "EnumDescriptor"),                  // tp_name
   sizeof(PyBaseDescriptor),             // tp_basicsize
   sizeof(PyBaseDescriptor),             // tp_basicsize
   0,                                    // tp_itemsize
   0,                                    // tp_itemsize
   0,                                    // tp_dealloc
   0,                                    // tp_dealloc

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

@@ -2304,8 +2304,9 @@ int SetAttr(CMessage* self, PyObject* name, PyObject* value) {
 
 
 PyTypeObject CMessage_Type = {
 PyTypeObject CMessage_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  "google.protobuf."
-  "pyext._message.CMessage",           // tp_name
+  // Keep the fully qualified _message symbol in a line for opensource.
+  "google.protobuf.pyext._message."
+  "CMessage",                          // tp_name
   sizeof(CMessage),                    // tp_basicsize
   sizeof(CMessage),                    // tp_basicsize
   0,                                   //  tp_itemsize
   0,                                   //  tp_itemsize
   (destructor)cmessage::Dealloc,       //  tp_dealloc
   (destructor)cmessage::Dealloc,       //  tp_dealloc

+ 4 - 3
python/google/protobuf/pyext/repeated_composite_container.cc

@@ -732,9 +732,10 @@ static PyMethodDef Methods[] = {
 
 
 PyTypeObject RepeatedCompositeContainer_Type = {
 PyTypeObject RepeatedCompositeContainer_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  "google.protobuf.pyext."
-  "_message.RepeatedCompositeContainer",  // tp_name
-  sizeof(RepeatedCompositeContainer),     // tp_basicsize
+  // Keep the fully qualified _message symbol in a line for opensource.
+  "google.protobuf.pyext._message."
+  "RepeatedCompositeContainer",        // tp_name
+  sizeof(RepeatedCompositeContainer),  // tp_basicsize
   0,                                   //  tp_itemsize
   0,                                   //  tp_itemsize
   (destructor)repeated_composite_container::Dealloc,  //  tp_dealloc
   (destructor)repeated_composite_container::Dealloc,  //  tp_dealloc
   0,                                   //  tp_print
   0,                                   //  tp_print

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

@@ -769,8 +769,9 @@ static PyMethodDef Methods[] = {
 
 
 PyTypeObject RepeatedScalarContainer_Type = {
 PyTypeObject RepeatedScalarContainer_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  "google.protobuf."
-  "pyext._message.RepeatedScalarContainer",  // tp_name
+  // Keep the fully qualified _message symbol in a line for opensource.
+  "google.protobuf.pyext._message."
+  "RepeatedScalarContainer",           // tp_name
   sizeof(RepeatedScalarContainer),     // tp_basicsize
   sizeof(RepeatedScalarContainer),     // tp_basicsize
   0,                                   //  tp_itemsize
   0,                                   //  tp_itemsize
   (destructor)repeated_scalar_container::Dealloc,  //  tp_dealloc
   (destructor)repeated_scalar_container::Dealloc,  //  tp_dealloc

+ 16 - 3
src/Makefile.am

@@ -84,10 +84,13 @@ nobase_include_HEADERS =                                        \
   google/protobuf/dynamic_message.h                             \
   google/protobuf/dynamic_message.h                             \
   google/protobuf/extension_set.h                               \
   google/protobuf/extension_set.h                               \
   google/protobuf/generated_enum_reflection.h                   \
   google/protobuf/generated_enum_reflection.h                   \
+  google/protobuf/generated_enum_util.h                         \
   google/protobuf/generated_message_reflection.h                \
   google/protobuf/generated_message_reflection.h                \
   google/protobuf/generated_message_util.h                      \
   google/protobuf/generated_message_util.h                      \
   google/protobuf/map_entry.h                                   \
   google/protobuf/map_entry.h                                   \
+  google/protobuf/map_entry_lite.h                              \
   google/protobuf/map_field.h                                   \
   google/protobuf/map_field.h                                   \
+  google/protobuf/map_field_lite.h                              \
   google/protobuf/map_field_inl.h                               \
   google/protobuf/map_field_inl.h                               \
   google/protobuf/map.h                                         \
   google/protobuf/map.h                                         \
   google/protobuf/map_type_handler.h                            \
   google/protobuf/map_type_handler.h                            \
@@ -316,6 +319,7 @@ protoc_inputs =                                                \
   google/protobuf/unittest_no_generic_services.proto           \
   google/protobuf/unittest_no_generic_services.proto           \
   google/protobuf/unittest_optimize_for.proto                  \
   google/protobuf/unittest_optimize_for.proto                  \
   google/protobuf/unittest_preserve_unknown_enum.proto         \
   google/protobuf/unittest_preserve_unknown_enum.proto         \
+  google/protobuf/unittest_preserve_unknown_enum2.proto        \
   google/protobuf/unittest_proto3_arena.proto                  \
   google/protobuf/unittest_proto3_arena.proto                  \
   google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
   google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
 
 
@@ -342,6 +346,8 @@ EXTRA_DIST =                                                   \
   google/protobuf/unittest_enormous_descriptor.proto
   google/protobuf/unittest_enormous_descriptor.proto
 
 
 protoc_lite_outputs =                                          \
 protoc_lite_outputs =                                          \
+  google/protobuf/map_lite_unittest.pb.cc                      \
+  google/protobuf/map_lite_unittest.pb.h                       \
   google/protobuf/unittest_lite.pb.cc                          \
   google/protobuf/unittest_lite.pb.cc                          \
   google/protobuf/unittest_lite.pb.h                           \
   google/protobuf/unittest_lite.pb.h                           \
   google/protobuf/unittest_import_lite.pb.cc                   \
   google/protobuf/unittest_import_lite.pb.cc                   \
@@ -351,8 +357,6 @@ protoc_lite_outputs =                                          \
 
 
 protoc_outputs =                                               \
 protoc_outputs =                                               \
   $(protoc_lite_outputs)                                       \
   $(protoc_lite_outputs)                                       \
-  google/protobuf/map_lite_unittest.pb.cc                      \
-  google/protobuf/map_lite_unittest.pb.h                       \
   google/protobuf/map_proto2_unittest.pb.cc                    \
   google/protobuf/map_proto2_unittest.pb.cc                    \
   google/protobuf/map_proto2_unittest.pb.h                     \
   google/protobuf/map_proto2_unittest.pb.h                     \
   google/protobuf/map_unittest.pb.cc                           \
   google/protobuf/map_unittest.pb.cc                           \
@@ -389,12 +393,14 @@ protoc_outputs =                                               \
   google/protobuf/unittest_optimize_for.pb.h                   \
   google/protobuf/unittest_optimize_for.pb.h                   \
   google/protobuf/unittest_preserve_unknown_enum.pb.cc         \
   google/protobuf/unittest_preserve_unknown_enum.pb.cc         \
   google/protobuf/unittest_preserve_unknown_enum.pb.h          \
   google/protobuf/unittest_preserve_unknown_enum.pb.h          \
+  google/protobuf/unittest_preserve_unknown_enum2.pb.cc        \
+  google/protobuf/unittest_preserve_unknown_enum2.pb.h         \
   google/protobuf/unittest_proto3_arena.pb.cc                  \
   google/protobuf/unittest_proto3_arena.pb.cc                  \
   google/protobuf/unittest_proto3_arena.pb.h                   \
   google/protobuf/unittest_proto3_arena.pb.h                   \
   google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc  \
   google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc  \
   google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.h
   google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.h
 
 
-BUILT_SOURCES = $(public_config) $(protoc_outputs) 
+BUILT_SOURCES = $(public_config) $(protoc_outputs)
 
 
 if USE_EXTERNAL_PROTOC
 if USE_EXTERNAL_PROTOC
 
 
@@ -416,8 +422,11 @@ endif
 $(protoc_outputs): unittest_proto_middleman
 $(protoc_outputs): unittest_proto_middleman
 
 
 COMMON_TEST_SOURCES =                                          \
 COMMON_TEST_SOURCES =                                          \
+  google/protobuf/arena_test_util.cc                           \
+  google/protobuf/arena_test_util.h                            \
   google/protobuf/map_test_util.cc                             \
   google/protobuf/map_test_util.cc                             \
   google/protobuf/map_test_util.h                              \
   google/protobuf/map_test_util.h                              \
+  google/protobuf/map_test_util_impl.h                         \
   google/protobuf/test_util.cc                                 \
   google/protobuf/test_util.cc                                 \
   google/protobuf/test_util.h                                  \
   google/protobuf/test_util.h                                  \
   google/protobuf/testing/googletest.cc                        \
   google/protobuf/testing/googletest.cc                        \
@@ -503,8 +512,12 @@ protobuf_lite_test_LDADD = $(PTHREAD_LIBS) libprotobuf-lite.la
 protobuf_lite_test_CXXFLAGS = $(NO_OPT_CXXFLAGS)
 protobuf_lite_test_CXXFLAGS = $(NO_OPT_CXXFLAGS)
 protobuf_lite_test_SOURCES =                                           \
 protobuf_lite_test_SOURCES =                                           \
   google/protobuf/lite_unittest.cc                                     \
   google/protobuf/lite_unittest.cc                                     \
+  google/protobuf/map_lite_test_util.cc                                \
+  google/protobuf/map_lite_test_util.h                                 \
   google/protobuf/test_util_lite.cc                                    \
   google/protobuf/test_util_lite.cc                                    \
   google/protobuf/test_util_lite.h
   google/protobuf/test_util_lite.h
+  # TODO(teboring) add the file back and make the test build.
+  # google/protobuf/map_lite_test.cc
 nodist_protobuf_lite_test_SOURCES = $(protoc_lite_outputs)
 nodist_protobuf_lite_test_SOURCES = $(protoc_lite_outputs)
 
 
 # Test plugin binary.
 # Test plugin binary.

+ 47 - 20
src/google/protobuf/arena.cc

@@ -44,38 +44,56 @@ Arena::ThreadCache& Arena::thread_cache() {
   return thread_cache_;
   return thread_cache_;
 }
 }
 #else
 #else
-GOOGLE_THREAD_LOCAL Arena::ThreadCache Arena::thread_cache_ = { -1, NULL };
+__thread Arena::ThreadCache Arena::thread_cache_ = { -1, NULL };
 #endif
 #endif
 
 
-void Arena::Init(const ArenaOptions& options) {
+void Arena::Init() {
   lifecycle_id_ = lifecycle_id_generator_.GetNext();
   lifecycle_id_ = lifecycle_id_generator_.GetNext();
-  start_block_size_ = options.start_block_size;
-  max_block_size_ = options.max_block_size;
-  block_alloc = options.block_alloc;
-  block_dealloc = options.block_dealloc;
   blocks_ = 0;
   blocks_ = 0;
   hint_ = 0;
   hint_ = 0;
   owns_first_block_ = true;
   owns_first_block_ = true;
   cleanup_list_ = 0;
   cleanup_list_ = 0;
 
 
-  if (options.initial_block != NULL && options.initial_block_size > 0) {
+  if (options_.initial_block != NULL && options_.initial_block_size > 0) {
     // Add first unowned block to list.
     // Add first unowned block to list.
-    Block* first_block = reinterpret_cast<Block*>(options.initial_block);
-    first_block->size = options.initial_block_size;
+    Block* first_block = reinterpret_cast<Block*>(options_.initial_block);
+    first_block->size = options_.initial_block_size;
     first_block->pos = kHeaderSize;
     first_block->pos = kHeaderSize;
     first_block->next = NULL;
     first_block->next = NULL;
     first_block->owner = &first_block->owner;
     first_block->owner = &first_block->owner;
     AddBlock(first_block);
     AddBlock(first_block);
     owns_first_block_ = false;
     owns_first_block_ = false;
   }
   }
+
+  // Call the initialization hook
+  if (options_.on_arena_init != NULL) {
+    hooks_cookie_ = options_.on_arena_init(this);
+  } else {
+    hooks_cookie_ = NULL;
+  }
+}
+
+Arena::~Arena() {
+  uint64 space_allocated = Reset();
+
+  // Call the destruction hook
+  if (options_.on_arena_destruction != NULL) {
+    options_.on_arena_destruction(this, hooks_cookie_, space_allocated);
+  }
 }
 }
 
 
 uint64 Arena::Reset() {
 uint64 Arena::Reset() {
   CleanupList();
   CleanupList();
-  uint64 space_used = FreeBlocks();
+  uint64 space_allocated = FreeBlocks();
   // Invalidate any ThreadCaches pointing to any blocks we just destroyed.
   // Invalidate any ThreadCaches pointing to any blocks we just destroyed.
   lifecycle_id_ = lifecycle_id_generator_.GetNext();
   lifecycle_id_ = lifecycle_id_generator_.GetNext();
-  return space_used;
+
+  // Call the reset hook
+  if (options_.on_arena_reset != NULL) {
+    options_.on_arena_reset(this, hooks_cookie_, space_allocated);
+  }
+
+  return space_allocated;
 }
 }
 
 
 Arena::Block* Arena::NewBlock(void* me, Block* my_last_block, size_t n,
 Arena::Block* Arena::NewBlock(void* me, Block* my_last_block, size_t n,
@@ -93,7 +111,7 @@ Arena::Block* Arena::NewBlock(void* me, Block* my_last_block, size_t n,
     size = kHeaderSize + n;
     size = kHeaderSize + n;
   }
   }
 
 
-  Block* b = reinterpret_cast<Block*>(block_alloc(size));
+  Block* b = reinterpret_cast<Block*>(options_.block_alloc(size));
   b->pos = kHeaderSize + n;
   b->pos = kHeaderSize + n;
   b->size = size;
   b->size = size;
   if (b->avail() == 0) {
   if (b->avail() == 0) {
@@ -184,7 +202,7 @@ void* Arena::SlowAlloc(size_t n) {
     google::protobuf::internal::NoBarrier_Store(&hint_, reinterpret_cast<google::protobuf::internal::AtomicWord>(b));
     google::protobuf::internal::NoBarrier_Store(&hint_, reinterpret_cast<google::protobuf::internal::AtomicWord>(b));
     return AllocFromBlock(b, n);
     return AllocFromBlock(b, n);
   }
   }
-  b = NewBlock(me, b, n, start_block_size_, max_block_size_);
+  b = NewBlock(me, b, n, options_.start_block_size, options_.max_block_size);
   AddBlock(b);
   AddBlock(b);
   if (b->owner == me) {  // If this block can be reused (see NewBlock()).
   if (b->owner == me) {  // If this block can be reused (see NewBlock()).
     SetThreadCacheBlock(b);
     SetThreadCacheBlock(b);
@@ -192,29 +210,38 @@ void* Arena::SlowAlloc(size_t n) {
   return reinterpret_cast<char*>(b) + kHeaderSize;
   return reinterpret_cast<char*>(b) + kHeaderSize;
 }
 }
 
 
+uint64 Arena::SpaceAllocated() const {
+  uint64 space_allocated = 0;
+  Block* b = reinterpret_cast<Block*>(google::protobuf::internal::NoBarrier_Load(&blocks_));
+  while (b != NULL) {
+    space_allocated += (b->size);
+    b = b->next;
+  }
+  return space_allocated;
+}
+
 uint64 Arena::SpaceUsed() const {
 uint64 Arena::SpaceUsed() const {
   uint64 space_used = 0;
   uint64 space_used = 0;
   Block* b = reinterpret_cast<Block*>(google::protobuf::internal::NoBarrier_Load(&blocks_));
   Block* b = reinterpret_cast<Block*>(google::protobuf::internal::NoBarrier_Load(&blocks_));
   while (b != NULL) {
   while (b != NULL) {
-    space_used += (b->size);
+    space_used += (b->pos - kHeaderSize);
     b = b->next;
     b = b->next;
   }
   }
   return space_used;
   return space_used;
 }
 }
 
 
-
 uint64 Arena::FreeBlocks() {
 uint64 Arena::FreeBlocks() {
-  uint64 space_used = 0;
+  uint64 space_allocated = 0;
   Block* b = reinterpret_cast<Block*>(google::protobuf::internal::NoBarrier_Load(&blocks_));
   Block* b = reinterpret_cast<Block*>(google::protobuf::internal::NoBarrier_Load(&blocks_));
   Block* first_block = NULL;
   Block* first_block = NULL;
   while (b != NULL) {
   while (b != NULL) {
-    space_used += (b->size);
+    space_allocated += (b->size);
     Block* next = b->next;
     Block* next = b->next;
     if (next != NULL) {
     if (next != NULL) {
-      block_dealloc(b, b->size);
+      options_.block_dealloc(b, b->size);
     } else {
     } else {
       if (owns_first_block_) {
       if (owns_first_block_) {
-        block_dealloc(b, b->size);
+        options_.block_dealloc(b, b->size);
       } else {
       } else {
         // User passed in the first block, skip free'ing the memory.
         // User passed in the first block, skip free'ing the memory.
         first_block = b;
         first_block = b;
@@ -231,7 +258,7 @@ uint64 Arena::FreeBlocks() {
     first_block->owner = &first_block->owner;
     first_block->owner = &first_block->owner;
     AddBlock(first_block);
     AddBlock(first_block);
   }
   }
-  return space_used;
+  return space_allocated;
 }
 }
 
 
 void Arena::CleanupList() {
 void Arena::CleanupList() {

+ 136 - 20
src/google/protobuf/arena.h

@@ -34,9 +34,11 @@
 #ifndef GOOGLE_PROTOBUF_ARENA_H__
 #ifndef GOOGLE_PROTOBUF_ARENA_H__
 #define GOOGLE_PROTOBUF_ARENA_H__
 #define GOOGLE_PROTOBUF_ARENA_H__
 
 
-#include <google/protobuf/stubs/common.h>
+#include <typeinfo>
+
 #include <google/protobuf/stubs/atomic_sequence_num.h>
 #include <google/protobuf/stubs/atomic_sequence_num.h>
 #include <google/protobuf/stubs/atomicops.h>
 #include <google/protobuf/stubs/atomicops.h>
+#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/type_traits.h>
 #include <google/protobuf/stubs/type_traits.h>
 
 
 namespace google {
 namespace google {
@@ -89,19 +91,44 @@ struct ArenaOptions {
 
 
   // A function pointer to an alloc method that returns memory blocks of size
   // A function pointer to an alloc method that returns memory blocks of size
   // requested. By default, it contains a ptr to the malloc function.
   // requested. By default, it contains a ptr to the malloc function.
+  //
+  // NOTE: block_alloc and dealloc functions are expected to behave like
+  // malloc and free, including Asan poisoning.
   void* (*block_alloc)(size_t);
   void* (*block_alloc)(size_t);
   // A function pointer to a dealloc method that takes ownership of the blocks
   // A function pointer to a dealloc method that takes ownership of the blocks
   // from the arena. By default, it contains a ptr to a wrapper function that
   // from the arena. By default, it contains a ptr to a wrapper function that
   // calls free.
   // calls free.
   void (*block_dealloc)(void*, size_t);
   void (*block_dealloc)(void*, size_t);
 
 
+  // Hooks for adding external functionality such as user-specific metrics
+  // collection, specific debugging abilities, etc.
+  // Init hook may return a pointer to a cookie to be stored in the arena.
+  // reset and destruction hooks will then be called with the same cookie
+  // pointer. This allows us to save an external object per arena instance and
+  // use it on the other hooks (Note: It is just as legal for init to return
+  // NULL and not use the cookie feature).
+  // on_arena_reset and on_arena_destruction also receive the space used in
+  // the arena just before the reset.
+  void* (*on_arena_init)(Arena* arena);
+  void (*on_arena_reset)(Arena* arena, void* cookie, uint64 space_used);
+  void (*on_arena_destruction)(Arena* arena, void* cookie, uint64 space_used);
+
+  // type_name is promised to be a static string - its lifetime extends to
+  // match program's lifetime.
+  void (*on_arena_allocation)(const char* type_name, uint64 alloc_size,
+      Arena* arena, void* cookie);
+
   ArenaOptions()
   ArenaOptions()
       : start_block_size(kDefaultStartBlockSize),
       : start_block_size(kDefaultStartBlockSize),
         max_block_size(kDefaultMaxBlockSize),
         max_block_size(kDefaultMaxBlockSize),
         initial_block(NULL),
         initial_block(NULL),
         initial_block_size(0),
         initial_block_size(0),
         block_alloc(&malloc),
         block_alloc(&malloc),
-        block_dealloc(&internal::arena_free) {}
+        block_dealloc(&internal::arena_free),
+        on_arena_init(NULL),
+        on_arena_reset(NULL),
+        on_arena_destruction(NULL),
+        on_arena_allocation(NULL) {}
 
 
  private:
  private:
   // Constants define default starting block size and max block size for
   // Constants define default starting block size and max block size for
@@ -123,23 +150,21 @@ class LIBPROTOBUF_EXPORT Arena {
  public:
  public:
   // Arena constructor taking custom options. See ArenaOptions below for
   // Arena constructor taking custom options. See ArenaOptions below for
   // descriptions of the options available.
   // descriptions of the options available.
-  explicit Arena(const ArenaOptions& options) {
-    Init(options);
+  explicit Arena(const ArenaOptions& options) : options_(options) {
+    Init();
   }
   }
 
 
   // Default constructor with sensible default options, tuned for average
   // Default constructor with sensible default options, tuned for average
   // use-cases.
   // use-cases.
   Arena() {
   Arena() {
-    Init(ArenaOptions());
+    Init();
   }
   }
 
 
   // Destructor deletes all owned heap allocated objects, and destructs objects
   // Destructor deletes all owned heap allocated objects, and destructs objects
   // that have non-trivial destructors, except for proto2 message objects whose
   // that have non-trivial destructors, except for proto2 message objects whose
   // destructors can be skipped. Also, frees all blocks except the initial block
   // destructors can be skipped. Also, frees all blocks except the initial block
   // if it was passed in.
   // if it was passed in.
-  ~Arena() {
-    Reset();
-  }
+  ~Arena();
 
 
   // API to create proto2 message objects on the arena. If the arena passed in
   // API to create proto2 message objects on the arena. If the arena passed in
   // is NULL, then a heap allocated object is returned. Type T must be a message
   // is NULL, then a heap allocated object is returned. Type T must be a message
@@ -195,6 +220,40 @@ class LIBPROTOBUF_EXPORT Arena {
     }
     }
   }
   }
 
 
+  // Version of the above with three constructor arguments for the created
+  // object.
+  template <typename T, typename Arg1, typename Arg2, typename Arg3>
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* Create(::google::protobuf::Arena* arena,
+                                           const Arg1& arg1, const Arg2& arg2,
+                                           const Arg3& arg3) {
+    if (arena == NULL) {
+      return new T(arg1, arg2, arg3);
+    } else {
+      return arena->CreateInternal<T>(SkipDeleteList<T>(static_cast<T*>(0)),
+                                      arg1,
+                                      arg2,
+                                      arg3);
+    }
+  }
+
+  // Version of the above with four constructor arguments for the created
+  // object.
+  template <typename T, typename Arg1, typename Arg2, typename Arg3,
+            typename Arg4>
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* Create(::google::protobuf::Arena* arena,
+                                           const Arg1& arg1, const Arg2& arg2,
+                                           const Arg3& arg3, const Arg4& arg4) {
+    if (arena == NULL) {
+      return new T(arg1, arg2, arg3, arg4);
+    } else {
+      return arena->CreateInternal<T>(SkipDeleteList<T>(static_cast<T*>(0)),
+                                      arg1,
+                                      arg2,
+                                      arg3,
+                                      arg4);
+    }
+  }
+
   // Create an array of object type T on the arena. Type T must have a trivial
   // Create an array of object type T on the arena. Type T must have a trivial
   // constructor, as it will not be invoked when created on the arena.
   // constructor, as it will not be invoked when created on the arena.
   template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
   template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
@@ -202,8 +261,7 @@ class LIBPROTOBUF_EXPORT Arena {
     if (arena == NULL) {
     if (arena == NULL) {
       return new T[num_elements];
       return new T[num_elements];
     } else {
     } else {
-      return static_cast<T*>(
-          arena->AllocateAligned(num_elements * sizeof(T)));
+      return arena->CreateInternalRawArray<T>(num_elements);
     }
     }
   }
   }
 
 
@@ -211,6 +269,8 @@ class LIBPROTOBUF_EXPORT Arena {
   // of the underlying blocks. The total space used may not include the new
   // of the underlying blocks. The total space used may not include the new
   // blocks that are allocated by this arena from other threads concurrently
   // blocks that are allocated by this arena from other threads concurrently
   // with the call to this method.
   // with the call to this method.
+  uint64 SpaceAllocated() const GOOGLE_ATTRIBUTE_NOINLINE;
+  // As above, but does not include any free space in underlying blocks.
   uint64 SpaceUsed() const GOOGLE_ATTRIBUTE_NOINLINE;
   uint64 SpaceUsed() const GOOGLE_ATTRIBUTE_NOINLINE;
 
 
   // Frees all storage allocated by this arena after calling destructors
   // Frees all storage allocated by this arena after calling destructors
@@ -253,7 +313,7 @@ class LIBPROTOBUF_EXPORT Arena {
   // latter is a virtual call, while this method is a templated call that
   // latter is a virtual call, while this method is a templated call that
   // resolves at compile-time.
   // resolves at compile-time.
   template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
   template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
-  static inline ::google::protobuf::Arena* GetArena(T* value) {
+  static inline ::google::protobuf::Arena* GetArena(const T* value) {
     return GetArenaInternal(value, static_cast<T*>(0));
     return GetArenaInternal(value, static_cast<T*>(0));
   }
   }
 
 
@@ -295,9 +355,6 @@ class LIBPROTOBUF_EXPORT Arena {
     // data follows
     // data follows
   };
   };
 
 
-  void* (*block_alloc)(size_t);  // Allocates a free block of a particular size.
-  void (*block_dealloc)(void*, size_t);  // Deallocates the given block.
-
   template<typename Type> friend class ::google::protobuf::internal::GenericTypeHandler;
   template<typename Type> friend class ::google::protobuf::internal::GenericTypeHandler;
   friend class MockArena;              // For unit-testing.
   friend class MockArena;              // For unit-testing.
   friend class internal::ArenaString;  // For AllocateAligned.
   friend class internal::ArenaString;  // For AllocateAligned.
@@ -317,7 +374,7 @@ class LIBPROTOBUF_EXPORT Arena {
   // wrap them in static functions.
   // wrap them in static functions.
   static ThreadCache& thread_cache();
   static ThreadCache& thread_cache();
 #else
 #else
-  static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_;
+  static __thread ThreadCache thread_cache_;
   static ThreadCache& thread_cache() { return thread_cache_; }
   static ThreadCache& thread_cache() { return thread_cache_; }
 #endif
 #endif
 
 
@@ -354,6 +411,13 @@ class LIBPROTOBUF_EXPORT Arena {
     return Create<T>(arena);
     return Create<T>(arena);
   }
   }
 
 
+  // Just allocate the required size for the given type assuming the
+  // type has a trivial constructor.
+  template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+  inline T* CreateInternalRawArray(uint32 num_elements) {
+    return static_cast<T*>(AllocateAligned(sizeof(T) * num_elements));
+  }
+
   template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
   template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
   inline T* CreateInternal(
   inline T* CreateInternal(
       bool skip_explicit_ownership) {
       bool skip_explicit_ownership) {
@@ -384,12 +448,57 @@ class LIBPROTOBUF_EXPORT Arena {
     return t;
     return t;
   }
   }
 
 
+  template <typename T, typename Arg1, typename Arg2, typename Arg3>
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline T* CreateInternal(bool skip_explicit_ownership,
+                                                   const Arg1& arg1,
+                                                   const Arg2& arg2,
+                                                   const Arg3& arg3) {
+    T* t = new (AllocateAligned(sizeof(T))) T(arg1, arg2, arg3);
+    if (!skip_explicit_ownership) {
+      AddListNode(t, &internal::arena_destruct_object<T>);
+    }
+    return t;
+  }
+
+  template <typename T, typename Arg1, typename Arg2, typename Arg3,
+            typename Arg4>
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline T* CreateInternal(bool skip_explicit_ownership,
+                                                   const Arg1& arg1,
+                                                   const Arg2& arg2,
+                                                   const Arg3& arg3,
+                                                   const Arg4& arg4) {
+    T* t = new (AllocateAligned(sizeof(T))) T(arg1, arg2, arg3, arg4);
+    if (!skip_explicit_ownership) {
+      AddListNode(t, &internal::arena_destruct_object<T>);
+    }
+    return t;
+  }
+
   template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
   template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
   inline T* CreateMessageInternal(typename T::InternalArenaConstructable_*) {
   inline T* CreateMessageInternal(typename T::InternalArenaConstructable_*) {
     return CreateInternal<T, Arena*>(SkipDeleteList<T>(static_cast<T*>(0)),
     return CreateInternal<T, Arena*>(SkipDeleteList<T>(static_cast<T*>(0)),
                                      this);
                                      this);
   }
   }
 
 
+  // CreateInArenaStorage is used to implement map field. Without it,
+  // google::protobuf::Map need to call generated message's protected arena constructor,
+  // which needs to declare google::protobuf::Map as friend of generated message.
+  template <typename T>
+  static void CreateInArenaStorage(T* ptr, Arena* arena) {
+    CreateInArenaStorageInternal(ptr, arena, is_arena_constructable<T>::value);
+  }
+  template <typename T>
+  static void CreateInArenaStorageInternal(
+      T* ptr, Arena* arena, google::protobuf::internal::true_type) {
+    new (ptr) T(arena);
+  }
+
+  template <typename T>
+  static void CreateInArenaStorageInternal(
+      T* ptr, Arena* arena, google::protobuf::internal::false_type) {
+    new (ptr) T;
+  }
+
   // These implement Own(), which registers an object for deletion (destructor
   // These implement Own(), which registers an object for deletion (destructor
   // call and operator delete()). The second parameter has type 'true_type' if T
   // call and operator delete()). The second parameter has type 'true_type' if T
   // is a subtype of ::google::protobuf::Message and 'false_type' otherwise. Collapsing
   // is a subtype of ::google::protobuf::Message and 'false_type' otherwise. Collapsing
@@ -412,20 +521,20 @@ class LIBPROTOBUF_EXPORT Arena {
   // InternalArenaConstructable_ tags can be associated with an arena, and such
   // InternalArenaConstructable_ tags can be associated with an arena, and such
   // objects must implement a GetArenaNoVirtual() method.
   // objects must implement a GetArenaNoVirtual() method.
   template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
   template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
-  static inline ::google::protobuf::Arena* GetArenaInternal(T* value,
+  static inline ::google::protobuf::Arena* GetArenaInternal(const T* value,
       typename T::InternalArenaConstructable_*) {
       typename T::InternalArenaConstructable_*) {
     return value->GetArenaNoVirtual();
     return value->GetArenaNoVirtual();
   }
   }
 
 
   template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
   template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
-  static inline ::google::protobuf::Arena* GetArenaInternal(T* value, ...) {
+  static inline ::google::protobuf::Arena* GetArenaInternal(const T* value, ...) {
     return NULL;
     return NULL;
   }
   }
 
 
 
 
   void* AllocateAligned(size_t size);
   void* AllocateAligned(size_t size);
 
 
-  void Init(const ArenaOptions& options);
+  void Init();
 
 
   // Free all blocks and return the total space used which is the sums of sizes
   // Free all blocks and return the total space used which is the sums of sizes
   // of the all the allocated blocks.
   // of the all the allocated blocks.
@@ -446,8 +555,6 @@ class LIBPROTOBUF_EXPORT Arena {
   }
   }
 
 
   int64 lifecycle_id_;  // Unique for each arena. Changes on Reset().
   int64 lifecycle_id_;  // Unique for each arena. Changes on Reset().
-  size_t start_block_size_;  // Starting block size of the arena.
-  size_t max_block_size_;    // Max block size of the arena.
 
 
   google::protobuf::internal::AtomicWord blocks_;  // Head of linked list of all allocated blocks
   google::protobuf::internal::AtomicWord blocks_;  // Head of linked list of all allocated blocks
   google::protobuf::internal::AtomicWord hint_;    // Fast thread-local block access
   google::protobuf::internal::AtomicWord hint_;    // Fast thread-local block access
@@ -472,6 +579,15 @@ class LIBPROTOBUF_EXPORT Arena {
   Block* NewBlock(void* me, Block* my_last_block, size_t n,
   Block* NewBlock(void* me, Block* my_last_block, size_t n,
                   size_t start_block_size, size_t max_block_size);
                   size_t start_block_size, size_t max_block_size);
   static void* AllocFromBlock(Block* b, size_t n);
   static void* AllocFromBlock(Block* b, size_t n);
+  template <typename Key, typename T>
+  friend class Map;
+
+  // The arena may save a cookie it receives from the external on_init hook
+  // and then use it when calling the on_reset and on_destruction hooks.
+  void* hooks_cookie_;
+
+  ArenaOptions options_;
+
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Arena);
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Arena);
 };
 };
 
 

+ 49 - 0
src/google/protobuf/arena_test_util.cc

@@ -0,0 +1,49 @@
+// 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.
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arena_test_util.h>
+
+
+#define EXPECT_EQ GOOGLE_CHECK_EQ
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+NoHeapChecker::~NoHeapChecker() {
+  capture_alloc.Unhook();
+  EXPECT_EQ(0, capture_alloc.alloc_count());
+  EXPECT_EQ(0, capture_alloc.free_count());
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google

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

@@ -0,0 +1,59 @@
+// 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_ARENA_TEST_UTIL_H__
+#define GOOGLE_PROTOBUF_ARENA_TEST_UTIL_H__
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+class NoHeapChecker {
+ public:
+  NoHeapChecker() {
+    capture_alloc.Hook();
+  }
+  ~NoHeapChecker();
+ private:
+  class NewDeleteCapture {
+   public:
+    // TOOD(xiaofeng): Implement this for opensource protobuf.
+    void Hook() {}
+    void Unhook() {}
+    int alloc_count() { return 0; }
+    int free_count() { return 0; }
+  } capture_alloc;
+};
+
+}  // namespace internal
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_ARENA_TEST_UTIL_H__

+ 196 - 31
src/google/protobuf/arena_unittest.cc

@@ -30,6 +30,8 @@
 
 
 #include <google/protobuf/arena.h>
 #include <google/protobuf/arena.h>
 
 
+#include <stdint.h>
+
 #include <algorithm>
 #include <algorithm>
 #include <cstring>
 #include <cstring>
 #include <memory>
 #include <memory>
@@ -40,6 +42,7 @@
 #include <vector>
 #include <vector>
 
 
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arena_test_util.h>
 #include <google/protobuf/test_util.h>
 #include <google/protobuf/test_util.h>
 #include <google/protobuf/unittest.pb.h>
 #include <google/protobuf/unittest.pb.h>
 #include <google/protobuf/unittest_arena.pb.h>
 #include <google/protobuf/unittest_arena.pb.h>
@@ -91,6 +94,37 @@ class SimpleDataType {
  private:
  private:
   Notifier* notifier_;
   Notifier* notifier_;
 };
 };
+
+// A simple class that does not allow copying and so cannot be used as a
+// parameter type without "const &".
+class PleaseDontCopyMe {
+ public:
+  explicit PleaseDontCopyMe(int value) : value_(value) {}
+
+  int value() const { return value_; }
+
+ private:
+  int value_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PleaseDontCopyMe);
+};
+
+// A class that takes four different types as constructor arguments.
+class MustBeConstructedWithOneThroughFour {
+ public:
+  MustBeConstructedWithOneThroughFour(
+      int one, const char* two, const string& three,
+      const PleaseDontCopyMe* four)
+      : one_(one), two_(two), three_(three), four_(four) {}
+
+  int one_;
+  const char* const two_;
+  string three_;
+  const PleaseDontCopyMe* four_;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MustBeConstructedWithOneThroughFour);
+};
+
 }  // namespace
 }  // namespace
 
 
 TEST(ArenaTest, ArenaConstructable) {
 TEST(ArenaTest, ArenaConstructable) {
@@ -122,6 +156,20 @@ TEST(ArenaTest, BasicCreate) {
   EXPECT_EQ(2, notifier.GetCount());
   EXPECT_EQ(2, notifier.GetCount());
 }
 }
 
 
+TEST(ArenaTest, CreateWithManyConstructorArguments) {
+  Arena arena;
+  const string three("3");
+  const PleaseDontCopyMe four(4);
+  const MustBeConstructedWithOneThroughFour* new_object =
+      Arena::Create<MustBeConstructedWithOneThroughFour>(
+          &arena, 1, "2", three, &four);
+  EXPECT_TRUE(new_object != NULL);
+  ASSERT_EQ(1, new_object->one_);
+  ASSERT_STREQ("2", new_object->two_);
+  ASSERT_EQ("3", new_object->three_);
+  ASSERT_EQ(4, new_object->four_->value());
+}
+
 TEST(ArenaTest, InitialBlockTooSmall) {
 TEST(ArenaTest, InitialBlockTooSmall) {
   // Construct a small (64 byte) initial block of memory to be used by the
   // Construct a small (64 byte) initial block of memory to be used by the
   // arena allocator; then, allocate an object which will not fit in the
   // arena allocator; then, allocate an object which will not fit in the
@@ -380,6 +428,7 @@ TEST(ArenaTest, ReleaseFromArenaMessageMakesCopy) {
   delete nested_string;
   delete nested_string;
 }
 }
 
 
+#ifndef GOOGLE_PROTOBUF_NO_RTTI
 TEST(ArenaTest, ReleaseFromArenaMessageUsingReflectionMakesCopy) {
 TEST(ArenaTest, ReleaseFromArenaMessageUsingReflectionMakesCopy) {
   TestAllTypes::NestedMessage* nested_msg = NULL;
   TestAllTypes::NestedMessage* nested_msg = NULL;
   // Note: no string: reflection API only supports releasing submessages.
   // Note: no string: reflection API only supports releasing submessages.
@@ -396,6 +445,7 @@ TEST(ArenaTest, ReleaseFromArenaMessageUsingReflectionMakesCopy) {
   EXPECT_EQ(42, nested_msg->bb());
   EXPECT_EQ(42, nested_msg->bb());
   delete nested_msg;
   delete nested_msg;
 }
 }
+#endif  // !GOOGLE_PROTOBUF_NO_RTTI
 
 
 TEST(ArenaTest, UnsafeArenaReleaseDoesNotMakeCopy) {
 TEST(ArenaTest, UnsafeArenaReleaseDoesNotMakeCopy) {
   Arena arena;
   Arena arena;
@@ -671,6 +721,57 @@ TEST(ArenaTest, UnsafeArenaAddAllocated) {
   }
   }
 }
 }
 
 
+TEST(ArenaTest, UnsafeArenaRelease) {
+  Arena arena;
+  TestAllTypes* message = Arena::CreateMessage<TestAllTypes>(&arena);
+
+  string* s = new string("test string");
+  message->unsafe_arena_set_allocated_optional_string(s);
+  EXPECT_TRUE(message->has_optional_string());
+  EXPECT_EQ("test string", message->optional_string());
+  s = message->unsafe_arena_release_optional_string();
+  EXPECT_FALSE(message->has_optional_string());
+  delete s;
+
+  s = new string("test string");
+  message->unsafe_arena_set_allocated_oneof_string(s);
+  EXPECT_TRUE(message->has_oneof_string());
+  EXPECT_EQ("test string", message->oneof_string());
+  s = message->unsafe_arena_release_oneof_string();
+  EXPECT_FALSE(message->has_oneof_string());
+  delete s;
+}
+
+TEST(ArenaTest, ArenaOneofReflection) {
+  Arena arena;
+  TestAllTypes* message = Arena::CreateMessage<TestAllTypes>(&arena);
+  const Descriptor* desc = message->GetDescriptor();
+  const Reflection* refl = message->GetReflection();
+
+  const FieldDescriptor* string_field = desc->FindFieldByName(
+      "oneof_string");
+  const FieldDescriptor* msg_field = desc->FindFieldByName(
+      "oneof_nested_message");
+  const OneofDescriptor* oneof = desc->FindOneofByName(
+      "oneof_field");
+
+  refl->SetString(message, string_field, "Test value");
+  EXPECT_TRUE(refl->HasOneof(*message, oneof));
+  refl->ClearOneof(message, oneof);
+  EXPECT_FALSE(refl->HasOneof(*message, oneof));
+
+  Message* submsg = refl->MutableMessage(message, msg_field);
+  EXPECT_TRUE(refl->HasOneof(*message, oneof));
+  refl->ClearOneof(message, oneof);
+  EXPECT_FALSE(refl->HasOneof(*message, oneof));
+  refl->MutableMessage(message, msg_field);
+  EXPECT_TRUE(refl->HasOneof(*message, oneof));
+  submsg = refl->ReleaseMessage(message, msg_field);
+  EXPECT_FALSE(refl->HasOneof(*message, oneof));
+  EXPECT_TRUE(submsg->GetArena() == NULL);
+  delete submsg;
+}
+
 namespace {
 namespace {
 void TestSwapRepeatedField(Arena* arena1, Arena* arena2) {
 void TestSwapRepeatedField(Arena* arena1, Arena* arena2) {
   // Test "safe" (copying) semantics for direct Swap() on RepeatedPtrField
   // Test "safe" (copying) semantics for direct Swap() on RepeatedPtrField
@@ -746,27 +847,6 @@ TEST(ArenaTest, ExtensionsOnArena) {
       protobuf_unittest::optional_nested_message_extension)->set_bb(42);
       protobuf_unittest::optional_nested_message_extension)->set_bb(42);
 }
 }
 
 
-class NoHeapChecker {
- public:
-  NoHeapChecker() {
-    capture_alloc.Hook();
-  }
-  ~NoHeapChecker() {
-    capture_alloc.Unhook();
-    EXPECT_EQ(0, capture_alloc.alloc_count());
-    EXPECT_EQ(0, capture_alloc.free_count());
-  }
- private:
-  class NewDeleteCapture {
-   public:
-    // TOOD(xiaofeng): Implement this for opensource protobuf.
-    void Hook() {}
-    void Unhook() {}
-    int alloc_count() { return 0; }
-    int free_count() { return 0; }
-  } capture_alloc;
-};
-
 TEST(ArenaTest, RepeatedFieldOnArena) {
 TEST(ArenaTest, RepeatedFieldOnArena) {
   // Preallocate an initial arena block to avoid mallocs during hooked region.
   // Preallocate an initial arena block to avoid mallocs during hooked region.
   std::vector<char> arena_block(1024 * 1024);
   std::vector<char> arena_block(1024 * 1024);
@@ -776,7 +856,7 @@ TEST(ArenaTest, RepeatedFieldOnArena) {
   Arena arena(options);
   Arena arena(options);
 
 
   {
   {
-    NoHeapChecker no_heap;
+    internal::NoHeapChecker no_heap;
 
 
     // Fill some repeated fields on the arena to test for leaks. Also verify no
     // Fill some repeated fields on the arena to test for leaks. Also verify no
     // memory allocations.
     // memory allocations.
@@ -846,6 +926,7 @@ TEST(ArenaTest, RepeatedFieldOnArena) {
 }
 }
 
 
 
 
+#ifndef GOOGLE_PROTOBUF_NO_RTTI
 TEST(ArenaTest, MutableMessageReflection) {
 TEST(ArenaTest, MutableMessageReflection) {
   Arena arena;
   Arena arena;
   TestAllTypes* message = Arena::CreateMessage<TestAllTypes>(&arena);
   TestAllTypes* message = Arena::CreateMessage<TestAllTypes>(&arena);
@@ -869,6 +950,7 @@ TEST(ArenaTest, MutableMessageReflection) {
   EXPECT_EQ(submessage_expected, submessage);
   EXPECT_EQ(submessage_expected, submessage);
   EXPECT_EQ(&arena, submessage->GetArena());
   EXPECT_EQ(&arena, submessage->GetArena());
 }
 }
+#endif  // !GOOGLE_PROTOBUF_NO_RTTI
 
 
 
 
 namespace {
 namespace {
@@ -911,7 +993,7 @@ TEST(ArenaTest, NoHeapAllocationsTest) {
   arena.Reset();
   arena.Reset();
 }
 }
 
 
-
+#ifndef GOOGLE_PROTOBUF_NO_RTTI
 // Test construction on an arena via generic MessageLite interface. We should be
 // Test construction on an arena via generic MessageLite interface. We should be
 // able to successfully deserialize on the arena without incurring heap
 // able to successfully deserialize on the arena without incurring heap
 // allocations, i.e., everything should still be arena-allocation-aware.
 // allocations, i.e., everything should still be arena-allocation-aware.
@@ -921,8 +1003,7 @@ TEST(ArenaTest, MessageLiteOnArena) {
   options.initial_block = &arena_block[0];
   options.initial_block = &arena_block[0];
   options.initial_block_size = arena_block.size();
   options.initial_block_size = arena_block.size();
   Arena arena(options);
   Arena arena(options);
-  const google::protobuf::MessageLite* prototype =
-      &TestAllTypes::default_instance();
+  const google::protobuf::MessageLite* prototype = &TestAllTypes::default_instance();
 
 
   TestAllTypes initial_message;
   TestAllTypes initial_message;
   FillArenaAwareFields(&initial_message);
   FillArenaAwareFields(&initial_message);
@@ -941,6 +1022,7 @@ TEST(ArenaTest, MessageLiteOnArena) {
 
 
   arena.Reset();
   arena.Reset();
 }
 }
+#endif  // !GOOGLE_PROTOBUF_NO_RTTI
 
 
 
 
 // RepeatedField should support non-POD types, and invoke constructors and
 // RepeatedField should support non-POD types, and invoke constructors and
@@ -962,16 +1044,23 @@ TEST(ArenaTest, RepeatedFieldWithNonPODType) {
   }
   }
 }
 }
 
 
-TEST(ArenaTest, SpaceUsed) {
+// Align n to next multiple of 8
+namespace {
+uint64 Align8(uint64 n) { return (n + 7) & -8; }
+}  // namespace
+
+TEST(ArenaTest, SpaceAllocated_and_Used) {
   ArenaOptions options;
   ArenaOptions options;
   options.start_block_size = 256;
   options.start_block_size = 256;
   options.max_block_size = 8192;
   options.max_block_size = 8192;
   Arena arena_1(options);
   Arena arena_1(options);
+  EXPECT_EQ(0, arena_1.SpaceAllocated());
   EXPECT_EQ(0, arena_1.SpaceUsed());
   EXPECT_EQ(0, arena_1.SpaceUsed());
   EXPECT_EQ(0, arena_1.Reset());
   EXPECT_EQ(0, arena_1.Reset());
   ::google::protobuf::Arena::CreateArray<char>(&arena_1, 320);
   ::google::protobuf::Arena::CreateArray<char>(&arena_1, 320);
   // Arena will allocate slightly more than 320 for the block headers.
   // Arena will allocate slightly more than 320 for the block headers.
-  EXPECT_LE(320, arena_1.SpaceUsed());
+  EXPECT_LE(320, arena_1.SpaceAllocated());
+  EXPECT_EQ(Align8(320), arena_1.SpaceUsed());
   EXPECT_LE(320, arena_1.Reset());
   EXPECT_LE(320, arena_1.Reset());
 
 
   // Test with initial block.
   // Test with initial block.
@@ -979,20 +1068,25 @@ TEST(ArenaTest, SpaceUsed) {
   options.initial_block = &arena_block[0];
   options.initial_block = &arena_block[0];
   options.initial_block_size = arena_block.size();
   options.initial_block_size = arena_block.size();
   Arena arena_2(options);
   Arena arena_2(options);
-  EXPECT_EQ(1024, arena_2.SpaceUsed());
+  EXPECT_EQ(1024, arena_2.SpaceAllocated());
+  EXPECT_EQ(0, arena_2.SpaceUsed());
   EXPECT_EQ(1024, arena_2.Reset());
   EXPECT_EQ(1024, arena_2.Reset());
   ::google::protobuf::Arena::CreateArray<char>(&arena_2, 55);
   ::google::protobuf::Arena::CreateArray<char>(&arena_2, 55);
-  EXPECT_EQ(1024, arena_2.SpaceUsed());
+  EXPECT_EQ(1024, arena_2.SpaceAllocated());
+  EXPECT_EQ(Align8(55), arena_2.SpaceUsed());
   EXPECT_EQ(1024, arena_2.Reset());
   EXPECT_EQ(1024, arena_2.Reset());
 
 
   // Reset options to test doubling policy explicitly.
   // Reset options to test doubling policy explicitly.
   options.initial_block = NULL;
   options.initial_block = NULL;
   options.initial_block_size = 0;
   options.initial_block_size = 0;
   Arena arena_3(options);
   Arena arena_3(options);
+  EXPECT_EQ(0, arena_3.SpaceUsed());
   ::google::protobuf::Arena::CreateArray<char>(&arena_3, 190);
   ::google::protobuf::Arena::CreateArray<char>(&arena_3, 190);
-  EXPECT_EQ(256, arena_3.SpaceUsed());
+  EXPECT_EQ(256, arena_3.SpaceAllocated());
+  EXPECT_EQ(Align8(190), arena_3.SpaceUsed());
   ::google::protobuf::Arena::CreateArray<char>(&arena_3, 70);
   ::google::protobuf::Arena::CreateArray<char>(&arena_3, 70);
-  EXPECT_EQ(256 + 512, arena_3.SpaceUsed());
+  EXPECT_EQ(256 + 512, arena_3.SpaceAllocated());
+  EXPECT_EQ(Align8(190) + Align8(70), arena_3.SpaceUsed());
   EXPECT_EQ(256 + 512, arena_3.Reset());
   EXPECT_EQ(256 + 512, arena_3.Reset());
 }
 }
 
 
@@ -1004,5 +1098,76 @@ TEST(ArenaTest, Alignment) {
   }
   }
 }
 }
 
 
+TEST(ArenaTest, GetArenaShouldReturnTheArenaForArenaAllocatedMessages) {
+  ::google::protobuf::Arena arena;
+  ArenaMessage* message = Arena::CreateMessage<ArenaMessage>(&arena);
+  const ArenaMessage* const_pointer_to_message = message;
+  EXPECT_EQ(&arena, Arena::GetArena(message));
+  EXPECT_EQ(&arena, Arena::GetArena(const_pointer_to_message));
+}
+
+TEST(ArenaTest, GetArenaShouldReturnNullForNonArenaAllocatedMessages) {
+  ArenaMessage message;
+  const ArenaMessage* const_pointer_to_message = &message;
+  EXPECT_EQ(NULL, Arena::GetArena(&message));
+  EXPECT_EQ(NULL, Arena::GetArena(const_pointer_to_message));
+}
+
+// A helper utility class to only contain static hook functions, some
+// counters to be used to verify the counters have been called and a cookie
+// value to be verified.
+class ArenaHooksTestUtil {
+ public:
+  static void* on_init(::google::protobuf::Arena* arena) {
+    ++num_init;
+    int* cookie = new int(kCookieValue);
+    return static_cast<void*>(cookie);
+  }
+
+  static void on_reset(::google::protobuf::Arena* arena, void* cookie,
+                       uint64 space_used) {
+    ++num_reset;
+    int cookie_value = *static_cast<int*>(cookie);
+    EXPECT_EQ(kCookieValue, cookie_value);
+  }
+
+  static void on_destruction(::google::protobuf::Arena* arena, void* cookie,
+                             uint64 space_used) {
+    ++num_destruct;
+    int cookie_value = *static_cast<int*>(cookie);
+    EXPECT_EQ(kCookieValue, cookie_value);
+    delete static_cast<int*>(cookie);
+  }
+
+  static const int kCookieValue = 999;
+  static uint32 num_init;
+  static uint32 num_reset;
+  static uint32 num_destruct;
+};
+uint32 ArenaHooksTestUtil::num_init = 0;
+uint32 ArenaHooksTestUtil::num_reset = 0;
+uint32 ArenaHooksTestUtil::num_destruct = 0;
+const int ArenaHooksTestUtil::kCookieValue;
+
+// Test the hooks are correctly called and that the cookie is passed.
+TEST(ArenaTest, ArenaHooksSanity) {
+  ::google::protobuf::ArenaOptions options;
+  options.on_arena_init = ArenaHooksTestUtil::on_init;
+  options.on_arena_reset = ArenaHooksTestUtil::on_reset;
+  options.on_arena_destruction = ArenaHooksTestUtil::on_destruction;
+
+  // Scope for defining the arena
+  {
+    ::google::protobuf::Arena arena(options);
+    EXPECT_EQ(1, ArenaHooksTestUtil::num_init);
+
+    arena.Reset();
+    arena.Reset();
+    EXPECT_EQ(2, ArenaHooksTestUtil::num_reset);
+  }
+  EXPECT_EQ(3, ArenaHooksTestUtil::num_reset);
+  EXPECT_EQ(1, ArenaHooksTestUtil::num_destruct);
+}
+
 }  // namespace protobuf
 }  // namespace protobuf
 }  // namespace google
 }  // namespace google

+ 112 - 91
src/google/protobuf/compiler/command_line_interface.cc

@@ -152,7 +152,7 @@ bool VerifyDirectoryExists(const string& path) {
   if (path.empty()) return true;
   if (path.empty()) return true;
 
 
   if (access(path.c_str(), F_OK) == -1) {
   if (access(path.c_str(), F_OK) == -1) {
-    cerr << path << ": " << strerror(errno) << endl;
+    std::cerr << path << ": " << strerror(errno) << std::endl;
     return false;
     return false;
   } else {
   } else {
     return true;
     return true;
@@ -171,8 +171,8 @@ bool TryCreateParentDirectory(const string& prefix, const string& filename) {
     path_so_far += parts[i];
     path_so_far += parts[i];
     if (mkdir(path_so_far.c_str(), 0777) != 0) {
     if (mkdir(path_so_far.c_str(), 0777) != 0) {
       if (errno != EEXIST) {
       if (errno != EEXIST) {
-        cerr << filename << ": while trying to create directory "
-             << path_so_far << ": " << strerror(errno) << endl;
+        std::cerr << filename << ": while trying to create directory "
+                  << path_so_far << ": " << strerror(errno) << std::endl;
         return false;
         return false;
       }
       }
     }
     }
@@ -201,9 +201,9 @@ class CommandLineInterface::ErrorPrinter : public MultiFileErrorCollector,
     if (format_ == CommandLineInterface::ERROR_FORMAT_MSVS &&
     if (format_ == CommandLineInterface::ERROR_FORMAT_MSVS &&
         tree_ != NULL &&
         tree_ != NULL &&
         tree_->VirtualFileToDiskFile(filename, &dfile)) {
         tree_->VirtualFileToDiskFile(filename, &dfile)) {
-      cerr << dfile;
+      std::cerr << dfile;
     } else {
     } else {
-      cerr << filename;
+      std::cerr << filename;
     }
     }
 
 
     // Users typically expect 1-based line/column numbers, so we add 1
     // Users typically expect 1-based line/column numbers, so we add 1
@@ -212,15 +212,16 @@ class CommandLineInterface::ErrorPrinter : public MultiFileErrorCollector,
       // Allow for both GCC- and Visual-Studio-compatible output.
       // Allow for both GCC- and Visual-Studio-compatible output.
       switch (format_) {
       switch (format_) {
         case CommandLineInterface::ERROR_FORMAT_GCC:
         case CommandLineInterface::ERROR_FORMAT_GCC:
-          cerr << ":" << (line + 1) << ":" << (column + 1);
+          std::cerr << ":" << (line + 1) << ":" << (column + 1);
           break;
           break;
         case CommandLineInterface::ERROR_FORMAT_MSVS:
         case CommandLineInterface::ERROR_FORMAT_MSVS:
-          cerr << "(" << (line + 1) << ") : error in column=" << (column + 1);
+          std::cerr << "(" << (line + 1)
+                    << ") : error in column=" << (column + 1);
           break;
           break;
       }
       }
     }
     }
 
 
-    cerr << ": " << message << endl;
+    std::cerr << ": " << message << std::endl;
   }
   }
 
 
   // implements io::ErrorCollector -----------------------------------
   // implements io::ErrorCollector -----------------------------------
@@ -345,7 +346,7 @@ bool CommandLineInterface::GeneratorContextImpl::WriteAllToDisk(
 
 
     if (file_descriptor < 0) {
     if (file_descriptor < 0) {
       int error = errno;
       int error = errno;
-      cerr << filename << ": " << strerror(error);
+      std::cerr << filename << ": " << strerror(error);
       return false;
       return false;
     }
     }
 
 
@@ -369,9 +370,9 @@ bool CommandLineInterface::GeneratorContextImpl::WriteAllToDisk(
 
 
         if (write_result < 0) {
         if (write_result < 0) {
           int error = errno;
           int error = errno;
-          cerr << filename << ": write: " << strerror(error);
+          std::cerr << filename << ": write: " << strerror(error);
         } else {
         } else {
-          cerr << filename << ": write() returned zero?" << endl;
+          std::cerr << filename << ": write() returned zero?" << std::endl;
         }
         }
         return false;
         return false;
       }
       }
@@ -382,7 +383,7 @@ bool CommandLineInterface::GeneratorContextImpl::WriteAllToDisk(
 
 
     if (close(file_descriptor) != 0) {
     if (close(file_descriptor) != 0) {
       int error = errno;
       int error = errno;
-      cerr << filename << ": close: " << strerror(error);
+      std::cerr << filename << ": close: " << strerror(error);
       return false;
       return false;
     }
     }
   }
   }
@@ -405,7 +406,7 @@ bool CommandLineInterface::GeneratorContextImpl::WriteAllToZip(
 
 
   if (file_descriptor < 0) {
   if (file_descriptor < 0) {
     int error = errno;
     int error = errno;
-    cerr << filename << ": " << strerror(error);
+    std::cerr << filename << ": " << strerror(error);
     return false;
     return false;
   }
   }
 
 
@@ -421,11 +422,11 @@ bool CommandLineInterface::GeneratorContextImpl::WriteAllToZip(
   zip_writer.WriteDirectory();
   zip_writer.WriteDirectory();
 
 
   if (stream.GetErrno() != 0) {
   if (stream.GetErrno() != 0) {
-    cerr << filename << ": " << strerror(stream.GetErrno()) << endl;
+    std::cerr << filename << ": " << strerror(stream.GetErrno()) << std::endl;
   }
   }
 
 
   if (!stream.Close()) {
   if (!stream.Close()) {
-    cerr << filename << ": " << strerror(stream.GetErrno()) << endl;
+    std::cerr << filename << ": " << strerror(stream.GetErrno()) << std::endl;
   }
   }
 
 
   return true;
   return true;
@@ -490,7 +491,8 @@ CommandLineInterface::MemoryOutputStream::~MemoryOutputStream() {
       if (append_mode_) {
       if (append_mode_) {
         (*map_slot)->append(data_);
         (*map_slot)->append(data_);
       } else {
       } else {
-        cerr << filename_ << ": Tried to write the same file twice." << endl;
+        std::cerr << filename_ << ": Tried to write the same file twice."
+                  << std::endl;
         directory_->had_error_ = true;
         directory_->had_error_ = true;
       }
       }
       return;
       return;
@@ -508,8 +510,9 @@ CommandLineInterface::MemoryOutputStream::~MemoryOutputStream() {
 
 
     // Find the file we are going to insert into.
     // Find the file we are going to insert into.
     if (*map_slot == NULL) {
     if (*map_slot == NULL) {
-      cerr << filename_ << ": Tried to insert into file that doesn't exist."
-           << endl;
+      std::cerr << filename_
+                << ": Tried to insert into file that doesn't exist."
+                << std::endl;
       directory_->had_error_ = true;
       directory_->had_error_ = true;
       return;
       return;
     }
     }
@@ -521,8 +524,8 @@ CommandLineInterface::MemoryOutputStream::~MemoryOutputStream() {
     string::size_type pos = target->find(magic_string);
     string::size_type pos = target->find(magic_string);
 
 
     if (pos == string::npos) {
     if (pos == string::npos) {
-      cerr << filename_ << ": insertion point \"" << insertion_point_
-           << "\" not found." << endl;
+      std::cerr << filename_ << ": insertion point \"" << insertion_point_
+                << "\" not found." << std::endl;
       directory_->had_error_ = true;
       directory_->had_error_ = true;
       return;
       return;
     }
     }
@@ -793,27 +796,31 @@ bool CommandLineInterface::MakeInputsBeProtoPathRelative(
         input_files_[i] = virtual_file;
         input_files_[i] = virtual_file;
         break;
         break;
       case DiskSourceTree::SHADOWED:
       case DiskSourceTree::SHADOWED:
-        cerr << input_files_[i] << ": Input is shadowed in the --proto_path "
-                "by \"" << shadowing_disk_file << "\".  Either use the latter "
-                "file as your input or reorder the --proto_path so that the "
-                "former file's location comes first." << endl;
+        std::cerr << input_files_[i]
+                  << ": Input is shadowed in the --proto_path by \""
+                  << shadowing_disk_file
+                  << "\".  Either use the latter file as your input or reorder "
+                     "the --proto_path so that the former file's location "
+                     "comes first." << std::endl;
         return false;
         return false;
       case DiskSourceTree::CANNOT_OPEN:
       case DiskSourceTree::CANNOT_OPEN:
-        cerr << input_files_[i] << ": " << strerror(errno) << endl;
+        std::cerr << input_files_[i] << ": " << strerror(errno) << std::endl;
         return false;
         return false;
       case DiskSourceTree::NO_MAPPING:
       case DiskSourceTree::NO_MAPPING:
         // First check if the file exists at all.
         // First check if the file exists at all.
         if (access(input_files_[i].c_str(), F_OK) < 0) {
         if (access(input_files_[i].c_str(), F_OK) < 0) {
           // File does not even exist.
           // File does not even exist.
-          cerr << input_files_[i] << ": " << strerror(ENOENT) << endl;
+          std::cerr << input_files_[i] << ": " << strerror(ENOENT) << std::endl;
         } else {
         } else {
-          cerr << input_files_[i] << ": File does not reside within any path "
-                  "specified using --proto_path (or -I).  You must specify a "
-                  "--proto_path which encompasses this file.  Note that the "
-                  "proto_path must be an exact prefix of the .proto file "
-                  "names -- protoc is too dumb to figure out when two paths "
-                  "(e.g. absolute and relative) are equivalent (it's harder "
-                  "than you think)." << endl;
+          std::cerr
+              << input_files_[i]
+              << ": File does not reside within any path "
+                 "specified using --proto_path (or -I).  You must specify a "
+                 "--proto_path which encompasses this file.  Note that the "
+                 "proto_path must be an exact prefix of the .proto file "
+                 "names -- protoc is too dumb to figure out when two paths "
+                 "(e.g. absolute and relative) are equivalent (it's harder "
+                 "than you think)." << std::endl;
         }
         }
         return false;
         return false;
     }
     }
@@ -833,9 +840,10 @@ CommandLineInterface::ParseArguments(int argc, const char* const argv[]) {
     if (ParseArgument(argv[i], &name, &value)) {
     if (ParseArgument(argv[i], &name, &value)) {
       // Returned true => Use the next argument as the flag value.
       // Returned true => Use the next argument as the flag value.
       if (i + 1 == argc || argv[i+1][0] == '-') {
       if (i + 1 == argc || argv[i+1][0] == '-') {
-        cerr << "Missing value for flag: " << name << endl;
+        std::cerr << "Missing value for flag: " << name << std::endl;
         if (name == "--decode") {
         if (name == "--decode") {
-          cerr << "To decode an unknown message, use --decode_raw." << endl;
+          std::cerr << "To decode an unknown message, use --decode_raw."
+                    << std::endl;
         }
         }
         return PARSE_ARGUMENT_FAIL;
         return PARSE_ARGUMENT_FAIL;
       } else {
       } else {
@@ -860,24 +868,25 @@ CommandLineInterface::ParseArguments(int argc, const char* const argv[]) {
   // Check some errror cases.
   // Check some errror cases.
   bool decoding_raw = (mode_ == MODE_DECODE) && codec_type_.empty();
   bool decoding_raw = (mode_ == MODE_DECODE) && codec_type_.empty();
   if (decoding_raw && !input_files_.empty()) {
   if (decoding_raw && !input_files_.empty()) {
-    cerr << "When using --decode_raw, no input files should be given." << endl;
+    std::cerr << "When using --decode_raw, no input files should be given."
+              << std::endl;
     return PARSE_ARGUMENT_FAIL;
     return PARSE_ARGUMENT_FAIL;
   } else if (!decoding_raw && input_files_.empty()) {
   } else if (!decoding_raw && input_files_.empty()) {
-    cerr << "Missing input file." << endl;
+    std::cerr << "Missing input file." << std::endl;
     return PARSE_ARGUMENT_FAIL;
     return PARSE_ARGUMENT_FAIL;
   }
   }
   if (mode_ == MODE_COMPILE && output_directives_.empty() &&
   if (mode_ == MODE_COMPILE && output_directives_.empty() &&
       descriptor_set_name_.empty()) {
       descriptor_set_name_.empty()) {
-    cerr << "Missing output directives." << endl;
+    std::cerr << "Missing output directives." << std::endl;
     return PARSE_ARGUMENT_FAIL;
     return PARSE_ARGUMENT_FAIL;
   }
   }
   if (imports_in_descriptor_set_ && descriptor_set_name_.empty()) {
   if (imports_in_descriptor_set_ && descriptor_set_name_.empty()) {
-    cerr << "--include_imports only makes sense when combined with "
-            "--descriptor_set_out." << endl;
+    std::cerr << "--include_imports only makes sense when combined with "
+                 "--descriptor_set_out." << std::endl;
   }
   }
   if (source_info_in_descriptor_set_ && descriptor_set_name_.empty()) {
   if (source_info_in_descriptor_set_ && descriptor_set_name_.empty()) {
-    cerr << "--include_source_info only makes sense when combined with "
-            "--descriptor_set_out." << endl;
+    std::cerr << "--include_source_info only makes sense when combined with "
+                 "--descriptor_set_out." << std::endl;
   }
   }
 
 
   return PARSE_ARGUMENT_DONE_AND_CONTINUE;
   return PARSE_ARGUMENT_DONE_AND_CONTINUE;
@@ -950,10 +959,12 @@ CommandLineInterface::InterpretArgument(const string& name,
   if (name.empty()) {
   if (name.empty()) {
     // Not a flag.  Just a filename.
     // Not a flag.  Just a filename.
     if (value.empty()) {
     if (value.empty()) {
-      cerr << "You seem to have passed an empty string as one of the "
-              "arguments to " << executable_name_ << ".  This is actually "
-              "sort of hard to do.  Congrats.  Unfortunately it is not valid "
-              "input so the program is going to die now." << endl;
+      std::cerr
+          << "You seem to have passed an empty string as one of the "
+             "arguments to " << executable_name_
+          << ".  This is actually "
+             "sort of hard to do.  Congrats.  Unfortunately it is not valid "
+             "input so the program is going to die now." << std::endl;
       return PARSE_ARGUMENT_FAIL;
       return PARSE_ARGUMENT_FAIL;
     }
     }
 
 
@@ -980,14 +991,16 @@ CommandLineInterface::InterpretArgument(const string& name,
       }
       }
 
 
       if (disk_path.empty()) {
       if (disk_path.empty()) {
-        cerr << "--proto_path passed empty directory name.  (Use \".\" for "
-                "current directory.)" << endl;
+        std::cerr
+            << "--proto_path passed empty directory name.  (Use \".\" for "
+               "current directory.)" << std::endl;
         return PARSE_ARGUMENT_FAIL;
         return PARSE_ARGUMENT_FAIL;
       }
       }
 
 
       // Make sure disk path exists, warn otherwise.
       // Make sure disk path exists, warn otherwise.
       if (access(disk_path.c_str(), F_OK) < 0) {
       if (access(disk_path.c_str(), F_OK) < 0) {
-        cerr << disk_path << ": warning: directory does not exist." << endl;
+        std::cerr << disk_path << ": warning: directory does not exist."
+                  << std::endl;
       }
       }
 
 
       // Don't use make_pair as the old/default standard library on Solaris
       // Don't use make_pair as the old/default standard library on Solaris
@@ -998,30 +1011,31 @@ CommandLineInterface::InterpretArgument(const string& name,
 
 
   } else if (name == "-o" || name == "--descriptor_set_out") {
   } else if (name == "-o" || name == "--descriptor_set_out") {
     if (!descriptor_set_name_.empty()) {
     if (!descriptor_set_name_.empty()) {
-      cerr << name << " may only be passed once." << endl;
+      std::cerr << name << " may only be passed once." << std::endl;
       return PARSE_ARGUMENT_FAIL;
       return PARSE_ARGUMENT_FAIL;
     }
     }
     if (value.empty()) {
     if (value.empty()) {
-      cerr << name << " requires a non-empty value." << endl;
+      std::cerr << name << " requires a non-empty value." << std::endl;
       return PARSE_ARGUMENT_FAIL;
       return PARSE_ARGUMENT_FAIL;
     }
     }
     if (mode_ != MODE_COMPILE) {
     if (mode_ != MODE_COMPILE) {
-      cerr << "Cannot use --encode or --decode and generate descriptors at the "
-              "same time." << endl;
+      std::cerr
+          << "Cannot use --encode or --decode and generate descriptors at the "
+             "same time." << std::endl;
       return PARSE_ARGUMENT_FAIL;
       return PARSE_ARGUMENT_FAIL;
     }
     }
     descriptor_set_name_ = value;
     descriptor_set_name_ = value;
 
 
   } else if (name == "--include_imports") {
   } else if (name == "--include_imports") {
     if (imports_in_descriptor_set_) {
     if (imports_in_descriptor_set_) {
-      cerr << name << " may only be passed once." << endl;
+      std::cerr << name << " may only be passed once." << std::endl;
       return PARSE_ARGUMENT_FAIL;
       return PARSE_ARGUMENT_FAIL;
     }
     }
     imports_in_descriptor_set_ = true;
     imports_in_descriptor_set_ = true;
 
 
   } else if (name == "--include_source_info") {
   } else if (name == "--include_source_info") {
     if (source_info_in_descriptor_set_) {
     if (source_info_in_descriptor_set_) {
-      cerr << name << " may only be passed once." << endl;
+      std::cerr << name << " may only be passed once." << std::endl;
       return PARSE_ARGUMENT_FAIL;
       return PARSE_ARGUMENT_FAIL;
     }
     }
     source_info_in_descriptor_set_ = true;
     source_info_in_descriptor_set_ = true;
@@ -1032,7 +1046,7 @@ CommandLineInterface::InterpretArgument(const string& name,
 
 
   } else if (name == "--version") {
   } else if (name == "--version") {
     if (!version_info_.empty()) {
     if (!version_info_.empty()) {
-      cout << version_info_ << endl;
+      std::cout << version_info_ << std::endl;
     }
     }
     cout << "libprotoc "
     cout << "libprotoc "
          << protobuf::internal::VersionString(GOOGLE_PROTOBUF_VERSION)
          << protobuf::internal::VersionString(GOOGLE_PROTOBUF_VERSION)
@@ -1045,25 +1059,28 @@ CommandLineInterface::InterpretArgument(const string& name,
   } else if (name == "--encode" || name == "--decode" ||
   } else if (name == "--encode" || name == "--decode" ||
              name == "--decode_raw") {
              name == "--decode_raw") {
     if (mode_ != MODE_COMPILE) {
     if (mode_ != MODE_COMPILE) {
-      cerr << "Only one of --encode and --decode can be specified." << endl;
+      std::cerr << "Only one of --encode and --decode can be specified."
+                << std::endl;
       return PARSE_ARGUMENT_FAIL;
       return PARSE_ARGUMENT_FAIL;
     }
     }
     if (!output_directives_.empty() || !descriptor_set_name_.empty()) {
     if (!output_directives_.empty() || !descriptor_set_name_.empty()) {
-      cerr << "Cannot use " << name
-           << " and generate code or descriptors at the same time." << endl;
+      std::cerr << "Cannot use " << name
+                << " and generate code or descriptors at the same time."
+                << std::endl;
       return PARSE_ARGUMENT_FAIL;
       return PARSE_ARGUMENT_FAIL;
     }
     }
 
 
     mode_ = (name == "--encode") ? MODE_ENCODE : MODE_DECODE;
     mode_ = (name == "--encode") ? MODE_ENCODE : MODE_DECODE;
 
 
     if (value.empty() && name != "--decode_raw") {
     if (value.empty() && name != "--decode_raw") {
-      cerr << "Type name for " << name << " cannot be blank." << endl;
+      std::cerr << "Type name for " << name << " cannot be blank." << std::endl;
       if (name == "--decode") {
       if (name == "--decode") {
-        cerr << "To decode an unknown message, use --decode_raw." << endl;
+        std::cerr << "To decode an unknown message, use --decode_raw."
+                  << std::endl;
       }
       }
       return PARSE_ARGUMENT_FAIL;
       return PARSE_ARGUMENT_FAIL;
     } else if (!value.empty() && name == "--decode_raw") {
     } else if (!value.empty() && name == "--decode_raw") {
-      cerr << "--decode_raw does not take a parameter." << endl;
+      std::cerr << "--decode_raw does not take a parameter." << std::endl;
       return PARSE_ARGUMENT_FAIL;
       return PARSE_ARGUMENT_FAIL;
     }
     }
 
 
@@ -1075,13 +1092,13 @@ CommandLineInterface::InterpretArgument(const string& name,
     } else if (value == "msvs") {
     } else if (value == "msvs") {
       error_format_ = ERROR_FORMAT_MSVS;
       error_format_ = ERROR_FORMAT_MSVS;
     } else {
     } else {
-      cerr << "Unknown error format: " << value << endl;
+      std::cerr << "Unknown error format: " << value << std::endl;
       return PARSE_ARGUMENT_FAIL;
       return PARSE_ARGUMENT_FAIL;
     }
     }
 
 
   } else if (name == "--plugin") {
   } else if (name == "--plugin") {
     if (plugin_prefix_.empty()) {
     if (plugin_prefix_.empty()) {
-      cerr << "This compiler does not support plugins." << endl;
+      std::cerr << "This compiler does not support plugins." << std::endl;
       return PARSE_ARGUMENT_FAIL;
       return PARSE_ARGUMENT_FAIL;
     }
     }
 
 
@@ -1107,13 +1124,15 @@ CommandLineInterface::InterpretArgument(const string& name,
 
 
   } else if (name == "--print_free_field_numbers") {
   } else if (name == "--print_free_field_numbers") {
     if (mode_ != MODE_COMPILE) {
     if (mode_ != MODE_COMPILE) {
-      cerr << "Cannot use " << name << " and use --encode, --decode or print "
-           << "other info at the same time." << endl;
+      std::cerr << "Cannot use " << name
+                << " and use --encode, --decode or print "
+                << "other info at the same time." << std::endl;
       return PARSE_ARGUMENT_FAIL;
       return PARSE_ARGUMENT_FAIL;
     }
     }
     if (!output_directives_.empty() || !descriptor_set_name_.empty()) {
     if (!output_directives_.empty() || !descriptor_set_name_.empty()) {
-      cerr << "Cannot use " << name
-           << " and generate code or descriptors at the same time." << endl;
+      std::cerr << "Cannot use " << name
+                << " and generate code or descriptors at the same time."
+                << std::endl;
       return PARSE_ARGUMENT_FAIL;
       return PARSE_ARGUMENT_FAIL;
     }
     }
     mode_ = MODE_PRINT;
     mode_ = MODE_PRINT;
@@ -1127,7 +1146,7 @@ CommandLineInterface::InterpretArgument(const string& name,
       // Check if it's a generator option flag.
       // Check if it's a generator option flag.
       generator_info = FindOrNull(generators_by_option_name_, name);
       generator_info = FindOrNull(generators_by_option_name_, name);
       if (generator_info == NULL) {
       if (generator_info == NULL) {
-        cerr << "Unknown flag: " << name << endl;
+        std::cerr << "Unknown flag: " << name << std::endl;
         return PARSE_ARGUMENT_FAIL;
         return PARSE_ARGUMENT_FAIL;
       } else {
       } else {
         string* parameters = &generator_parameters_[generator_info->flag_name];
         string* parameters = &generator_parameters_[generator_info->flag_name];
@@ -1139,8 +1158,8 @@ CommandLineInterface::InterpretArgument(const string& name,
     } else {
     } else {
       // It's an output flag.  Add it to the output directives.
       // It's an output flag.  Add it to the output directives.
       if (mode_ != MODE_COMPILE) {
       if (mode_ != MODE_COMPILE) {
-        cerr << "Cannot use --encode, --decode or print .proto info and "
-                "generate code at the same time." << endl;
+        std::cerr << "Cannot use --encode, --decode or print .proto info and "
+                     "generate code at the same time." << std::endl;
         return PARSE_ARGUMENT_FAIL;
         return PARSE_ARGUMENT_FAIL;
       }
       }
 
 
@@ -1172,7 +1191,7 @@ CommandLineInterface::InterpretArgument(const string& name,
 
 
 void CommandLineInterface::PrintHelpText() {
 void CommandLineInterface::PrintHelpText() {
   // Sorry for indentation here; line wrapping would be uglier.
   // Sorry for indentation here; line wrapping would be uglier.
-  cerr <<
+  std::cerr <<
 "Usage: " << executable_name_ << " [OPTION] PROTO_FILES\n"
 "Usage: " << executable_name_ << " [OPTION] PROTO_FILES\n"
 "Parse PROTO_FILES and generate output based on the options given:\n"
 "Parse PROTO_FILES and generate output based on the options given:\n"
 "  -IPATH, --proto_path=PATH   Specify the directory in which to search for\n"
 "  -IPATH, --proto_path=PATH   Specify the directory in which to search for\n"
@@ -1213,9 +1232,9 @@ void CommandLineInterface::PrintHelpText() {
 "                              defined in the given proto files. Groups share\n"
 "                              defined in the given proto files. Groups share\n"
 "                              the same field number space with the parent \n"
 "                              the same field number space with the parent \n"
 "                              message. Extension ranges are counted as \n"
 "                              message. Extension ranges are counted as \n"
-"                              occupied fields numbers."  << endl;
+"                              occupied fields numbers."  << std::endl;
   if (!plugin_prefix_.empty()) {
   if (!plugin_prefix_.empty()) {
-    cerr <<
+    std::cerr <<
 "  --plugin=EXECUTABLE         Specifies a plugin executable to use.\n"
 "  --plugin=EXECUTABLE         Specifies a plugin executable to use.\n"
 "                              Normally, protoc searches the PATH for\n"
 "                              Normally, protoc searches the PATH for\n"
 "                              plugins, but you may specify additional\n"
 "                              plugins, but you may specify additional\n"
@@ -1223,7 +1242,7 @@ void CommandLineInterface::PrintHelpText() {
 "                              Additionally, EXECUTABLE may be of the form\n"
 "                              Additionally, EXECUTABLE may be of the form\n"
 "                              NAME=PATH, in which case the given plugin name\n"
 "                              NAME=PATH, in which case the given plugin name\n"
 "                              is mapped to the given executable even if\n"
 "                              is mapped to the given executable even if\n"
-"                              the executable's own name differs." << endl;
+"                              the executable's own name differs." << std::endl;
   }
   }
 
 
   for (GeneratorMap::iterator iter = generators_by_flag_name_.begin();
   for (GeneratorMap::iterator iter = generators_by_flag_name_.begin();
@@ -1231,9 +1250,9 @@ void CommandLineInterface::PrintHelpText() {
     // FIXME(kenton):  If the text is long enough it will wrap, which is ugly,
     // FIXME(kenton):  If the text is long enough it will wrap, which is ugly,
     //   but fixing this nicely (e.g. splitting on spaces) is probably more
     //   but fixing this nicely (e.g. splitting on spaces) is probably more
     //   trouble than it's worth.
     //   trouble than it's worth.
-    cerr << "  " << iter->first << "=OUT_DIR "
-         << string(19 - iter->first.size(), ' ')  // Spaces for alignment.
-         << iter->second.help_text << endl;
+    std::cerr << "  " << iter->first << "=OUT_DIR "
+              << string(19 - iter->first.size(), ' ')  // Spaces for alignment.
+              << iter->second.help_text << std::endl;
   }
   }
 }
 }
 
 
@@ -1256,7 +1275,7 @@ bool CommandLineInterface::GenerateOutput(
     if (!GeneratePluginOutput(parsed_files, plugin_name,
     if (!GeneratePluginOutput(parsed_files, plugin_name,
                               output_directive.parameter,
                               output_directive.parameter,
                               generator_context, &error)) {
                               generator_context, &error)) {
-      cerr << output_directive.name << ": " << error << endl;
+      std::cerr << output_directive.name << ": " << error << std::endl;
       return false;
       return false;
     }
     }
   } else {
   } else {
@@ -1272,8 +1291,8 @@ bool CommandLineInterface::GenerateOutput(
       if (!output_directive.generator->Generate(parsed_files[i], parameters,
       if (!output_directive.generator->Generate(parsed_files[i], parameters,
                                                 generator_context, &error)) {
                                                 generator_context, &error)) {
         // Generator returned an error.
         // Generator returned an error.
-        cerr << output_directive.name << ": " << parsed_files[i]->name() << ": "
-             << error << endl;
+        std::cerr << output_directive.name << ": " << parsed_files[i]->name()
+                  << ": " << error << std::endl;
         return false;
         return false;
       }
       }
     }
     }
@@ -1365,7 +1384,7 @@ bool CommandLineInterface::EncodeOrDecode(const DescriptorPool* pool) {
   // Look up the type.
   // Look up the type.
   const Descriptor* type = pool->FindMessageTypeByName(codec_type_);
   const Descriptor* type = pool->FindMessageTypeByName(codec_type_);
   if (type == NULL) {
   if (type == NULL) {
-    cerr << "Type not defined: " << codec_type_ << endl;
+    std::cerr << "Type not defined: " << codec_type_ << std::endl;
     return false;
     return false;
   }
   }
 
 
@@ -1391,32 +1410,32 @@ bool CommandLineInterface::EncodeOrDecode(const DescriptorPool* pool) {
     parser.AllowPartialMessage(true);
     parser.AllowPartialMessage(true);
 
 
     if (!parser.Parse(&in, message.get())) {
     if (!parser.Parse(&in, message.get())) {
-      cerr << "Failed to parse input." << endl;
+      std::cerr << "Failed to parse input." << std::endl;
       return false;
       return false;
     }
     }
   } else {
   } else {
     // Input is binary.
     // Input is binary.
     if (!message->ParsePartialFromZeroCopyStream(&in)) {
     if (!message->ParsePartialFromZeroCopyStream(&in)) {
-      cerr << "Failed to parse input." << endl;
+      std::cerr << "Failed to parse input." << std::endl;
       return false;
       return false;
     }
     }
   }
   }
 
 
   if (!message->IsInitialized()) {
   if (!message->IsInitialized()) {
-    cerr << "warning:  Input message is missing required fields:  "
-         << message->InitializationErrorString() << endl;
+    std::cerr << "warning:  Input message is missing required fields:  "
+              << message->InitializationErrorString() << std::endl;
   }
   }
 
 
   if (mode_ == MODE_ENCODE) {
   if (mode_ == MODE_ENCODE) {
     // Output is binary.
     // Output is binary.
     if (!message->SerializePartialToZeroCopyStream(&out)) {
     if (!message->SerializePartialToZeroCopyStream(&out)) {
-      cerr << "output: I/O error." << endl;
+      std::cerr << "output: I/O error." << std::endl;
       return false;
       return false;
     }
     }
   } else {
   } else {
     // Output is text.
     // Output is text.
     if (!TextFormat::Print(*message, &out)) {
     if (!TextFormat::Print(*message, &out)) {
-      cerr << "output: I/O error." << endl;
+      std::cerr << "output: I/O error." << std::endl;
       return false;
       return false;
     }
     }
   }
   }
@@ -1458,12 +1477,14 @@ bool CommandLineInterface::WriteDescriptorSet(
 
 
   io::FileOutputStream out(fd);
   io::FileOutputStream out(fd);
   if (!file_set.SerializeToZeroCopyStream(&out)) {
   if (!file_set.SerializeToZeroCopyStream(&out)) {
-    cerr << descriptor_set_name_ << ": " << strerror(out.GetErrno()) << endl;
+    std::cerr << descriptor_set_name_ << ": " << strerror(out.GetErrno())
+              << std::endl;
     out.Close();
     out.Close();
     return false;
     return false;
   }
   }
   if (!out.Close()) {
   if (!out.Close()) {
-    cerr << descriptor_set_name_ << ": " << strerror(out.GetErrno()) << endl;
+    std::cerr << descriptor_set_name_ << ": " << strerror(out.GetErrno())
+              << std::endl;
     return false;
     return false;
   }
   }
 
 
@@ -1582,7 +1603,7 @@ void FormatFreeFieldNumbers(const string& name,
   if (next_free_number <= FieldDescriptor::kMaxNumber) {
   if (next_free_number <= FieldDescriptor::kMaxNumber) {
     StringAppendF(&output, " %d-INF", next_free_number);
     StringAppendF(&output, " %d-INF", next_free_number);
   }
   }
-  cout << output << endl;
+  std::cout << output << std::endl;
 }
 }
 
 
 }  // namespace
 }  // namespace

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

@@ -67,7 +67,6 @@
 // Disable the whole test when we use tcmalloc for "draconian" heap checks, in
 // Disable the whole test when we use tcmalloc for "draconian" heap checks, in
 // which case tcmalloc will print warnings that fail the plugin tests.
 // which case tcmalloc will print warnings that fail the plugin tests.
 #if !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN
 #if !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN
-
 namespace google {
 namespace google {
 namespace protobuf {
 namespace protobuf {
 namespace compiler {
 namespace compiler {
@@ -1666,6 +1665,6 @@ TEST_F(EncodeDecodeTest, ProtoParseError) {
 
 
 }  // namespace compiler
 }  // namespace compiler
 }  // namespace protobuf
 }  // namespace protobuf
-}  // namespace google
 
 
-#endif // !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN
+#endif  // !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN
+}  // namespace google

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

@@ -98,7 +98,8 @@ class MockGeneratorContext : public GeneratorContext {
                           &actual_contents, true));
                           &actual_contents, true));
     EXPECT_TRUE(actual_contents == *expected_contents)
     EXPECT_TRUE(actual_contents == *expected_contents)
       << physical_filename << " needs to be regenerated.  Please run "
       << physical_filename << " needs to be regenerated.  Please run "
-         "generate_descriptor_proto.sh and add this file "
+         "google/protobuf/compiler/release_compiler.sh and "
+         "generate_descriptor_proto.sh. Then add this file "
          "to your CL.";
          "to your CL.";
   }
   }
 
 

+ 6 - 3
src/google/protobuf/compiler/cpp/cpp_enum.cc

@@ -47,7 +47,7 @@ namespace cpp {
 
 
 namespace {
 namespace {
 // The GOOGLE_ARRAYSIZE constant is the max enum value plus 1. If the max enum value
 // The GOOGLE_ARRAYSIZE constant is the max enum value plus 1. If the max enum value
-// is kint32max, GOOGLE_ARRAYSIZE will overflow. In such cases we should omit the
+// is ::google::protobuf::kint32max, GOOGLE_ARRAYSIZE will overflow. In such cases we should omit the
 // generation of the GOOGLE_ARRAYSIZE constant.
 // generation of the GOOGLE_ARRAYSIZE constant.
 bool ShouldGenerateArraySize(const EnumDescriptor* descriptor) {
 bool ShouldGenerateArraySize(const EnumDescriptor* descriptor) {
   int32 max_value = descriptor->value(0)->number();
   int32 max_value = descriptor->value(0)->number();
@@ -56,7 +56,7 @@ bool ShouldGenerateArraySize(const EnumDescriptor* descriptor) {
       max_value = descriptor->value(i)->number();
       max_value = descriptor->value(i)->number();
     }
     }
   }
   }
-  return max_value != kint32max;
+  return max_value != ::google::protobuf::kint32max;
 }
 }
 }  // namespace
 }  // namespace
 
 
@@ -153,9 +153,12 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) {
 
 
 void EnumGenerator::
 void EnumGenerator::
 GenerateGetEnumDescriptorSpecializations(io::Printer* printer) {
 GenerateGetEnumDescriptorSpecializations(io::Printer* printer) {
+  printer->Print(
+      "template <> struct is_proto_enum< $classname$> : ::google::protobuf::internal::true_type "
+      "{};\n",
+      "classname", ClassName(descriptor_, true));
   if (HasDescriptorMethods(descriptor_->file())) {
   if (HasDescriptorMethods(descriptor_->file())) {
     printer->Print(
     printer->Print(
-      "template <> struct is_proto_enum< $classname$> : ::google::protobuf::internal::true_type {};\n"
       "template <>\n"
       "template <>\n"
       "inline const EnumDescriptor* GetEnumDescriptor< $classname$>() {\n"
       "inline const EnumDescriptor* GetEnumDescriptor< $classname$>() {\n"
       "  return $classname$_descriptor();\n"
       "  return $classname$_descriptor();\n"

+ 73 - 40
src/google/protobuf/compiler/cpp/cpp_enum_field.cc

@@ -76,23 +76,26 @@ GeneratePrivateMembers(io::Printer* printer) const {
 void EnumFieldGenerator::
 void EnumFieldGenerator::
 GenerateAccessorDeclarations(io::Printer* printer) const {
 GenerateAccessorDeclarations(io::Printer* printer) const {
   printer->Print(variables_,
   printer->Print(variables_,
-    "inline $type$ $name$() const$deprecation$;\n"
-    "inline void set_$name$($type$ value)$deprecation$;\n");
+    "$type$ $name$() const$deprecation$;\n"
+    "void set_$name$($type$ value)$deprecation$;\n");
 }
 }
 
 
 void EnumFieldGenerator::
 void EnumFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
-  printer->Print(variables_,
-    "inline $type$ $classname$::$name$() const {\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                  bool is_inline) const {
+  map<string, string> variables(variables_);
+  variables["inline"] = is_inline ? "inline" : "";
+  printer->Print(variables,
+    "$inline$ $type$ $classname$::$name$() const {\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  return static_cast< $type$ >($name$_);\n"
     "  return static_cast< $type$ >($name$_);\n"
     "}\n"
     "}\n"
-    "inline void $classname$::set_$name$($type$ value) {\n");
+    "$inline$ void $classname$::set_$name$($type$ value) {\n");
   if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
   if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
-    printer->Print(variables_,
+    printer->Print(variables,
     "  assert($type$_IsValid(value));\n");
     "  assert($type$_IsValid(value));\n");
   }
   }
-  printer->Print(variables_,
+  printer->Print(variables,
     "  $set_hasbit$\n"
     "  $set_hasbit$\n"
     "  $name$_ = value;\n"
     "  $name$_ = value;\n"
     "  // @@protoc_insertion_point(field_set:$full_name$)\n"
     "  // @@protoc_insertion_point(field_set:$full_name$)\n"
@@ -181,21 +184,24 @@ EnumOneofFieldGenerator(const FieldDescriptor* descriptor,
 EnumOneofFieldGenerator::~EnumOneofFieldGenerator() {}
 EnumOneofFieldGenerator::~EnumOneofFieldGenerator() {}
 
 
 void EnumOneofFieldGenerator::
 void EnumOneofFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
-  printer->Print(variables_,
-    "inline $type$ $classname$::$name$() const {\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                  bool is_inline) const {
+  map<string, string> variables(variables_);
+  variables["inline"] = is_inline ? "inline" : "";
+  printer->Print(variables,
+    "$inline$ $type$ $classname$::$name$() const {\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  if (has_$name$()) {\n"
     "  if (has_$name$()) {\n"
     "    return static_cast< $type$ >($oneof_prefix$$name$_);\n"
     "    return static_cast< $type$ >($oneof_prefix$$name$_);\n"
     "  }\n"
     "  }\n"
     "  return static_cast< $type$ >($default$);\n"
     "  return static_cast< $type$ >($default$);\n"
     "}\n"
     "}\n"
-    "inline void $classname$::set_$name$($type$ value) {\n");
+    "$inline$ void $classname$::set_$name$($type$ value) {\n");
   if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
   if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
-    printer->Print(variables_,
+    printer->Print(variables,
     "  assert($type$_IsValid(value));\n");
     "  assert($type$_IsValid(value));\n");
   }
   }
-  printer->Print(variables_,
+  printer->Print(variables,
     "  if (!has_$name$()) {\n"
     "  if (!has_$name$()) {\n"
     "    clear_$oneof_name$();\n"
     "    clear_$oneof_name$();\n"
     "    set_has_$name$();\n"
     "    set_has_$name$();\n"
@@ -246,46 +252,49 @@ GeneratePrivateMembers(io::Printer* printer) const {
 void RepeatedEnumFieldGenerator::
 void RepeatedEnumFieldGenerator::
 GenerateAccessorDeclarations(io::Printer* printer) const {
 GenerateAccessorDeclarations(io::Printer* printer) const {
   printer->Print(variables_,
   printer->Print(variables_,
-    "inline $type$ $name$(int index) const$deprecation$;\n"
-    "inline void set_$name$(int index, $type$ value)$deprecation$;\n"
-    "inline void add_$name$($type$ value)$deprecation$;\n");
+    "$type$ $name$(int index) const$deprecation$;\n"
+    "void set_$name$(int index, $type$ value)$deprecation$;\n"
+    "void add_$name$($type$ value)$deprecation$;\n");
   printer->Print(variables_,
   printer->Print(variables_,
-    "inline const ::google::protobuf::RepeatedField<int>& $name$() const$deprecation$;\n"
-    "inline ::google::protobuf::RepeatedField<int>* mutable_$name$()$deprecation$;\n");
+    "const ::google::protobuf::RepeatedField<int>& $name$() const$deprecation$;\n"
+    "::google::protobuf::RepeatedField<int>* mutable_$name$()$deprecation$;\n");
 }
 }
 
 
 void RepeatedEnumFieldGenerator::
 void RepeatedEnumFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
-  printer->Print(variables_,
-    "inline $type$ $classname$::$name$(int index) const {\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                  bool is_inline) const {
+  map<string, string> variables(variables_);
+  variables["inline"] = is_inline ? "inline" : "";
+  printer->Print(variables,
+    "$inline$ $type$ $classname$::$name$(int index) const {\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  return static_cast< $type$ >($name$_.Get(index));\n"
     "  return static_cast< $type$ >($name$_.Get(index));\n"
     "}\n"
     "}\n"
-    "inline void $classname$::set_$name$(int index, $type$ value) {\n");
+    "$inline$ void $classname$::set_$name$(int index, $type$ value) {\n");
   if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
   if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
-    printer->Print(variables_,
+    printer->Print(variables,
     "  assert($type$_IsValid(value));\n");
     "  assert($type$_IsValid(value));\n");
   }
   }
-  printer->Print(variables_,
+  printer->Print(variables,
     "  $name$_.Set(index, value);\n"
     "  $name$_.Set(index, value);\n"
     "  // @@protoc_insertion_point(field_set:$full_name$)\n"
     "  // @@protoc_insertion_point(field_set:$full_name$)\n"
     "}\n"
     "}\n"
-    "inline void $classname$::add_$name$($type$ value) {\n");
+    "$inline$ void $classname$::add_$name$($type$ value) {\n");
   if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
   if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
-    printer->Print(variables_,
+    printer->Print(variables,
     "  assert($type$_IsValid(value));\n");
     "  assert($type$_IsValid(value));\n");
   }
   }
-  printer->Print(variables_,
+  printer->Print(variables,
     "  $name$_.Add(value);\n"
     "  $name$_.Add(value);\n"
     "  // @@protoc_insertion_point(field_add:$full_name$)\n"
     "  // @@protoc_insertion_point(field_add:$full_name$)\n"
     "}\n");
     "}\n");
-  printer->Print(variables_,
-    "inline const ::google::protobuf::RepeatedField<int>&\n"
+  printer->Print(variables,
+    "$inline$ const ::google::protobuf::RepeatedField<int>&\n"
     "$classname$::$name$() const {\n"
     "$classname$::$name$() const {\n"
     "  // @@protoc_insertion_point(field_list:$full_name$)\n"
     "  // @@protoc_insertion_point(field_list:$full_name$)\n"
     "  return $name$_;\n"
     "  return $name$_;\n"
     "}\n"
     "}\n"
-    "inline ::google::protobuf::RepeatedField<int>*\n"
+    "$inline$ ::google::protobuf::RepeatedField<int>*\n"
     "$classname$::mutable_$name$() {\n"
     "$classname$::mutable_$name$() {\n"
     "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
     "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
     "  return &$name$_;\n"
     "  return &$name$_;\n"
@@ -344,20 +353,34 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
 void RepeatedEnumFieldGenerator::
 void RepeatedEnumFieldGenerator::
 GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
 GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
   if (!descriptor_->options().packed()) {
   if (!descriptor_->options().packed()) {
-    // We use a non-inlined implementation in this case, since this path will
-    // rarely be executed.
-    printer->Print(variables_,
-      "DO_((::google::protobuf::internal::WireFormatLite::ReadPackedEnumNoInline(\n"
-      "       input,\n");
+      // This path is rarely executed, so we use a non-inlined implementation.
     if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
     if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
       printer->Print(variables_,
       printer->Print(variables_,
-      "       NULL,\n");
+        "DO_((::google::protobuf::internal::"
+                    "WireFormatLite::ReadPackedEnumPreserveUnknowns(\n"
+        "       input,\n"
+        "       $number$,\n"
+        "       NULL,\n"
+        "       NULL,\n"
+        "       this->mutable_$name$())));\n");
+    } else if (UseUnknownFieldSet(descriptor_->file())) {
+      printer->Print(variables_,
+        "DO_((::google::protobuf::internal::WireFormat::ReadPackedEnumPreserveUnknowns(\n"
+        "       input,\n"
+        "       $number$,\n"
+        "       $type$_IsValid,\n"
+        "       mutable_unknown_fields(),\n"
+        "       this->mutable_$name$())));\n");
     } else {
     } else {
       printer->Print(variables_,
       printer->Print(variables_,
-      "       &$type$_IsValid,\n");
+        "DO_((::google::protobuf::internal::"
+                     "WireFormatLite::ReadPackedEnumPreserveUnknowns(\n"
+        "       input,\n"
+        "       $number$,\n"
+        "       $type$_IsValid,\n"
+        "       &unknown_fields_stream,\n"
+        "       this->mutable_$name$())));\n");
     }
     }
-    printer->Print(variables_,
-      "       this->mutable_$name$())));\n");
   } else {
   } else {
     printer->Print(variables_,
     printer->Print(variables_,
       "::google::protobuf::uint32 length;\n"
       "::google::protobuf::uint32 length;\n"
@@ -376,6 +399,16 @@ GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
       printer->Print(variables_,
       printer->Print(variables_,
       "  if ($type$_IsValid(value)) {\n"
       "  if ($type$_IsValid(value)) {\n"
       "    add_$name$(static_cast< $type$ >(value));\n"
       "    add_$name$(static_cast< $type$ >(value));\n"
+      "  } else {\n");
+      if (UseUnknownFieldSet(descriptor_->file())) {
+        printer->Print(variables_,
+        "    mutable_unknown_fields()->AddVarint($number$, value);\n");
+      } else {
+        printer->Print(variables_,
+        "    unknown_fields_stream.WriteVarint32(tag);\n"
+        "    unknown_fields_stream.WriteVarint32(value);\n");
+      }
+      printer->Print(
       "  }\n");
       "  }\n");
     }
     }
     printer->Print(variables_,
     printer->Print(variables_,

+ 6 - 3
src/google/protobuf/compiler/cpp/cpp_enum_field.h

@@ -53,7 +53,8 @@ class EnumFieldGenerator : public FieldGenerator {
   // implements FieldGenerator ---------------------------------------
   // implements FieldGenerator ---------------------------------------
   void GeneratePrivateMembers(io::Printer* printer) const;
   void GeneratePrivateMembers(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
-  void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                         bool is_inline) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
@@ -78,7 +79,8 @@ class EnumOneofFieldGenerator : public EnumFieldGenerator {
   ~EnumOneofFieldGenerator();
   ~EnumOneofFieldGenerator();
 
 
   // implements FieldGenerator ---------------------------------------
   // implements FieldGenerator ---------------------------------------
-  void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                         bool is_inline) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
   void GenerateConstructorCode(io::Printer* printer) const;
   void GenerateConstructorCode(io::Printer* printer) const;
@@ -96,7 +98,8 @@ class RepeatedEnumFieldGenerator : public FieldGenerator {
   // implements FieldGenerator ---------------------------------------
   // implements FieldGenerator ---------------------------------------
   void GeneratePrivateMembers(io::Printer* printer) const;
   void GeneratePrivateMembers(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
-  void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                         bool is_inline) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;

+ 1 - 1
src/google/protobuf/compiler/cpp/cpp_field.h

@@ -89,7 +89,7 @@ class FieldGenerator {
   // Generate inline definitions of accessor functions for this field.
   // Generate inline definitions of accessor functions for this field.
   // These are placed inside the header after all class definitions.
   // These are placed inside the header after all class definitions.
   virtual void GenerateInlineAccessorDefinitions(
   virtual void GenerateInlineAccessorDefinitions(
-    io::Printer* printer) const = 0;
+    io::Printer* printer, bool is_inline) const = 0;
 
 
   // Generate definitions of accessors that aren't inlined.  These are
   // Generate definitions of accessors that aren't inlined.  These are
   // placed somewhere in the .cc file.
   // placed somewhere in the .cc file.

+ 32 - 10
src/google/protobuf/compiler/cpp/cpp_file.cc

@@ -136,8 +136,11 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
   printer->Print(
   printer->Print(
     "#include <google/protobuf/arena.h>\n"
     "#include <google/protobuf/arena.h>\n"
     "#include <google/protobuf/arenastring.h>\n"
     "#include <google/protobuf/arenastring.h>\n"
-    "#include <google/protobuf/generated_message_util.h>\n"
-    "#include <google/protobuf/metadata.h>\n");
+    "#include <google/protobuf/generated_message_util.h>\n");
+  if (UseUnknownFieldSet(file_)) {
+    printer->Print(
+      "#include <google/protobuf/metadata.h>\n");
+  }
   if (file_->message_type_count() > 0) {
   if (file_->message_type_count() > 0) {
     if (HasDescriptorMethods(file_)) {
     if (HasDescriptorMethods(file_)) {
       printer->Print(
       printer->Print(
@@ -152,13 +155,24 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
     "#include <google/protobuf/extension_set.h>\n");
     "#include <google/protobuf/extension_set.h>\n");
   if (HasMapFields(file_)) {
   if (HasMapFields(file_)) {
     printer->Print(
     printer->Print(
-      "#include <google/protobuf/map.h>\n"
-      "#include <google/protobuf/map_field_inl.h>\n");
+        "#include <google/protobuf/map.h>\n");
+    if (HasDescriptorMethods(file_)) {
+      printer->Print(
+          "#include <google/protobuf/map_field_inl.h>\n");
+    } else {
+      printer->Print(
+          "#include <google/protobuf/map_field_lite.h>\n");
+    }
   }
   }
 
 
-  if (HasDescriptorMethods(file_) && HasEnumDefinitions(file_)) {
-    printer->Print(
-      "#include <google/protobuf/generated_enum_reflection.h>\n");
+  if (HasEnumDefinitions(file_)) {
+    if (HasDescriptorMethods(file_)) {
+      printer->Print(
+          "#include <google/protobuf/generated_enum_reflection.h>\n");
+    } else {
+      printer->Print(
+          "#include <google/protobuf/generated_enum_util.h>\n");
+    }
   }
   }
 
 
   if (HasGenericServices(file_)) {
   if (HasGenericServices(file_)) {
@@ -272,15 +286,17 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
   printer->Print(kThickSeparator);
   printer->Print(kThickSeparator);
   printer->Print("\n");
   printer->Print("\n");
 
 
-
+  printer->Print("#if !PROTOBUF_INLINE_NOT_IN_HEADERS\n");
   // Generate class inline methods.
   // Generate class inline methods.
   for (int i = 0; i < file_->message_type_count(); i++) {
   for (int i = 0; i < file_->message_type_count(); i++) {
     if (i > 0) {
     if (i > 0) {
       printer->Print(kThinSeparator);
       printer->Print(kThinSeparator);
       printer->Print("\n");
       printer->Print("\n");
     }
     }
-    message_generators_[i]->GenerateInlineMethods(printer);
+    message_generators_[i]->GenerateInlineMethods(printer,
+                                                  /* is_inline = */ true);
   }
   }
+  printer->Print("#endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS\n");
 
 
   printer->Print(
   printer->Print(
     "\n"
     "\n"
@@ -290,7 +306,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
   GenerateNamespaceClosers(printer);
   GenerateNamespaceClosers(printer);
 
 
   // Emit GetEnumDescriptor specializations into google::protobuf namespace:
   // Emit GetEnumDescriptor specializations into google::protobuf namespace:
-  if (HasDescriptorMethods(file_)) {
+  if (HasEnumDefinitions(file_)) {
     // The SWIG conditional is to avoid a null-pointer dereference
     // The SWIG conditional is to avoid a null-pointer dereference
     // (bug 1984964) in swig-1.3.21 resulting from the following syntax:
     // (bug 1984964) in swig-1.3.21 resulting from the following syntax:
     //   namespace X { void Y<Z::W>(); }
     //   namespace X { void Y<Z::W>(); }
@@ -417,6 +433,12 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
     printer->Print(kThickSeparator);
     printer->Print(kThickSeparator);
     printer->Print("\n");
     printer->Print("\n");
     message_generators_[i]->GenerateClassMethods(printer);
     message_generators_[i]->GenerateClassMethods(printer);
+
+    printer->Print("#if PROTOBUF_INLINE_NOT_IN_HEADERS\n");
+    // Generate class inline methods.
+    message_generators_[i]->GenerateInlineMethods(printer,
+                                                  /* is_inline = */ false);
+    printer->Print("#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS\n");
   }
   }
 
 
   if (HasGenericServices(file_)) {
   if (HasGenericServices(file_)) {

+ 8 - 3
src/google/protobuf/compiler/cpp/cpp_helpers.cc

@@ -352,9 +352,7 @@ string FilenameIdentifier(const string& filename) {
     } else {
     } else {
       // Not alphanumeric.  To avoid any possibility of name conflicts we
       // Not alphanumeric.  To avoid any possibility of name conflicts we
       // use the hex code for the character.
       // use the hex code for the character.
-      result.push_back('_');
-      char buffer[kFastToBufferSize];
-      result.append(FastHexToBuffer(static_cast<uint8>(filename[i]), buffer));
+      StrAppend(&result, "_", ToHex(static_cast<uint8>(filename[i])));
     }
     }
   }
   }
   return result;
   return result;
@@ -508,6 +506,13 @@ bool IsStringOrMessage(const FieldDescriptor* field) {
   return false;
   return false;
 }
 }
 
 
+FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field) {
+  GOOGLE_DCHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_STRING);
+  // Open-source protobuf release only supports STRING ctype.
+  return FieldOptions::STRING;
+
+}
+
 }  // namespace cpp
 }  // namespace cpp
 }  // namespace compiler
 }  // namespace compiler
 }  // namespace protobuf
 }  // namespace protobuf

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

@@ -211,6 +211,10 @@ inline bool IsMapEntryMessage(const Descriptor* descriptor) {
 // Returns true if the field's CPPTYPE is string or message.
 // Returns true if the field's CPPTYPE is string or message.
 bool IsStringOrMessage(const FieldDescriptor* field);
 bool IsStringOrMessage(const FieldDescriptor* field);
 
 
+// For a string field, returns the effective ctype.  If the actual ctype is
+// not supported, returns the default of STRING.
+FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field);
+
 string UnderscoresToCamelCase(const string& input, bool cap_next_letter);
 string UnderscoresToCamelCase(const string& input, bool cap_next_letter);
 
 
 inline bool HasFieldPresence(const FileDescriptor* file) {
 inline bool HasFieldPresence(const FileDescriptor* file) {

+ 117 - 27
src/google/protobuf/compiler/cpp/cpp_map_field.cc

@@ -31,6 +31,7 @@
 #include <google/protobuf/compiler/cpp/cpp_map_field.h>
 #include <google/protobuf/compiler/cpp/cpp_map_field.h>
 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/strutil.h>
 
 
 namespace google {
 namespace google {
@@ -72,14 +73,21 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
       (*variables)["val_cpp"] = PrimitiveTypeName(val->cpp_type());
       (*variables)["val_cpp"] = PrimitiveTypeName(val->cpp_type());
       (*variables)["wrapper"] = "EntryWrapper";
       (*variables)["wrapper"] = "EntryWrapper";
   }
   }
-  (*variables)["key_type"] =
-      "::google::protobuf::FieldDescriptor::TYPE_" +
+  (*variables)["key_wire_type"] =
+      "::google::protobuf::internal::WireFormatLite::TYPE_" +
       ToUpper(DeclaredTypeMethodName(key->type()));
       ToUpper(DeclaredTypeMethodName(key->type()));
-  (*variables)["val_type"] =
-      "::google::protobuf::FieldDescriptor::TYPE_" +
+  (*variables)["val_wire_type"] =
+      "::google::protobuf::internal::WireFormatLite::TYPE_" +
       ToUpper(DeclaredTypeMethodName(val->type()));
       ToUpper(DeclaredTypeMethodName(val->type()));
   (*variables)["map_classname"] = ClassName(descriptor->message_type(), false);
   (*variables)["map_classname"] = ClassName(descriptor->message_type(), false);
-  (*variables)["number"] = Int32ToString(descriptor->number());
+  (*variables)["number"] = SimpleItoa(descriptor->number());
+  (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
+
+  if (HasDescriptorMethods(descriptor->file())) {
+    (*variables)["lite"] = "";
+  } else {
+    (*variables)["lite"] = "Lite";
+  }
 
 
   if (!IsProto3Field(descriptor) &&
   if (!IsProto3Field(descriptor) &&
       val->type() == FieldDescriptor::TYPE_ENUM) {
       val->type() == FieldDescriptor::TYPE_ENUM) {
@@ -102,33 +110,40 @@ MapFieldGenerator::~MapFieldGenerator() {}
 void MapFieldGenerator::
 void MapFieldGenerator::
 GeneratePrivateMembers(io::Printer* printer) const {
 GeneratePrivateMembers(io::Printer* printer) const {
   printer->Print(variables_,
   printer->Print(variables_,
-      "typedef ::google::protobuf::internal::MapEntry<\n"
+      "typedef ::google::protobuf::internal::MapEntryLite<\n"
       "    $key_cpp$, $val_cpp$,\n"
       "    $key_cpp$, $val_cpp$,\n"
-      "    $key_type$,\n"
-      "    $val_type$, $default_enum_value$>\n"
+      "    $key_wire_type$,\n"
+      "    $val_wire_type$,\n"
+      "    $default_enum_value$ >\n"
       "    $map_classname$;\n"
       "    $map_classname$;\n"
-      "::google::protobuf::internal::MapField< $key_cpp$, $val_cpp$,"
-      "$key_type$, $val_type$, $default_enum_value$ > $name$_;\n");
+      "::google::protobuf::internal::MapField$lite$<\n"
+      "    $key_cpp$, $val_cpp$,\n"
+      "    $key_wire_type$,\n"
+      "    $val_wire_type$,\n"
+      "    $default_enum_value$ > $name$_;\n");
 }
 }
 
 
 void MapFieldGenerator::
 void MapFieldGenerator::
 GenerateAccessorDeclarations(io::Printer* printer) const {
 GenerateAccessorDeclarations(io::Printer* printer) const {
   printer->Print(variables_,
   printer->Print(variables_,
-      "inline const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n"
+      "const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n"
       "    $name$() const$deprecation$;\n"
       "    $name$() const$deprecation$;\n"
-      "inline ::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n"
+      "::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n"
       "    mutable_$name$()$deprecation$;\n");
       "    mutable_$name$()$deprecation$;\n");
 }
 }
 
 
 void MapFieldGenerator::
 void MapFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
-  printer->Print(variables_,
-      "inline const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                  bool is_inline) const {
+  map<string, string> variables(variables_);
+  variables["inline"] = is_inline ? "inline" : "";
+  printer->Print(variables,
+      "$inline$ const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n"
       "$classname$::$name$() const {\n"
       "$classname$::$name$() const {\n"
       "  // @@protoc_insertion_point(field_map:$full_name$)\n"
       "  // @@protoc_insertion_point(field_map:$full_name$)\n"
       "  return $name$_.GetMap();\n"
       "  return $name$_.GetMap();\n"
       "}\n"
       "}\n"
-      "inline ::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n"
+      "$inline$ ::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n"
       "$classname$::mutable_$name$() {\n"
       "$classname$::mutable_$name$() {\n"
       "  // @@protoc_insertion_point(field_mutable_map:$full_name$)\n"
       "  // @@protoc_insertion_point(field_mutable_map:$full_name$)\n"
       "  return $name$_.MutableMap();\n"
       "  return $name$_.MutableMap();\n"
@@ -198,11 +213,29 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
         "  if ($val_cpp$_IsValid(*entry->mutable_value())) {\n"
         "  if ($val_cpp$_IsValid(*entry->mutable_value())) {\n"
         "    (*mutable_$name$())[entry->key()] =\n"
         "    (*mutable_$name$())[entry->key()] =\n"
         "        static_cast<$val_cpp$>(*entry->mutable_value());\n"
         "        static_cast<$val_cpp$>(*entry->mutable_value());\n"
-        "  } else {\n"
-        "    mutable_unknown_fields()->AddLengthDelimited($number$, data);\n"
+        "  } else {\n");
+    if (HasDescriptorMethods(descriptor_->file())) {
+      printer->Print(variables_,
+          "    mutable_unknown_fields()"
+          "->AddLengthDelimited($number$, data);\n");
+    } else {
+      printer->Print(variables_,
+          "    unknown_fields_stream.WriteVarint32($tag$);\n"
+          "    unknown_fields_stream.WriteVarint32(data.size());\n"
+          "    unknown_fields_stream.WriteString(data);\n");
+    }
+
+
+    printer->Print(variables_,
         "  }\n"
         "  }\n"
         "}\n");
         "}\n");
   }
   }
+
+  // If entry is allocated by arena, its desctructor should be avoided.
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(variables_,
+        "if (entry->GetArena() != NULL) entry.release();\n");
+  }
 }
 }
 
 
 void MapFieldGenerator::
 void MapFieldGenerator::
@@ -211,12 +244,31 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const {
       "{\n"
       "{\n"
       "  ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
       "  ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
       "  for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
       "  for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
-      "      it = $name$().begin(); it != $name$().end(); ++it) {\n"
+      "      it = $name$().begin(); it != $name$().end(); ++it) {\n");
+
+  // If entry is allocated by arena, its desctructor should be avoided.
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(variables_,
+        "    if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
+        "      entry.release();\n"
+        "    }\n");
+  }
+
+  printer->Print(variables_,
       "    entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
       "    entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
       "    ::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n"
       "    ::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n"
       "        $number$, *entry, output);\n"
       "        $number$, *entry, output);\n"
-      "  }\n"
-      "}\n");
+      "  }\n");
+
+  // If entry is allocated by arena, its desctructor should be avoided.
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(variables_,
+        "  if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
+        "    entry.release();\n"
+        "  }\n");
+  }
+
+  printer->Print("}\n");
 }
 }
 
 
 void MapFieldGenerator::
 void MapFieldGenerator::
@@ -225,13 +277,32 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
       "{\n"
       "{\n"
       "  ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
       "  ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
       "  for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
       "  for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
-      "      it = $name$().begin(); it != $name$().end(); ++it) {\n"
+      "      it = $name$().begin(); it != $name$().end(); ++it) {\n");
+
+  // If entry is allocated by arena, its desctructor should be avoided.
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(variables_,
+        "    if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
+        "      entry.release();\n"
+        "    }\n");
+  }
+
+  printer->Print(variables_,
       "    entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
       "    entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
       "    target = ::google::protobuf::internal::WireFormatLite::\n"
       "    target = ::google::protobuf::internal::WireFormatLite::\n"
       "        Write$declared_type$NoVirtualToArray(\n"
       "        Write$declared_type$NoVirtualToArray(\n"
       "            $number$, *entry, target);\n"
       "            $number$, *entry, target);\n"
-      "  }\n"
-      "}\n");
+      "  }\n");
+
+  // If entry is allocated by arena, its desctructor should be avoided.
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(variables_,
+        "  if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
+        "    entry.release();\n"
+        "  }\n");
+  }
+
+  printer->Print("}\n");
 }
 }
 
 
 void MapFieldGenerator::
 void MapFieldGenerator::
@@ -241,12 +312,31 @@ GenerateByteSize(io::Printer* printer) const {
       "{\n"
       "{\n"
       "  ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
       "  ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
       "  for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
       "  for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
-      "      it = $name$().begin(); it != $name$().end(); ++it) {\n"
+      "      it = $name$().begin(); it != $name$().end(); ++it) {\n");
+
+  // If entry is allocated by arena, its desctructor should be avoided.
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(variables_,
+        "    if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
+        "      entry.release();\n"
+        "    }\n");
+  }
+
+  printer->Print(variables_,
       "    entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
       "    entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
       "    total_size += ::google::protobuf::internal::WireFormatLite::\n"
       "    total_size += ::google::protobuf::internal::WireFormatLite::\n"
       "        $declared_type$SizeNoVirtual(*entry);\n"
       "        $declared_type$SizeNoVirtual(*entry);\n"
-      "  }\n"
-      "}\n");
+      "  }\n");
+
+  // If entry is allocated by arena, its desctructor should be avoided.
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(variables_,
+        "  if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
+        "    entry.release();\n"
+        "  }\n");
+  }
+
+  printer->Print("}\n");
 }
 }
 
 
 }  // namespace cpp
 }  // namespace cpp

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

@@ -50,7 +50,8 @@ class MapFieldGenerator : public FieldGenerator {
   // implements FieldGenerator ---------------------------------------
   // implements FieldGenerator ---------------------------------------
   void GeneratePrivateMembers(io::Printer* printer) const;
   void GeneratePrivateMembers(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
-  void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                         bool is_inline) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;

+ 50 - 45
src/google/protobuf/compiler/cpp/cpp_message.cc

@@ -87,8 +87,8 @@ const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) {
   for (int i = 0; i < descriptor->field_count(); i++) {
   for (int i = 0; i < descriptor->field_count(); i++) {
     fields[i] = descriptor->field(i);
     fields[i] = descriptor->field(i);
   }
   }
-  sort(fields, fields + descriptor->field_count(),
-       FieldOrderingByNumber());
+  std::sort(fields, fields + descriptor->field_count(),
+            FieldOrderingByNumber());
   return fields;
   return fields;
 }
 }
 
 
@@ -253,7 +253,7 @@ void OptimizePadding(vector<const FieldDescriptor*>* fields) {
   // Sort by preferred location to keep fields as close to their original
   // Sort by preferred location to keep fields as close to their original
   // location as possible.  Using stable_sort ensures that the output is
   // location as possible.  Using stable_sort ensures that the output is
   // consistent across runs.
   // consistent across runs.
-  stable_sort(aligned_to_4.begin(), aligned_to_4.end());
+  std::stable_sort(aligned_to_4.begin(), aligned_to_4.end());
 
 
   // Now group fields aligned to 4 bytes (or the 4-field groups created above)
   // Now group fields aligned to 4 bytes (or the 4-field groups created above)
   // into pairs, and treat those like a single field aligned to 8 bytes.
   // into pairs, and treat those like a single field aligned to 8 bytes.
@@ -269,7 +269,7 @@ void OptimizePadding(vector<const FieldDescriptor*>* fields) {
     aligned_to_8.push_back(field_group);
     aligned_to_8.push_back(field_group);
   }
   }
   // Sort by preferred location.
   // Sort by preferred location.
-  stable_sort(aligned_to_8.begin(), aligned_to_8.end());
+  std::stable_sort(aligned_to_8.begin(), aligned_to_8.end());
 
 
   // Now pull out all the FieldDescriptors in order.
   // Now pull out all the FieldDescriptors in order.
   fields->clear();
   fields->clear();
@@ -347,11 +347,11 @@ void CollectMapInfo(const Descriptor* descriptor,
     default:
     default:
       (*variables)["val"] = PrimitiveTypeName(val->cpp_type());
       (*variables)["val"] = PrimitiveTypeName(val->cpp_type());
   }
   }
-  (*variables)["key_type"] =
-      "::google::protobuf::FieldDescriptor::TYPE_" +
+  (*variables)["key_wire_type"] =
+      "::google::protobuf::internal::WireFormatLite::TYPE_" +
       ToUpper(DeclaredTypeMethodName(key->type()));
       ToUpper(DeclaredTypeMethodName(key->type()));
-  (*variables)["val_type"] =
-      "::google::protobuf::FieldDescriptor::TYPE_" +
+  (*variables)["val_wire_type"] =
+      "::google::protobuf::internal::WireFormatLite::TYPE_" +
       ToUpper(DeclaredTypeMethodName(val->type()));
       ToUpper(DeclaredTypeMethodName(val->type()));
 }
 }
 
 
@@ -453,17 +453,17 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) {
     vars["constant_name"] = FieldConstantName(field);
     vars["constant_name"] = FieldConstantName(field);
 
 
     if (field->is_repeated()) {
     if (field->is_repeated()) {
-      printer->Print(vars, "inline int $name$_size() const$deprecation$;\n");
+      printer->Print(vars, "int $name$_size() const$deprecation$;\n");
     } else if (HasHasMethod(field)) {
     } else if (HasHasMethod(field)) {
-      printer->Print(vars, "inline bool has_$name$() const$deprecation$;\n");
+      printer->Print(vars, "bool has_$name$() const$deprecation$;\n");
     } else if (HasPrivateHasMethod(field)) {
     } else if (HasPrivateHasMethod(field)) {
       printer->Print(vars,
       printer->Print(vars,
           "private:\n"
           "private:\n"
-          "inline bool has_$name$() const$deprecation$;\n"
+          "bool has_$name$() const$deprecation$;\n"
           "public:\n");
           "public:\n");
     }
     }
 
 
-    printer->Print(vars, "inline void clear_$name$()$deprecation$;\n");
+    printer->Print(vars, "void clear_$name$()$deprecation$;\n");
     printer->Print(vars, "static const int $constant_name$ = $number$;\n");
     printer->Print(vars, "static const int $constant_name$ = $number$;\n");
 
 
     // Generate type-specific accessor declarations.
     // Generate type-specific accessor declarations.
@@ -482,7 +482,7 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) {
 
 
   for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
   for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
     printer->Print(
     printer->Print(
-        "inline $camel_oneof_name$Case $oneof_name$_case() const;\n",
+        "$camel_oneof_name$Case $oneof_name$_case() const;\n",
         "camel_oneof_name",
         "camel_oneof_name",
         UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true),
         UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true),
         "oneof_name", descriptor_->oneof_decl(i)->name());
         "oneof_name", descriptor_->oneof_decl(i)->name());
@@ -490,7 +490,7 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) {
 }
 }
 
 
 void MessageGenerator::
 void MessageGenerator::
-GenerateFieldAccessorDefinitions(io::Printer* printer) {
+GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline) {
   printer->Print("// $classname$\n\n", "classname", classname_);
   printer->Print("// $classname$\n\n", "classname", classname_);
 
 
   for (int i = 0; i < descriptor_->field_count(); i++) {
   for (int i = 0; i < descriptor_->field_count(); i++) {
@@ -500,11 +500,12 @@ GenerateFieldAccessorDefinitions(io::Printer* printer) {
 
 
     map<string, string> vars;
     map<string, string> vars;
     SetCommonFieldVariables(field, &vars, options_);
     SetCommonFieldVariables(field, &vars, options_);
+    vars["inline"] = is_inline ? "inline" : "";
 
 
     // Generate has_$name$() or $name$_size().
     // Generate has_$name$() or $name$_size().
     if (field->is_repeated()) {
     if (field->is_repeated()) {
       printer->Print(vars,
       printer->Print(vars,
-        "inline int $classname$::$name$_size() const {\n"
+        "$inline$ int $classname$::$name$_size() const {\n"
         "  return $name$_.size();\n"
         "  return $name$_.size();\n"
         "}\n");
         "}\n");
     } else if (field->containing_oneof()) {
     } else if (field->containing_oneof()) {
@@ -518,11 +519,11 @@ GenerateFieldAccessorDefinitions(io::Printer* printer) {
       vars["oneof_name"] = field->containing_oneof()->name();
       vars["oneof_name"] = field->containing_oneof()->name();
       vars["oneof_index"] = SimpleItoa(field->containing_oneof()->index());
       vars["oneof_index"] = SimpleItoa(field->containing_oneof()->index());
       printer->Print(vars,
       printer->Print(vars,
-        "inline bool $classname$::has_$name$() const {\n"
+        "$inline$ bool $classname$::has_$name$() const {\n"
         "  return $oneof_name$_case() == k$field_name$;\n"
         "  return $oneof_name$_case() == k$field_name$;\n"
         "}\n");
         "}\n");
       printer->Print(vars,
       printer->Print(vars,
-        "inline void $classname$::set_has_$name$() {\n"
+        "$inline$ void $classname$::set_has_$name$() {\n"
         "  _oneof_case_[$oneof_index$] = k$field_name$;\n"
         "  _oneof_case_[$oneof_index$] = k$field_name$;\n"
         "}\n");
         "}\n");
     } else {
     } else {
@@ -535,13 +536,13 @@ GenerateFieldAccessorDefinitions(io::Printer* printer) {
         vars["has_mask"] = FastHex32ToBuffer(1u << (field->index() % 32),
         vars["has_mask"] = FastHex32ToBuffer(1u << (field->index() % 32),
                                              buffer);
                                              buffer);
         printer->Print(vars,
         printer->Print(vars,
-          "inline bool $classname$::has_$name$() const {\n"
+          "$inline$ bool $classname$::has_$name$() const {\n"
           "  return (_has_bits_[$has_array_index$] & 0x$has_mask$u) != 0;\n"
           "  return (_has_bits_[$has_array_index$] & 0x$has_mask$u) != 0;\n"
           "}\n"
           "}\n"
-          "inline void $classname$::set_has_$name$() {\n"
+          "$inline$ void $classname$::set_has_$name$() {\n"
           "  _has_bits_[$has_array_index$] |= 0x$has_mask$u;\n"
           "  _has_bits_[$has_array_index$] |= 0x$has_mask$u;\n"
           "}\n"
           "}\n"
-          "inline void $classname$::clear_has_$name$() {\n"
+          "$inline$ void $classname$::clear_has_$name$() {\n"
           "  _has_bits_[$has_array_index$] &= ~0x$has_mask$u;\n"
           "  _has_bits_[$has_array_index$] &= ~0x$has_mask$u;\n"
           "}\n"
           "}\n"
           );
           );
@@ -551,12 +552,12 @@ GenerateFieldAccessorDefinitions(io::Printer* printer) {
           bool is_lazy = false;
           bool is_lazy = false;
           if (is_lazy) {
           if (is_lazy) {
             printer->Print(vars,
             printer->Print(vars,
-              "inline bool $classname$::has_$name$() const {\n"
+              "$inline$ bool $classname$::has_$name$() const {\n"
               "  return !$name$_.IsCleared();\n"
               "  return !$name$_.IsCleared();\n"
               "}\n");
               "}\n");
           } else {
           } else {
             printer->Print(vars,
             printer->Print(vars,
-              "inline bool $classname$::has_$name$() const {\n"
+              "$inline$ bool $classname$::has_$name$() const {\n"
               "  return !_is_default_instance_ && $name$_ != NULL;\n"
               "  return !_is_default_instance_ && $name$_ != NULL;\n"
               "}\n");
               "}\n");
           }
           }
@@ -566,7 +567,7 @@ GenerateFieldAccessorDefinitions(io::Printer* printer) {
 
 
     // Generate clear_$name$()
     // Generate clear_$name$()
     printer->Print(vars,
     printer->Print(vars,
-      "inline void $classname$::clear_$name$() {\n");
+      "$inline$ void $classname$::clear_$name$() {\n");
 
 
     printer->Indent();
     printer->Indent();
 
 
@@ -595,7 +596,8 @@ GenerateFieldAccessorDefinitions(io::Printer* printer) {
     printer->Print("}\n");
     printer->Print("}\n");
 
 
     // Generate type-specific accessors.
     // Generate type-specific accessors.
-    field_generators_.get(field).GenerateInlineAccessorDefinitions(printer);
+    field_generators_.get(field).GenerateInlineAccessorDefinitions(printer,
+                                                                   is_inline);
 
 
     printer->Print("\n");
     printer->Print("\n");
   }
   }
@@ -608,12 +610,13 @@ GenerateFieldAccessorDefinitions(io::Printer* printer) {
     vars["cap_oneof_name"] =
     vars["cap_oneof_name"] =
         ToUpper(descriptor_->oneof_decl(i)->name());
         ToUpper(descriptor_->oneof_decl(i)->name());
     vars["classname"] = classname_;
     vars["classname"] = classname_;
+    vars["inline"] = is_inline ? "inline" : "";
     printer->Print(
     printer->Print(
       vars,
       vars,
-      "inline bool $classname$::has_$oneof_name$() const {\n"
+      "$inline$ bool $classname$::has_$oneof_name$() const {\n"
       "  return $oneof_name$_case() != $cap_oneof_name$_NOT_SET;\n"
       "  return $oneof_name$_case() != $cap_oneof_name$_NOT_SET;\n"
       "}\n"
       "}\n"
-      "inline void $classname$::clear_has_$oneof_name$() {\n"
+      "$inline$ void $classname$::clear_has_$oneof_name$() {\n"
       "  _oneof_case_[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n"
       "  _oneof_case_[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n"
       "}\n");
       "}\n");
   }
   }
@@ -1169,18 +1172,18 @@ GenerateClassDefinition(io::Printer* printer) {
 }
 }
 
 
 void MessageGenerator::
 void MessageGenerator::
-GenerateInlineMethods(io::Printer* printer) {
+GenerateInlineMethods(io::Printer* printer, bool is_inline) {
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
     // map entry message doesn't need inline methods. Since map entry message
     // map entry message doesn't need inline methods. Since map entry message
     // cannot be a top level class, we just need to avoid calling
     // cannot be a top level class, we just need to avoid calling
     // GenerateInlineMethods here.
     // GenerateInlineMethods here.
     if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
     if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
-    nested_generators_[i]->GenerateInlineMethods(printer);
+    nested_generators_[i]->GenerateInlineMethods(printer, is_inline);
     printer->Print(kThinSeparator);
     printer->Print(kThinSeparator);
     printer->Print("\n");
     printer->Print("\n");
   }
   }
 
 
-  GenerateFieldAccessorDefinitions(printer);
+  GenerateFieldAccessorDefinitions(printer, is_inline);
 
 
   // Generate oneof_case() functions.
   // Generate oneof_case() functions.
   for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
   for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
@@ -1190,9 +1193,10 @@ GenerateInlineMethods(io::Printer* printer) {
         descriptor_->oneof_decl(i)->name(), true);
         descriptor_->oneof_decl(i)->name(), true);
     vars["oneof_name"] = descriptor_->oneof_decl(i)->name();
     vars["oneof_name"] = descriptor_->oneof_decl(i)->name();
     vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index());
     vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index());
+    vars["inline"] = is_inline ? "inline " : "";
     printer->Print(
     printer->Print(
         vars,
         vars,
-        "inline $class_name$::$camel_oneof_name$Case $class_name$::"
+        "$inline$$class_name$::$camel_oneof_name$Case $class_name$::"
         "$oneof_name$_case() const {\n"
         "$oneof_name$_case() const {\n"
         "  return $class_name$::$camel_oneof_name$Case("
         "  return $class_name$::$camel_oneof_name$Case("
         "_oneof_case_[$oneof_index$]);\n"
         "_oneof_case_[$oneof_index$]);\n"
@@ -1222,7 +1226,9 @@ GenerateDescriptorDeclarations(io::Printer* printer) {
       for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
       for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
         const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
         const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
         printer->Print("  ");
         printer->Print("  ");
-        if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+        if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ||
+            (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
+             EffectiveStringCType(field) != FieldOptions::STRING)) {
           printer->Print("const ");
           printer->Print("const ");
         }
         }
         field_generators_.get(field).GeneratePrivateMembers(printer);
         field_generators_.get(field).GeneratePrivateMembers(printer);
@@ -1391,8 +1397,8 @@ GenerateTypeRegistrations(io::Printer* printer) {
       "      ::google::protobuf::internal::MapEntry<\n"
       "      ::google::protobuf::internal::MapEntry<\n"
       "          $key$,\n"
       "          $key$,\n"
       "          $val$,\n"
       "          $val$,\n"
-      "          $key_type$,\n"
-      "          $val_type$,\n"
+      "          $key_wire_type$,\n"
+      "          $val_wire_type$,\n"
       "          $default_enum_value$>::CreateDefaultInstance(\n"
       "          $default_enum_value$>::CreateDefaultInstance(\n"
       "              $classname$_descriptor_));\n");
       "              $classname$_descriptor_));\n");
   }
   }
@@ -2034,17 +2040,16 @@ GenerateClear(io::Printer* printer) {
 
 
   // Step 2a: Greedily seek runs of fields that can be cleared by memset-to-0.
   // Step 2a: Greedily seek runs of fields that can be cleared by memset-to-0.
   // The generated code uses two macros to help it clear runs of fields:
   // The generated code uses two macros to help it clear runs of fields:
-  // OFFSET_OF_FIELD_ computes the offset (in bytes) of a field in the Message.
+  // ZR_HELPER_(f1) - ZR_HELPER_(f0) computes the difference, in bytes, of the
+  // positions of two fields in the Message.
   // ZR_ zeroes a non-empty range of fields via memset.
   // ZR_ zeroes a non-empty range of fields via memset.
   const char* macros =
   const char* macros =
-      "#define OFFSET_OF_FIELD_(f) (reinterpret_cast<char*>(      \\\n"
-      "  &reinterpret_cast<$classname$*>(16)->f) - \\\n"
-      "   reinterpret_cast<char*>(16))\n\n"
-      "#define ZR_(first, last) do {                              \\\n"
-      "    size_t f = OFFSET_OF_FIELD_(first);                    \\\n"
-      "    size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last);  \\\n"
-      "    ::memset(&first, 0, n);                                \\\n"
-      "  } while (0)\n\n";
+      "#define ZR_HELPER_(f) reinterpret_cast<char*>(\\\n"
+      "  &reinterpret_cast<$classname$*>(16)->f)\n\n"
+      "#define ZR_(first, last) do {\\\n"
+      "  ::memset(&first, 0,\\\n"
+      "           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\\\n"
+      "} while (0)\n\n";
   for (int i = 0; i < runs_of_fields_.size(); i++) {
   for (int i = 0; i < runs_of_fields_.size(); i++) {
     const vector<string>& run = runs_of_fields_[i];
     const vector<string>& run = runs_of_fields_[i];
     if (run.size() < 2) continue;
     if (run.size() < 2) continue;
@@ -2133,7 +2138,7 @@ GenerateClear(io::Printer* printer) {
   }
   }
   if (macros_are_needed) {
   if (macros_are_needed) {
     printer->Outdent();
     printer->Outdent();
-    printer->Print("\n#undef OFFSET_OF_FIELD_\n#undef ZR_\n\n");
+    printer->Print("\n#undef ZR_HELPER_\n#undef ZR_\n\n");
     printer->Indent();
     printer->Indent();
   }
   }
 
 
@@ -2919,8 +2924,8 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) {
   for (int i = 0; i < descriptor_->extension_range_count(); ++i) {
   for (int i = 0; i < descriptor_->extension_range_count(); ++i) {
     sorted_extensions.push_back(descriptor_->extension_range(i));
     sorted_extensions.push_back(descriptor_->extension_range(i));
   }
   }
-  sort(sorted_extensions.begin(), sorted_extensions.end(),
-       ExtensionRangeSorter());
+  std::sort(sorted_extensions.begin(), sorted_extensions.end(),
+            ExtensionRangeSorter());
 
 
   // Merge the fields and the extension ranges, both sorted by field number.
   // Merge the fields and the extension ranges, both sorted by field number.
   int i, j;
   int i, j;

+ 2 - 2
src/google/protobuf/compiler/cpp/cpp_message.h

@@ -82,7 +82,7 @@ class MessageGenerator {
 
 
   // Generate definitions of inline methods (placed at the end of the header
   // Generate definitions of inline methods (placed at the end of the header
   // file).
   // file).
-  void GenerateInlineMethods(io::Printer* printer);
+  void GenerateInlineMethods(io::Printer* printer, bool is_inline);
 
 
   // Source file stuff.
   // Source file stuff.
 
 
@@ -116,7 +116,7 @@ class MessageGenerator {
  private:
  private:
   // Generate declarations and definitions of accessors for fields.
   // Generate declarations and definitions of accessors for fields.
   void GenerateFieldAccessorDeclarations(io::Printer* printer);
   void GenerateFieldAccessorDeclarations(io::Printer* printer);
-  void GenerateFieldAccessorDefinitions(io::Printer* printer);
+  void GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline);
 
 
   // Generate the field offsets array.
   // Generate the field offsets array.
   void GenerateOffsets(io::Printer* printer);
   void GenerateOffsets(io::Printer* printer);

+ 157 - 113
src/google/protobuf/compiler/cpp/cpp_message_field.cc

@@ -85,76 +85,141 @@ GeneratePrivateMembers(io::Printer* printer) const {
 
 
 void MessageFieldGenerator::
 void MessageFieldGenerator::
 GenerateAccessorDeclarations(io::Printer* printer) const {
 GenerateAccessorDeclarations(io::Printer* printer) const {
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(variables_,
+       "private:\n"
+       "void _slow_mutable_$name$()$deprecation$;\n");
+    if (SupportsArenas(descriptor_->message_type())) {
+      printer->Print(variables_,
+       "void _slow_set_allocated_$name$(\n"
+       "    ::google::protobuf::Arena* message_arena, $type$** $name$)$deprecation$;\n");
+    }
+    printer->Print(variables_,
+       "$type$* _slow_$release_name$()$deprecation$;\n"
+       "public:\n");
+  }
   printer->Print(variables_,
   printer->Print(variables_,
-    "inline const $type$& $name$() const$deprecation$;\n"
-    "inline $type$* mutable_$name$()$deprecation$;\n"
-    "inline $type$* $release_name$()$deprecation$;\n"
-    "inline void set_allocated_$name$($type$* $name$)$deprecation$;\n");
+    "const $type$& $name$() const$deprecation$;\n"
+    "$type$* mutable_$name$()$deprecation$;\n"
+    "$type$* $release_name$()$deprecation$;\n"
+    "void set_allocated_$name$($type$* $name$)$deprecation$;\n");
   if (SupportsArenas(descriptor_)) {
   if (SupportsArenas(descriptor_)) {
     printer->Print(variables_,
     printer->Print(variables_,
-      "inline $type$* unsafe_arena_release_$name$()$deprecation$;\n"
-      "inline void unsafe_arena_set_allocated_$name$(\n"
+      "$type$* unsafe_arena_release_$name$()$deprecation$;\n"
+      "void unsafe_arena_set_allocated_$name$(\n"
       "    $type$* $name$)$deprecation$;\n");
       "    $type$* $name$)$deprecation$;\n");
   }
   }
 }
 }
 
 
+void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions(
+    io::Printer* printer) const {
+  if (SupportsArenas(descriptor_)) {
+    printer->Print(variables_,
+      "void $classname$::_slow_mutable_$name$() {\n");
+      if (SupportsArenas(descriptor_->message_type())) {
+        printer->Print(variables_,
+        "  $name$_ = ::google::protobuf::Arena::CreateMessage< $type$ >(\n"
+      "        GetArenaNoVirtual());\n");
+      } else {
+        printer->Print(variables_,
+         "  $name$_ = ::google::protobuf::Arena::Create< $type$ >(\n"
+         "     GetArenaNoVirtual());\n");
+      }
+    printer->Print(variables_,
+      "}\n"
+      "$type$* $classname$::_slow_$release_name$() {\n"
+      "  if ($name$_ == NULL) {\n"
+      "    return NULL;\n"
+      "  } else {\n"
+      "    $type$* temp = new $type$;\n"
+      "    temp->MergeFrom(*$name$_);\n"
+      "    $name$_ = NULL;\n"
+      "    return temp;\n"
+      "  }\n"
+      "}\n"
+      "$type$* $classname$::unsafe_arena_release_$name$() {\n"
+      "  $clear_hasbit$\n"
+      "  $type$* temp = $name$_;\n"
+      "  $name$_ = NULL;\n"
+      "  return temp;\n"
+      "}\n");
+    if (SupportsArenas(descriptor_->message_type())) {
+        printer->Print(variables_,
+          "void $classname$::_slow_set_allocated_$name$(\n"
+          "    ::google::protobuf::Arena* message_arena, $type$** $name$) {\n"
+          "    if (message_arena != NULL && \n"
+          "        ::google::protobuf::Arena::GetArena(*$name$) == NULL) {\n"
+          "      message_arena->Own(*$name$);\n"
+          "    } else if (message_arena !=\n"
+          "               ::google::protobuf::Arena::GetArena(*$name$)) {\n"
+          "      $type$* new_$name$ = \n"
+          "            ::google::protobuf::Arena::CreateMessage< $type$ >(\n"
+          "            message_arena);\n"
+          "      new_$name$->CopyFrom(**$name$);\n"
+          "      *$name$ = new_$name$;\n"
+          "    }\n"
+          "}\n");
+    }
+    printer->Print(variables_,
+      "void $classname$::unsafe_arena_set_allocated_$name$(\n"
+      "    $type$* $name$) {\n"
+      // If we're not on an arena, free whatever we were holding before.
+      // (If we are on arena, we can just forget the earlier pointer.)
+      "  if (GetArenaNoVirtual() == NULL) {\n"
+      "    delete $name$_;\n"
+      "  }\n"
+      "  $name$_ = $name$;\n"
+      "  if ($name$) {\n"
+      "    $set_hasbit$\n"
+      "  } else {\n"
+      "    $clear_hasbit$\n"
+      "  }\n"
+      "  // @@protoc_insertion_point(field_unsafe_arena_set_allocated"
+      ":$full_name$)\n"
+      "}\n");
+  }
+}
+
 void MessageFieldGenerator::
 void MessageFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
-  printer->Print(variables_,
-    "inline const $type$& $classname$::$name$() const {\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                  bool is_inline) const {
+  map<string, string> variables(variables_);
+  variables["inline"] = is_inline ? "inline" : "";
+  printer->Print(variables,
+    "$inline$ const $type$& $classname$::$name$() const {\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n");
     "  // @@protoc_insertion_point(field_get:$full_name$)\n");
 
 
   PrintHandlingOptionalStaticInitializers(
   PrintHandlingOptionalStaticInitializers(
-    variables_, descriptor_->file(), printer,
+    variables, descriptor_->file(), printer,
     // With static initializers.
     // With static initializers.
     "  return $name$_ != NULL ? *$name$_ : *default_instance_->$name$_;\n",
     "  return $name$_ != NULL ? *$name$_ : *default_instance_->$name$_;\n",
     // Without.
     // Without.
     "  return $name$_ != NULL ? *$name$_ : *default_instance().$name$_;\n");
     "  return $name$_ != NULL ? *$name$_ : *default_instance().$name$_;\n");
 
 
   if (SupportsArenas(descriptor_)) {
   if (SupportsArenas(descriptor_)) {
-    printer->Print(variables_,
+    printer->Print(variables,
       "}\n"
       "}\n"
-      "inline $type$* $classname$::mutable_$name$() {\n"
+      "$inline$ $type$* $classname$::mutable_$name$() {\n"
       "  $set_hasbit$\n"
       "  $set_hasbit$\n"
-      "  if ($name$_ == NULL) {\n");
-    if (SupportsArenas(descriptor_->message_type())) {
-      printer->Print(variables_,
-      "    $name$_ = ::google::protobuf::Arena::CreateMessage< $type$ >(\n"
-      "        GetArenaNoVirtual());\n");
-    } else {
-      printer->Print(variables_,
-       "    $name$_ = ::google::protobuf::Arena::Create< $type$ >(\n"
-       "        GetArenaNoVirtual());\n");
-    }
-    printer->Print(variables_, "  }\n"
+      "  if ($name$_ == NULL) {\n"
+      "    _slow_mutable_$name$();"
+      "  }\n"
       "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
       "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
       "  return $name$_;\n"
       "  return $name$_;\n"
       "}\n"
       "}\n"
-      "inline $type$* $classname$::$release_name$() {\n"
+      "$inline$ $type$* $classname$::$release_name$() {\n"
       "  $clear_hasbit$\n"
       "  $clear_hasbit$\n"
       "  if (GetArenaNoVirtual() != NULL) {\n"
       "  if (GetArenaNoVirtual() != NULL) {\n"
-      "    if ($name$_ == NULL) {\n"
-      "      return NULL;\n"
-      "    } else {\n"
-      "      $type$* temp = new $type$;\n"
-      "      temp->MergeFrom(*$name$_);\n"
-      "      $name$_ = NULL;\n"
-      "      return temp;\n"
-      "    }\n"
+      "    return _slow_$release_name$();\n"
       "  } else {\n"
       "  } else {\n"
       "    $type$* temp = $name$_;\n"
       "    $type$* temp = $name$_;\n"
       "    $name$_ = NULL;\n"
       "    $name$_ = NULL;\n"
       "    return temp;\n"
       "    return temp;\n"
       "  }\n"
       "  }\n"
       "}\n"
       "}\n"
-      "inline $type$* $classname$::unsafe_arena_release_$name$() {\n"
-      "  $clear_hasbit$\n"
-      "  $type$* temp = $name$_;\n"
-      "  $name$_ = NULL;\n"
-      "  return temp;\n"
-      "}\n"
-      "inline void $classname$::set_allocated_$name$($type$* $name$) {\n"
-      "  if (GetArenaNoVirtual() == NULL) {\n"
+      "$inline$ void $classname$::set_allocated_$name$($type$* $name$) {\n"
+      "  ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();\n"
+      "  if (message_arena == NULL) {\n"
       "    delete $name$_;\n"
       "    delete $name$_;\n"
       "  }\n"
       "  }\n"
       "  if ($name$ != NULL) {\n");
       "  if ($name$ != NULL) {\n");
@@ -164,26 +229,15 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
       // so we might as well defer it. Otherwise, if incoming message is on a
       // so we might as well defer it. Otherwise, if incoming message is on a
       // different ownership domain (specific arena, or the heap) than we are,
       // different ownership domain (specific arena, or the heap) than we are,
       // copy to our arena (or heap, as the case may be).
       // copy to our arena (or heap, as the case may be).
-      printer->Print(variables_,
-        "    if (GetArenaNoVirtual() != NULL && \n"
-        "        ::google::protobuf::Arena::GetArena($name$) == NULL) {\n"
-        "      GetArenaNoVirtual()->Own($name$);\n"
-        "    } else if (GetArenaNoVirtual() !=\n"
-        "               ::google::protobuf::Arena::GetArena($name$)) {\n"
-        "      $type$* new_$name$ = \n"
-        "            ::google::protobuf::Arena::CreateMessage< $type$ >(\n"
-        "            GetArenaNoVirtual());\n"
-        "      new_$name$->CopyFrom(*$name$);\n"
-        "      $name$ = new_$name$;\n"
-        "    }\n");
+      printer->Print(variables,
+        "    _slow_set_allocated_$name$(message_arena, &$name$);\n");
     } else {
     } else {
-      printer->Print(variables_,
-        "    if (GetArenaNoVirtual() != NULL) {\n"
-        "      GetArenaNoVirtual()->Own($name$);\n"
+      printer->Print(variables,
+        "    if (message_arena != NULL) {\n"
+        "      message_arena->Own($name$);\n"
         "    }\n");
         "    }\n");
     }
     }
-
-    printer->Print(variables_,
+    printer->Print(variables,
       "  }\n"
       "  }\n"
       "  $name$_ = $name$;\n"
       "  $name$_ = $name$;\n"
       "  if ($name$) {\n"
       "  if ($name$) {\n"
@@ -192,27 +246,11 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
       "    $clear_hasbit$\n"
       "    $clear_hasbit$\n"
       "  }\n"
       "  }\n"
       "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
       "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
-      "}\n"
-      "inline void $classname$::unsafe_arena_set_allocated_$name$(\n"
-      "    $type$* $name$) {\n"
-      // If we're not on an arena, free whatever we were holding before.
-      // (If we are on arena, we can just forget the earlier pointer.)
-      "  if (GetArenaNoVirtual() == NULL) {\n"
-      "    delete $name$_;\n"
-      "  }\n"
-      "  $name$_ = $name$;\n"
-      "  if ($name$) {\n"
-      "    $set_hasbit$\n"
-      "  } else {\n"
-      "    $clear_hasbit$\n"
-      "  }\n"
-      "  // @@protoc_insertion_point(field_unsafe_arena_set_allocated"
-      ":$full_name$)\n"
       "}\n");
       "}\n");
   } else {
   } else {
-    printer->Print(variables_,
+    printer->Print(variables,
       "}\n"
       "}\n"
-      "inline $type$* $classname$::mutable_$name$() {\n"
+      "$inline$ $type$* $classname$::mutable_$name$() {\n"
       "  $set_hasbit$\n"
       "  $set_hasbit$\n"
       "  if ($name$_ == NULL) {\n"
       "  if ($name$_ == NULL) {\n"
       "    $name$_ = new $type$;\n"
       "    $name$_ = new $type$;\n"
@@ -220,17 +258,17 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
       "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
       "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
       "  return $name$_;\n"
       "  return $name$_;\n"
       "}\n"
       "}\n"
-      "inline $type$* $classname$::$release_name$() {\n"
+      "$inline$ $type$* $classname$::$release_name$() {\n"
       "  $clear_hasbit$\n"
       "  $clear_hasbit$\n"
       "  $type$* temp = $name$_;\n"
       "  $type$* temp = $name$_;\n"
       "  $name$_ = NULL;\n"
       "  $name$_ = NULL;\n"
       "  return temp;\n"
       "  return temp;\n"
       "}\n"
       "}\n"
-      "inline void $classname$::set_allocated_$name$($type$* $name$) {\n"
+      "$inline$ void $classname$::set_allocated_$name$($type$* $name$) {\n"
       "  delete $name$_;\n");
       "  delete $name$_;\n");
 
 
     if (SupportsArenas(descriptor_->message_type())) {
     if (SupportsArenas(descriptor_->message_type())) {
-      printer->Print(variables_,
+      printer->Print(variables,
       "  if ($name$ != NULL && $name$->GetArena() != NULL) {\n"
       "  if ($name$ != NULL && $name$->GetArena() != NULL) {\n"
       "    $type$* new_$name$ = new $type$;\n"
       "    $type$* new_$name$ = new $type$;\n"
       "    new_$name$->CopyFrom(*$name$);\n"
       "    new_$name$->CopyFrom(*$name$);\n"
@@ -238,7 +276,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
       "  }\n");
       "  }\n");
     }
     }
 
 
-    printer->Print(variables_,
+    printer->Print(variables,
       "  $name$_ = $name$;\n"
       "  $name$_ = $name$;\n"
       "  if ($name$) {\n"
       "  if ($name$) {\n"
       "    $set_hasbit$\n"
       "    $set_hasbit$\n"
@@ -328,35 +366,38 @@ MessageOneofFieldGenerator(const FieldDescriptor* descriptor,
 MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {}
 MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {}
 
 
 void MessageOneofFieldGenerator::
 void MessageOneofFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                  bool is_inline) const {
+  map<string, string> variables(variables_);
+  variables["inline"] = is_inline ? "inline" : "";
   if (SupportsArenas(descriptor_)) {
   if (SupportsArenas(descriptor_)) {
-    printer->Print(variables_,
-      "inline const $type$& $classname$::$name$() const {\n"
+    printer->Print(variables,
+      "$inline$ const $type$& $classname$::$name$() const {\n"
       "  // @@protoc_insertion_point(field_get:$full_name$)\n"
       "  // @@protoc_insertion_point(field_get:$full_name$)\n"
       "  return has_$name$() ? *$oneof_prefix$$name$_\n"
       "  return has_$name$() ? *$oneof_prefix$$name$_\n"
       "                      : $type$::default_instance();\n"
       "                      : $type$::default_instance();\n"
       "}\n"
       "}\n"
-      "inline $type$* $classname$::mutable_$name$() {\n"
+      "$inline$ $type$* $classname$::mutable_$name$() {\n"
       "  if (!has_$name$()) {\n"
       "  if (!has_$name$()) {\n"
       "    clear_$oneof_name$();\n"
       "    clear_$oneof_name$();\n"
       "    set_has_$name$();\n");
       "    set_has_$name$();\n");
     if (SupportsArenas(descriptor_->message_type())) {
     if (SupportsArenas(descriptor_->message_type())) {
-      printer->Print(variables_,
+      printer->Print(variables,
          "    $oneof_prefix$$name$_ = \n"
          "    $oneof_prefix$$name$_ = \n"
          "      ::google::protobuf::Arena::CreateMessage< $type$ >(\n"
          "      ::google::protobuf::Arena::CreateMessage< $type$ >(\n"
          "      GetArenaNoVirtual());\n");
          "      GetArenaNoVirtual());\n");
     } else {
     } else {
-      printer->Print(variables_,
+      printer->Print(variables,
          "    $oneof_prefix$$name$_ = \n"
          "    $oneof_prefix$$name$_ = \n"
          "      ::google::protobuf::Arena::Create< $type$ >(\n"
          "      ::google::protobuf::Arena::Create< $type$ >(\n"
          "      GetArenaNoVirtual());\n");
          "      GetArenaNoVirtual());\n");
     }
     }
-    printer->Print(variables_,
+    printer->Print(variables,
       "  }\n"
       "  }\n"
       "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
       "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
       "  return $oneof_prefix$$name$_;\n"
       "  return $oneof_prefix$$name$_;\n"
       "}\n"
       "}\n"
-      "inline $type$* $classname$::$release_name$() {\n"
+      "$inline$ $type$* $classname$::$release_name$() {\n"
       "  if (has_$name$()) {\n"
       "  if (has_$name$()) {\n"
       "    clear_has_$oneof_name$();\n"
       "    clear_has_$oneof_name$();\n"
       "    if (GetArenaNoVirtual() != NULL) {\n"
       "    if (GetArenaNoVirtual() != NULL) {\n"
@@ -375,7 +416,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
       "    return NULL;\n"
       "    return NULL;\n"
       "  }\n"
       "  }\n"
       "}\n"
       "}\n"
-      "inline $type$* $classname$::unsafe_arena_release_$name$() {\n"
+      "$inline$ $type$* $classname$::unsafe_arena_release_$name$() {\n"
       "  if (has_$name$()) {\n"
       "  if (has_$name$()) {\n"
       "    clear_has_$oneof_name$();\n"
       "    clear_has_$oneof_name$();\n"
       "    $type$* temp = $oneof_prefix$$name$_;\n"
       "    $type$* temp = $oneof_prefix$$name$_;\n"
@@ -385,12 +426,12 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
       "    return NULL;\n"
       "    return NULL;\n"
       "  }\n"
       "  }\n"
       "}\n"
       "}\n"
-      "inline void $classname$::set_allocated_$name$($type$* $name$) {\n"
+      "$inline$ void $classname$::set_allocated_$name$($type$* $name$) {\n"
       "  clear_$oneof_name$();\n"
       "  clear_$oneof_name$();\n"
       "  if ($name$) {\n");
       "  if ($name$) {\n");
 
 
     if (SupportsArenas(descriptor_->message_type())) {
     if (SupportsArenas(descriptor_->message_type())) {
-      printer->Print(variables_,
+      printer->Print(variables,
         // If incoming message is on the heap and we are on an arena, just Own()
         // If incoming message is on the heap and we are on an arena, just Own()
         // it (see above). If it's on a different arena than we are or one of us
         // it (see above). If it's on a different arena than we are or one of us
         // is on the heap, we make a copy to our arena/heap.
         // is on the heap, we make a copy to our arena/heap.
@@ -406,19 +447,19 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
         "      $name$ = new_$name$;\n"
         "      $name$ = new_$name$;\n"
         "    }\n");
         "    }\n");
     } else {
     } else {
-      printer->Print(variables_,
+      printer->Print(variables,
         "    if (GetArenaNoVirtual() != NULL) {\n"
         "    if (GetArenaNoVirtual() != NULL) {\n"
         "      GetArenaNoVirtual()->Own($name$);\n"
         "      GetArenaNoVirtual()->Own($name$);\n"
         "    }\n");
         "    }\n");
     }
     }
 
 
-    printer->Print(variables_,
+    printer->Print(variables,
       "    set_has_$name$();\n"
       "    set_has_$name$();\n"
       "    $oneof_prefix$$name$_ = $name$;\n"
       "    $oneof_prefix$$name$_ = $name$;\n"
       "  }\n"
       "  }\n"
       "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
       "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
       "}\n"
       "}\n"
-      "inline void $classname$::unsafe_arena_set_allocated_$name$("
+      "$inline$ void $classname$::unsafe_arena_set_allocated_$name$("
       "$type$* $name$) {\n"
       "$type$* $name$) {\n"
       // We rely on the oneof clear method to free the earlier contents of this
       // We rely on the oneof clear method to free the earlier contents of this
       // oneof. We can directly use the pointer we're given to set the new
       // oneof. We can directly use the pointer we're given to set the new
@@ -432,13 +473,13 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
       "$full_name$)\n"
       "$full_name$)\n"
       "}\n");
       "}\n");
   } else {
   } else {
-    printer->Print(variables_,
-      "inline const $type$& $classname$::$name$() const {\n"
+    printer->Print(variables,
+      "$inline$ const $type$& $classname$::$name$() const {\n"
       "  // @@protoc_insertion_point(field_get:$full_name$)\n"
       "  // @@protoc_insertion_point(field_get:$full_name$)\n"
       "  return has_$name$() ? *$oneof_prefix$$name$_\n"
       "  return has_$name$() ? *$oneof_prefix$$name$_\n"
       "                      : $type$::default_instance();\n"
       "                      : $type$::default_instance();\n"
       "}\n"
       "}\n"
-      "inline $type$* $classname$::mutable_$name$() {\n"
+      "$inline$ $type$* $classname$::mutable_$name$() {\n"
       "  if (!has_$name$()) {\n"
       "  if (!has_$name$()) {\n"
       "    clear_$oneof_name$();\n"
       "    clear_$oneof_name$();\n"
       "    set_has_$name$();\n"
       "    set_has_$name$();\n"
@@ -447,7 +488,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
       "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
       "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
       "  return $oneof_prefix$$name$_;\n"
       "  return $oneof_prefix$$name$_;\n"
       "}\n"
       "}\n"
-      "inline $type$* $classname$::$release_name$() {\n"
+      "$inline$ $type$* $classname$::$release_name$() {\n"
       "  if (has_$name$()) {\n"
       "  if (has_$name$()) {\n"
       "    clear_has_$oneof_name$();\n"
       "    clear_has_$oneof_name$();\n"
       "    $type$* temp = $oneof_prefix$$name$_;\n"
       "    $type$* temp = $oneof_prefix$$name$_;\n"
@@ -457,18 +498,18 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
       "    return NULL;\n"
       "    return NULL;\n"
       "  }\n"
       "  }\n"
       "}\n"
       "}\n"
-      "inline void $classname$::set_allocated_$name$($type$* $name$) {\n"
+      "$inline$ void $classname$::set_allocated_$name$($type$* $name$) {\n"
       "  clear_$oneof_name$();\n"
       "  clear_$oneof_name$();\n"
       "  if ($name$) {\n");
       "  if ($name$) {\n");
     if (SupportsArenas(descriptor_->message_type())) {
     if (SupportsArenas(descriptor_->message_type())) {
-      printer->Print(variables_,
+      printer->Print(variables,
         "    if ($name$->GetArena() != NULL) {\n"
         "    if ($name$->GetArena() != NULL) {\n"
         "      $type$* new_$name$ = new $type$;\n"
         "      $type$* new_$name$ = new $type$;\n"
         "      new_$name$->CopyFrom(*$name$);\n"
         "      new_$name$->CopyFrom(*$name$);\n"
         "      $name$ = new_$name$;\n"
         "      $name$ = new_$name$;\n"
         "    }\n");
         "    }\n");
     }
     }
-    printer->Print(variables_,
+    printer->Print(variables,
       "    set_has_$name$();\n"
       "    set_has_$name$();\n"
       "    $oneof_prefix$$name$_ = $name$;\n"
       "    $oneof_prefix$$name$_ = $name$;\n"
       "  }\n"
       "  }\n"
@@ -521,38 +562,41 @@ GeneratePrivateMembers(io::Printer* printer) const {
 void RepeatedMessageFieldGenerator::
 void RepeatedMessageFieldGenerator::
 GenerateAccessorDeclarations(io::Printer* printer) const {
 GenerateAccessorDeclarations(io::Printer* printer) const {
   printer->Print(variables_,
   printer->Print(variables_,
-    "inline const $type$& $name$(int index) const$deprecation$;\n"
-    "inline $type$* mutable_$name$(int index)$deprecation$;\n"
-    "inline $type$* add_$name$()$deprecation$;\n");
+    "const $type$& $name$(int index) const$deprecation$;\n"
+    "$type$* mutable_$name$(int index)$deprecation$;\n"
+    "$type$* add_$name$()$deprecation$;\n");
   printer->Print(variables_,
   printer->Print(variables_,
-    "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
+    "const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
     "    $name$() const$deprecation$;\n"
     "    $name$() const$deprecation$;\n"
-    "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n"
+    "::google::protobuf::RepeatedPtrField< $type$ >*\n"
     "    mutable_$name$()$deprecation$;\n");
     "    mutable_$name$()$deprecation$;\n");
 }
 }
 
 
 void RepeatedMessageFieldGenerator::
 void RepeatedMessageFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
-  printer->Print(variables_,
-    "inline const $type$& $classname$::$name$(int index) const {\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                  bool is_inline) const {
+  map<string, string> variables(variables_);
+  variables["inline"] = is_inline ? "inline" : "";
+  printer->Print(variables,
+    "$inline$ const $type$& $classname$::$name$(int index) const {\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  return $name$_.$cppget$(index);\n"
     "  return $name$_.$cppget$(index);\n"
     "}\n"
     "}\n"
-    "inline $type$* $classname$::mutable_$name$(int index) {\n"
+    "$inline$ $type$* $classname$::mutable_$name$(int index) {\n"
     "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
     "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
     "  return $name$_.Mutable(index);\n"
     "  return $name$_.Mutable(index);\n"
     "}\n"
     "}\n"
-    "inline $type$* $classname$::add_$name$() {\n"
+    "$inline$ $type$* $classname$::add_$name$() {\n"
     "  // @@protoc_insertion_point(field_add:$full_name$)\n"
     "  // @@protoc_insertion_point(field_add:$full_name$)\n"
     "  return $name$_.Add();\n"
     "  return $name$_.Add();\n"
     "}\n");
     "}\n");
-  printer->Print(variables_,
-    "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
+  printer->Print(variables,
+    "$inline$ const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
     "$classname$::$name$() const {\n"
     "$classname$::$name$() const {\n"
     "  // @@protoc_insertion_point(field_list:$full_name$)\n"
     "  // @@protoc_insertion_point(field_list:$full_name$)\n"
     "  return $name$_;\n"
     "  return $name$_;\n"
     "}\n"
     "}\n"
-    "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n"
+    "$inline$ ::google::protobuf::RepeatedPtrField< $type$ >*\n"
     "$classname$::mutable_$name$() {\n"
     "$classname$::mutable_$name$() {\n"
     "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
     "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
     "  return &$name$_;\n"
     "  return &$name$_;\n"

+ 8 - 3
src/google/protobuf/compiler/cpp/cpp_message_field.h

@@ -53,7 +53,9 @@ class MessageFieldGenerator : public FieldGenerator {
   // implements FieldGenerator ---------------------------------------
   // implements FieldGenerator ---------------------------------------
   void GeneratePrivateMembers(io::Printer* printer) const;
   void GeneratePrivateMembers(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
-  void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                         bool is_inline) const;
+  void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
@@ -78,7 +80,9 @@ class MessageOneofFieldGenerator : public MessageFieldGenerator {
   ~MessageOneofFieldGenerator();
   ~MessageOneofFieldGenerator();
 
 
   // implements FieldGenerator ---------------------------------------
   // implements FieldGenerator ---------------------------------------
-  void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                         bool is_inline) const;
+  void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const {}
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
   void GenerateConstructorCode(io::Printer* printer) const;
   void GenerateConstructorCode(io::Printer* printer) const;
@@ -96,7 +100,8 @@ class RepeatedMessageFieldGenerator : public FieldGenerator {
   // implements FieldGenerator ---------------------------------------
   // implements FieldGenerator ---------------------------------------
   void GeneratePrivateMembers(io::Printer* printer) const;
   void GeneratePrivateMembers(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
-  void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                         bool is_inline) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;

+ 29 - 23
src/google/protobuf/compiler/cpp/cpp_primitive_field.cc

@@ -117,18 +117,20 @@ GeneratePrivateMembers(io::Printer* printer) const {
 void PrimitiveFieldGenerator::
 void PrimitiveFieldGenerator::
 GenerateAccessorDeclarations(io::Printer* printer) const {
 GenerateAccessorDeclarations(io::Printer* printer) const {
   printer->Print(variables_,
   printer->Print(variables_,
-    "inline $type$ $name$() const$deprecation$;\n"
-    "inline void set_$name$($type$ value)$deprecation$;\n");
+    "$type$ $name$() const$deprecation$;\n"
+    "void set_$name$($type$ value)$deprecation$;\n");
 }
 }
 
 
 void PrimitiveFieldGenerator::
 void PrimitiveFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
-  printer->Print(variables_,
-    "inline $type$ $classname$::$name$() const {\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const {
+  map<string, string> variables(variables_);
+  variables["inline"] = is_inline ? "inline" : "";
+  printer->Print(variables,
+    "$inline$ $type$ $classname$::$name$() const {\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  return $name$_;\n"
     "  return $name$_;\n"
     "}\n"
     "}\n"
-    "inline void $classname$::set_$name$($type$ value) {\n"
+    "$inline$ void $classname$::set_$name$($type$ value) {\n"
     "  $set_hasbit$\n"
     "  $set_hasbit$\n"
     "  $name$_ = value;\n"
     "  $name$_ = value;\n"
     "  // @@protoc_insertion_point(field_set:$full_name$)\n"
     "  // @@protoc_insertion_point(field_set:$full_name$)\n"
@@ -204,16 +206,18 @@ PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor,
 PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {}
 PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {}
 
 
 void PrimitiveOneofFieldGenerator::
 void PrimitiveOneofFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
-  printer->Print(variables_,
-    "inline $type$ $classname$::$name$() const {\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const {
+  map<string, string> variables(variables_);
+  variables["inline"] = is_inline ? "inline" : "";
+  printer->Print(variables,
+    "$inline$ $type$ $classname$::$name$() const {\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  if (has_$name$()) {\n"
     "  if (has_$name$()) {\n"
     "    return $oneof_prefix$$name$_;\n"
     "    return $oneof_prefix$$name$_;\n"
     "  }\n"
     "  }\n"
     "  return $default$;\n"
     "  return $default$;\n"
     "}\n"
     "}\n"
-    "inline void $classname$::set_$name$($type$ value) {\n"
+    "$inline$ void $classname$::set_$name$($type$ value) {\n"
     "  if (!has_$name$()) {\n"
     "  if (!has_$name$()) {\n"
     "    clear_$oneof_name$();\n"
     "    clear_$oneof_name$();\n"
     "    set_has_$name$();\n"
     "    set_has_$name$();\n"
@@ -282,38 +286,40 @@ GeneratePrivateMembers(io::Printer* printer) const {
 void RepeatedPrimitiveFieldGenerator::
 void RepeatedPrimitiveFieldGenerator::
 GenerateAccessorDeclarations(io::Printer* printer) const {
 GenerateAccessorDeclarations(io::Printer* printer) const {
   printer->Print(variables_,
   printer->Print(variables_,
-    "inline $type$ $name$(int index) const$deprecation$;\n"
-    "inline void set_$name$(int index, $type$ value)$deprecation$;\n"
-    "inline void add_$name$($type$ value)$deprecation$;\n");
+    "$type$ $name$(int index) const$deprecation$;\n"
+    "void set_$name$(int index, $type$ value)$deprecation$;\n"
+    "void add_$name$($type$ value)$deprecation$;\n");
   printer->Print(variables_,
   printer->Print(variables_,
-    "inline const ::google::protobuf::RepeatedField< $type$ >&\n"
+    "const ::google::protobuf::RepeatedField< $type$ >&\n"
     "    $name$() const$deprecation$;\n"
     "    $name$() const$deprecation$;\n"
-    "inline ::google::protobuf::RepeatedField< $type$ >*\n"
+    "::google::protobuf::RepeatedField< $type$ >*\n"
     "    mutable_$name$()$deprecation$;\n");
     "    mutable_$name$()$deprecation$;\n");
 }
 }
 
 
 void RepeatedPrimitiveFieldGenerator::
 void RepeatedPrimitiveFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
-  printer->Print(variables_,
-    "inline $type$ $classname$::$name$(int index) const {\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const {
+  map<string, string> variables(variables_);
+  variables["inline"] = is_inline ? "inline" : "";
+  printer->Print(variables,
+    "$inline$ $type$ $classname$::$name$(int index) const {\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  return $name$_.Get(index);\n"
     "  return $name$_.Get(index);\n"
     "}\n"
     "}\n"
-    "inline void $classname$::set_$name$(int index, $type$ value) {\n"
+    "$inline$ void $classname$::set_$name$(int index, $type$ value) {\n"
     "  $name$_.Set(index, value);\n"
     "  $name$_.Set(index, value);\n"
     "  // @@protoc_insertion_point(field_set:$full_name$)\n"
     "  // @@protoc_insertion_point(field_set:$full_name$)\n"
     "}\n"
     "}\n"
-    "inline void $classname$::add_$name$($type$ value) {\n"
+    "$inline$ void $classname$::add_$name$($type$ value) {\n"
     "  $name$_.Add(value);\n"
     "  $name$_.Add(value);\n"
     "  // @@protoc_insertion_point(field_add:$full_name$)\n"
     "  // @@protoc_insertion_point(field_add:$full_name$)\n"
     "}\n");
     "}\n");
-  printer->Print(variables_,
-    "inline const ::google::protobuf::RepeatedField< $type$ >&\n"
+  printer->Print(variables,
+    "$inline$ const ::google::protobuf::RepeatedField< $type$ >&\n"
     "$classname$::$name$() const {\n"
     "$classname$::$name$() const {\n"
     "  // @@protoc_insertion_point(field_list:$full_name$)\n"
     "  // @@protoc_insertion_point(field_list:$full_name$)\n"
     "  return $name$_;\n"
     "  return $name$_;\n"
     "}\n"
     "}\n"
-    "inline ::google::protobuf::RepeatedField< $type$ >*\n"
+    "$inline$ ::google::protobuf::RepeatedField< $type$ >*\n"
     "$classname$::mutable_$name$() {\n"
     "$classname$::mutable_$name$() {\n"
     "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
     "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
     "  return &$name$_;\n"
     "  return &$name$_;\n"

+ 6 - 3
src/google/protobuf/compiler/cpp/cpp_primitive_field.h

@@ -53,7 +53,8 @@ class PrimitiveFieldGenerator : public FieldGenerator {
   // implements FieldGenerator ---------------------------------------
   // implements FieldGenerator ---------------------------------------
   void GeneratePrivateMembers(io::Printer* printer) const;
   void GeneratePrivateMembers(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
-  void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                         bool is_inline) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
@@ -78,7 +79,8 @@ class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator {
   ~PrimitiveOneofFieldGenerator();
   ~PrimitiveOneofFieldGenerator();
 
 
   // implements FieldGenerator ---------------------------------------
   // implements FieldGenerator ---------------------------------------
-  void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                         bool is_inline) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
   void GenerateConstructorCode(io::Printer* printer) const;
   void GenerateConstructorCode(io::Printer* printer) const;
@@ -97,7 +99,8 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
   // implements FieldGenerator ---------------------------------------
   // implements FieldGenerator ---------------------------------------
   void GeneratePrivateMembers(io::Printer* printer) const;
   void GeneratePrivateMembers(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
-  void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                         bool is_inline) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;

+ 92 - 76
src/google/protobuf/compiler/cpp/cpp_string_field.cc

@@ -127,7 +127,11 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
   // files that applied the ctype.  The field can still be accessed via the
   // files that applied the ctype.  The field can still be accessed via the
   // reflection interface since the reflection interface is independent of
   // reflection interface since the reflection interface is independent of
   // the string's underlying representation.
   // the string's underlying representation.
-  if (descriptor_->options().ctype() != FieldOptions::STRING) {
+
+  bool unknown_ctype =
+      descriptor_->options().ctype() != EffectiveStringCType(descriptor_);
+
+  if (unknown_ctype) {
     printer->Outdent();
     printer->Outdent();
     printer->Print(
     printer->Print(
       " private:\n"
       " private:\n"
@@ -136,23 +140,23 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
   }
   }
 
 
   printer->Print(variables_,
   printer->Print(variables_,
-    "inline const ::std::string& $name$() const$deprecation$;\n"
-    "inline void set_$name$(const ::std::string& value)$deprecation$;\n"
-    "inline void set_$name$(const char* value)$deprecation$;\n"
-    "inline void set_$name$(const $pointer_type$* value, size_t size)"
+    "const ::std::string& $name$() const$deprecation$;\n"
+    "void set_$name$(const ::std::string& value)$deprecation$;\n"
+    "void set_$name$(const char* value)$deprecation$;\n"
+    "void set_$name$(const $pointer_type$* value, size_t size)"
                  "$deprecation$;\n"
                  "$deprecation$;\n"
-    "inline ::std::string* mutable_$name$()$deprecation$;\n"
-    "inline ::std::string* $release_name$()$deprecation$;\n"
-    "inline void set_allocated_$name$(::std::string* $name$)$deprecation$;\n");
+    "::std::string* mutable_$name$()$deprecation$;\n"
+    "::std::string* $release_name$()$deprecation$;\n"
+    "void set_allocated_$name$(::std::string* $name$)$deprecation$;\n");
   if (SupportsArenas(descriptor_)) {
   if (SupportsArenas(descriptor_)) {
     printer->Print(variables_,
     printer->Print(variables_,
-      "inline ::std::string* unsafe_arena_release_$name$()$deprecation$;\n"
-      "inline void unsafe_arena_set_allocated_$name$(\n"
+      "::std::string* unsafe_arena_release_$name$()$deprecation$;\n"
+      "void unsafe_arena_set_allocated_$name$(\n"
       "    ::std::string* $name$)$deprecation$;\n");
       "    ::std::string* $name$)$deprecation$;\n");
   }
   }
 
 
 
 
-  if (descriptor_->options().ctype() != FieldOptions::STRING) {
+  if (unknown_ctype) {
     printer->Outdent();
     printer->Outdent();
     printer->Print(" public:\n");
     printer->Print(" public:\n");
     printer->Indent();
     printer->Indent();
@@ -160,25 +164,28 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
 }
 }
 
 
 void StringFieldGenerator::
 void StringFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                  bool is_inline) const {
+  map<string, string> variables(variables_);
+  variables["inline"] = is_inline ? "inline" : "";
   if (SupportsArenas(descriptor_)) {
   if (SupportsArenas(descriptor_)) {
-    printer->Print(variables_,
-      "inline const ::std::string& $classname$::$name$() const {\n"
+    printer->Print(variables,
+      "$inline$ const ::std::string& $classname$::$name$() const {\n"
       "  // @@protoc_insertion_point(field_get:$full_name$)\n"
       "  // @@protoc_insertion_point(field_get:$full_name$)\n"
       "  return $name$_.Get($default_variable$);\n"
       "  return $name$_.Get($default_variable$);\n"
       "}\n"
       "}\n"
-      "inline void $classname$::set_$name$(const ::std::string& value) {\n"
+      "$inline$ void $classname$::set_$name$(const ::std::string& value) {\n"
       "  $set_hasbit$\n"
       "  $set_hasbit$\n"
       "  $name$_.Set($default_variable$, value, GetArenaNoVirtual());\n"
       "  $name$_.Set($default_variable$, value, GetArenaNoVirtual());\n"
       "  // @@protoc_insertion_point(field_set:$full_name$)\n"
       "  // @@protoc_insertion_point(field_set:$full_name$)\n"
       "}\n"
       "}\n"
-      "inline void $classname$::set_$name$(const char* value) {\n"
+      "$inline$ void $classname$::set_$name$(const char* value) {\n"
       "  $set_hasbit$\n"
       "  $set_hasbit$\n"
       "  $name$_.Set($default_variable$, $string_piece$(value),\n"
       "  $name$_.Set($default_variable$, $string_piece$(value),\n"
       "              GetArenaNoVirtual());\n"
       "              GetArenaNoVirtual());\n"
       "  // @@protoc_insertion_point(field_set_char:$full_name$)\n"
       "  // @@protoc_insertion_point(field_set_char:$full_name$)\n"
       "}\n"
       "}\n"
-      "inline "
+      "$inline$ "
       "void $classname$::set_$name$(const $pointer_type$* value,\n"
       "void $classname$::set_$name$(const $pointer_type$* value,\n"
       "    size_t size) {\n"
       "    size_t size) {\n"
       "  $set_hasbit$\n"
       "  $set_hasbit$\n"
@@ -186,22 +193,22 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
       "      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());\n"
       "      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());\n"
       "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
       "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
       "}\n"
       "}\n"
-      "inline ::std::string* $classname$::mutable_$name$() {\n"
+      "$inline$ ::std::string* $classname$::mutable_$name$() {\n"
       "  $set_hasbit$\n"
       "  $set_hasbit$\n"
       "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
       "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
       "  return $name$_.Mutable($default_variable$, GetArenaNoVirtual());\n"
       "  return $name$_.Mutable($default_variable$, GetArenaNoVirtual());\n"
       "}\n"
       "}\n"
-      "inline ::std::string* $classname$::$release_name$() {\n"
+      "$inline$ ::std::string* $classname$::$release_name$() {\n"
       "  $clear_hasbit$\n"
       "  $clear_hasbit$\n"
       "  return $name$_.Release($default_variable$, GetArenaNoVirtual());\n"
       "  return $name$_.Release($default_variable$, GetArenaNoVirtual());\n"
       "}\n"
       "}\n"
-      "inline ::std::string* $classname$::unsafe_arena_release_$name$() {\n"
+      "$inline$ ::std::string* $classname$::unsafe_arena_release_$name$() {\n"
       "  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n"
       "  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n"
       "  $clear_hasbit$\n"
       "  $clear_hasbit$\n"
       "  return $name$_.UnsafeArenaRelease($default_variable$,\n"
       "  return $name$_.UnsafeArenaRelease($default_variable$,\n"
       "      GetArenaNoVirtual());\n"
       "      GetArenaNoVirtual());\n"
       "}\n"
       "}\n"
-      "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
+      "$inline$ void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
       "  if ($name$ != NULL) {\n"
       "  if ($name$ != NULL) {\n"
       "    $set_hasbit$\n"
       "    $set_hasbit$\n"
       "  } else {\n"
       "  } else {\n"
@@ -211,7 +218,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
       "      GetArenaNoVirtual());\n"
       "      GetArenaNoVirtual());\n"
       "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
       "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
       "}\n"
       "}\n"
-      "inline void $classname$::unsafe_arena_set_allocated_$name$(\n"
+      "$inline$ void $classname$::unsafe_arena_set_allocated_$name$(\n"
       "    ::std::string* $name$) {\n"
       "    ::std::string* $name$) {\n"
       "  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n"
       "  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n"
       "  if ($name$ != NULL) {\n"
       "  if ($name$ != NULL) {\n"
@@ -226,22 +233,22 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
       "}\n");
       "}\n");
   } else {
   } else {
     // No-arena case.
     // No-arena case.
-    printer->Print(variables_,
-      "inline const ::std::string& $classname$::$name$() const {\n"
+    printer->Print(variables,
+      "$inline$ const ::std::string& $classname$::$name$() const {\n"
       "  // @@protoc_insertion_point(field_get:$full_name$)\n"
       "  // @@protoc_insertion_point(field_get:$full_name$)\n"
       "  return $name$_.GetNoArena($default_variable$);\n"
       "  return $name$_.GetNoArena($default_variable$);\n"
       "}\n"
       "}\n"
-      "inline void $classname$::set_$name$(const ::std::string& value) {\n"
+      "$inline$ void $classname$::set_$name$(const ::std::string& value) {\n"
       "  $set_hasbit$\n"
       "  $set_hasbit$\n"
       "  $name$_.SetNoArena($default_variable$, value);\n"
       "  $name$_.SetNoArena($default_variable$, value);\n"
       "  // @@protoc_insertion_point(field_set:$full_name$)\n"
       "  // @@protoc_insertion_point(field_set:$full_name$)\n"
       "}\n"
       "}\n"
-      "inline void $classname$::set_$name$(const char* value) {\n"
+      "$inline$ void $classname$::set_$name$(const char* value) {\n"
       "  $set_hasbit$\n"
       "  $set_hasbit$\n"
       "  $name$_.SetNoArena($default_variable$, $string_piece$(value));\n"
       "  $name$_.SetNoArena($default_variable$, $string_piece$(value));\n"
       "  // @@protoc_insertion_point(field_set_char:$full_name$)\n"
       "  // @@protoc_insertion_point(field_set_char:$full_name$)\n"
       "}\n"
       "}\n"
-      "inline "
+      "$inline$ "
       "void $classname$::set_$name$(const $pointer_type$* value, "
       "void $classname$::set_$name$(const $pointer_type$* value, "
       "size_t size) {\n"
       "size_t size) {\n"
       "  $set_hasbit$\n"
       "  $set_hasbit$\n"
@@ -249,16 +256,16 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
       "      $string_piece$(reinterpret_cast<const char*>(value), size));\n"
       "      $string_piece$(reinterpret_cast<const char*>(value), size));\n"
       "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
       "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
       "}\n"
       "}\n"
-      "inline ::std::string* $classname$::mutable_$name$() {\n"
+      "$inline$ ::std::string* $classname$::mutable_$name$() {\n"
       "  $set_hasbit$\n"
       "  $set_hasbit$\n"
       "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
       "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
       "  return $name$_.MutableNoArena($default_variable$);\n"
       "  return $name$_.MutableNoArena($default_variable$);\n"
       "}\n"
       "}\n"
-      "inline ::std::string* $classname$::$release_name$() {\n"
+      "$inline$ ::std::string* $classname$::$release_name$() {\n"
       "  $clear_hasbit$\n"
       "  $clear_hasbit$\n"
       "  return $name$_.ReleaseNoArena($default_variable$);\n"
       "  return $name$_.ReleaseNoArena($default_variable$);\n"
       "}\n"
       "}\n"
-      "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
+      "$inline$ void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
       "  if ($name$ != NULL) {\n"
       "  if ($name$ != NULL) {\n"
       "    $set_hasbit$\n"
       "    $set_hasbit$\n"
       "  } else {\n"
       "  } else {\n"
@@ -422,17 +429,20 @@ StringOneofFieldGenerator(const FieldDescriptor* descriptor,
 StringOneofFieldGenerator::~StringOneofFieldGenerator() {}
 StringOneofFieldGenerator::~StringOneofFieldGenerator() {}
 
 
 void StringOneofFieldGenerator::
 void StringOneofFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                  bool is_inline) const {
+  map<string, string> variables(variables_);
+  variables["inline"] = is_inline ? "inline" : "";
   if (SupportsArenas(descriptor_)) {
   if (SupportsArenas(descriptor_)) {
-    printer->Print(variables_,
-      "inline const ::std::string& $classname$::$name$() const {\n"
+    printer->Print(variables,
+      "$inline$ const ::std::string& $classname$::$name$() const {\n"
       "  // @@protoc_insertion_point(field_get:$full_name$)\n"
       "  // @@protoc_insertion_point(field_get:$full_name$)\n"
       "  if (has_$name$()) {\n"
       "  if (has_$name$()) {\n"
       "    return $oneof_prefix$$name$_.Get($default_variable$);\n"
       "    return $oneof_prefix$$name$_.Get($default_variable$);\n"
       "  }\n"
       "  }\n"
       "  return *$default_variable$;\n"
       "  return *$default_variable$;\n"
       "}\n"
       "}\n"
-      "inline void $classname$::set_$name$(const ::std::string& value) {\n"
+      "$inline$ void $classname$::set_$name$(const ::std::string& value) {\n"
       "  if (!has_$name$()) {\n"
       "  if (!has_$name$()) {\n"
       "    clear_$oneof_name$();\n"
       "    clear_$oneof_name$();\n"
       "    set_has_$name$();\n"
       "    set_has_$name$();\n"
@@ -442,7 +452,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
       "      GetArenaNoVirtual());\n"
       "      GetArenaNoVirtual());\n"
       "  // @@protoc_insertion_point(field_set:$full_name$)\n"
       "  // @@protoc_insertion_point(field_set:$full_name$)\n"
       "}\n"
       "}\n"
-      "inline void $classname$::set_$name$(const char* value) {\n"
+      "$inline$ void $classname$::set_$name$(const char* value) {\n"
       "  if (!has_$name$()) {\n"
       "  if (!has_$name$()) {\n"
       "    clear_$oneof_name$();\n"
       "    clear_$oneof_name$();\n"
       "    set_has_$name$();\n"
       "    set_has_$name$();\n"
@@ -452,7 +462,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
       "      $string_piece$(value), GetArenaNoVirtual());\n"
       "      $string_piece$(value), GetArenaNoVirtual());\n"
       "  // @@protoc_insertion_point(field_set_char:$full_name$)\n"
       "  // @@protoc_insertion_point(field_set_char:$full_name$)\n"
       "}\n"
       "}\n"
-      "inline "
+      "$inline$ "
       "void $classname$::set_$name$(const $pointer_type$* value,\n"
       "void $classname$::set_$name$(const $pointer_type$* value,\n"
       "                             size_t size) {\n"
       "                             size_t size) {\n"
       "  if (!has_$name$()) {\n"
       "  if (!has_$name$()) {\n"
@@ -465,7 +475,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
       "      GetArenaNoVirtual());\n"
       "      GetArenaNoVirtual());\n"
       "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
       "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
       "}\n"
       "}\n"
-      "inline ::std::string* $classname$::mutable_$name$() {\n"
+      "$inline$ ::std::string* $classname$::mutable_$name$() {\n"
       "  if (!has_$name$()) {\n"
       "  if (!has_$name$()) {\n"
       "    clear_$oneof_name$();\n"
       "    clear_$oneof_name$();\n"
       "    set_has_$name$();\n"
       "    set_has_$name$();\n"
@@ -475,7 +485,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
       "      GetArenaNoVirtual());\n"
       "      GetArenaNoVirtual());\n"
       "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
       "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
       "}\n"
       "}\n"
-      "inline ::std::string* $classname$::$release_name$() {\n"
+      "$inline$ ::std::string* $classname$::$release_name$() {\n"
       "  if (has_$name$()) {\n"
       "  if (has_$name$()) {\n"
       "    clear_has_$oneof_name$();\n"
       "    clear_has_$oneof_name$();\n"
       "    return $oneof_prefix$$name$_.Release($default_variable$,\n"
       "    return $oneof_prefix$$name$_.Release($default_variable$,\n"
@@ -484,7 +494,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
       "    return NULL;\n"
       "    return NULL;\n"
       "  }\n"
       "  }\n"
       "}\n"
       "}\n"
-      "inline ::std::string* $classname$::unsafe_arena_release_$name$() {\n"
+      "$inline$ ::std::string* $classname$::unsafe_arena_release_$name$() {\n"
       "  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n"
       "  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n"
       "  if (has_$name$()) {\n"
       "  if (has_$name$()) {\n"
       "    clear_has_$oneof_name$();\n"
       "    clear_has_$oneof_name$();\n"
@@ -494,7 +504,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
       "    return NULL;\n"
       "    return NULL;\n"
       "  }\n"
       "  }\n"
       "}\n"
       "}\n"
-      "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
+      "$inline$ void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
       "  if (!has_$name$()) {\n"
       "  if (!has_$name$()) {\n"
       "    $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
       "    $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
       "  }\n"
       "  }\n"
@@ -506,7 +516,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
       "  }\n"
       "  }\n"
       "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
       "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
       "}\n"
       "}\n"
-      "inline void $classname$::unsafe_arena_set_allocated_$name$("
+      "$inline$ void $classname$::unsafe_arena_set_allocated_$name$("
       "::std::string* $name$) {\n"
       "::std::string* $name$) {\n"
       "  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n"
       "  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n"
       "  if (!has_$name$()) {\n"
       "  if (!has_$name$()) {\n"
@@ -522,15 +532,15 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
       "}\n");
       "}\n");
   } else {
   } else {
     // No-arena case.
     // No-arena case.
-    printer->Print(variables_,
-      "inline const ::std::string& $classname$::$name$() const {\n"
+    printer->Print(variables,
+      "$inline$ const ::std::string& $classname$::$name$() const {\n"
       "  // @@protoc_insertion_point(field_get:$full_name$)\n"
       "  // @@protoc_insertion_point(field_get:$full_name$)\n"
       "  if (has_$name$()) {\n"
       "  if (has_$name$()) {\n"
       "    return $oneof_prefix$$name$_.GetNoArena($default_variable$);\n"
       "    return $oneof_prefix$$name$_.GetNoArena($default_variable$);\n"
       "  }\n"
       "  }\n"
       "  return *$default_variable$;\n"
       "  return *$default_variable$;\n"
       "}\n"
       "}\n"
-      "inline void $classname$::set_$name$(const ::std::string& value) {\n"
+      "$inline$ void $classname$::set_$name$(const ::std::string& value) {\n"
       "  // @@protoc_insertion_point(field_set:$full_name$)\n"
       "  // @@protoc_insertion_point(field_set:$full_name$)\n"
       "  if (!has_$name$()) {\n"
       "  if (!has_$name$()) {\n"
       "    clear_$oneof_name$();\n"
       "    clear_$oneof_name$();\n"
@@ -540,7 +550,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
       "  $oneof_prefix$$name$_.SetNoArena($default_variable$, value);\n"
       "  $oneof_prefix$$name$_.SetNoArena($default_variable$, value);\n"
       "  // @@protoc_insertion_point(field_set:$full_name$)\n"
       "  // @@protoc_insertion_point(field_set:$full_name$)\n"
       "}\n"
       "}\n"
-      "inline void $classname$::set_$name$(const char* value) {\n"
+      "$inline$ void $classname$::set_$name$(const char* value) {\n"
       "  if (!has_$name$()) {\n"
       "  if (!has_$name$()) {\n"
       "    clear_$oneof_name$();\n"
       "    clear_$oneof_name$();\n"
       "    set_has_$name$();\n"
       "    set_has_$name$();\n"
@@ -550,7 +560,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
       "      $string_piece$(value));\n"
       "      $string_piece$(value));\n"
       "  // @@protoc_insertion_point(field_set_char:$full_name$)\n"
       "  // @@protoc_insertion_point(field_set_char:$full_name$)\n"
       "}\n"
       "}\n"
-      "inline "
+      "$inline$ "
       "void $classname$::set_$name$(const $pointer_type$* value, size_t size) {\n"
       "void $classname$::set_$name$(const $pointer_type$* value, size_t size) {\n"
       "  if (!has_$name$()) {\n"
       "  if (!has_$name$()) {\n"
       "    clear_$oneof_name$();\n"
       "    clear_$oneof_name$();\n"
@@ -561,7 +571,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
       "      reinterpret_cast<const char*>(value), size));\n"
       "      reinterpret_cast<const char*>(value), size));\n"
       "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
       "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
       "}\n"
       "}\n"
-      "inline ::std::string* $classname$::mutable_$name$() {\n"
+      "$inline$ ::std::string* $classname$::mutable_$name$() {\n"
       "  if (!has_$name$()) {\n"
       "  if (!has_$name$()) {\n"
       "    clear_$oneof_name$();\n"
       "    clear_$oneof_name$();\n"
       "    set_has_$name$();\n"
       "    set_has_$name$();\n"
@@ -570,7 +580,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
       "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
       "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
       "  return $oneof_prefix$$name$_.MutableNoArena($default_variable$);\n"
       "  return $oneof_prefix$$name$_.MutableNoArena($default_variable$);\n"
       "}\n"
       "}\n"
-      "inline ::std::string* $classname$::$release_name$() {\n"
+      "$inline$ ::std::string* $classname$::$release_name$() {\n"
       "  if (has_$name$()) {\n"
       "  if (has_$name$()) {\n"
       "    clear_has_$oneof_name$();\n"
       "    clear_has_$oneof_name$();\n"
       "    return $oneof_prefix$$name$_.ReleaseNoArena($default_variable$);\n"
       "    return $oneof_prefix$$name$_.ReleaseNoArena($default_variable$);\n"
@@ -578,7 +588,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
       "    return NULL;\n"
       "    return NULL;\n"
       "  }\n"
       "  }\n"
       "}\n"
       "}\n"
-      "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
+      "$inline$ void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
       "  if (!has_$name$()) {\n"
       "  if (!has_$name$()) {\n"
       "    $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
       "    $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
       "  }\n"
       "  }\n"
@@ -670,7 +680,10 @@ GeneratePrivateMembers(io::Printer* printer) const {
 void RepeatedStringFieldGenerator::
 void RepeatedStringFieldGenerator::
 GenerateAccessorDeclarations(io::Printer* printer) const {
 GenerateAccessorDeclarations(io::Printer* printer) const {
   // See comment above about unknown ctypes.
   // See comment above about unknown ctypes.
-  if (descriptor_->options().ctype() != FieldOptions::STRING) {
+  bool unknown_ctype =
+      descriptor_->options().ctype() != EffectiveStringCType(descriptor_);
+
+  if (unknown_ctype) {
     printer->Outdent();
     printer->Outdent();
     printer->Print(
     printer->Print(
       " private:\n"
       " private:\n"
@@ -679,26 +692,26 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
   }
   }
 
 
   printer->Print(variables_,
   printer->Print(variables_,
-    "inline const ::std::string& $name$(int index) const$deprecation$;\n"
-    "inline ::std::string* mutable_$name$(int index)$deprecation$;\n"
-    "inline void set_$name$(int index, const ::std::string& value)$deprecation$;\n"
-    "inline void set_$name$(int index, const char* value)$deprecation$;\n"
-    "inline "
+    "const ::std::string& $name$(int index) const$deprecation$;\n"
+    "::std::string* mutable_$name$(int index)$deprecation$;\n"
+    "void set_$name$(int index, const ::std::string& value)$deprecation$;\n"
+    "void set_$name$(int index, const char* value)$deprecation$;\n"
+    ""
     "void set_$name$(int index, const $pointer_type$* value, size_t size)"
     "void set_$name$(int index, const $pointer_type$* value, size_t size)"
                  "$deprecation$;\n"
                  "$deprecation$;\n"
-    "inline ::std::string* add_$name$()$deprecation$;\n"
-    "inline void add_$name$(const ::std::string& value)$deprecation$;\n"
-    "inline void add_$name$(const char* value)$deprecation$;\n"
-    "inline void add_$name$(const $pointer_type$* value, size_t size)"
+    "::std::string* add_$name$()$deprecation$;\n"
+    "void add_$name$(const ::std::string& value)$deprecation$;\n"
+    "void add_$name$(const char* value)$deprecation$;\n"
+    "void add_$name$(const $pointer_type$* value, size_t size)"
                  "$deprecation$;\n");
                  "$deprecation$;\n");
 
 
   printer->Print(variables_,
   printer->Print(variables_,
-    "inline const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() const"
+    "const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() const"
                  "$deprecation$;\n"
                  "$deprecation$;\n"
-    "inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_$name$()"
+    "::google::protobuf::RepeatedPtrField< ::std::string>* mutable_$name$()"
                  "$deprecation$;\n");
                  "$deprecation$;\n");
 
 
-  if (descriptor_->options().ctype() != FieldOptions::STRING) {
+  if (unknown_ctype) {
     printer->Outdent();
     printer->Outdent();
     printer->Print(" public:\n");
     printer->Print(" public:\n");
     printer->Indent();
     printer->Indent();
@@ -706,54 +719,57 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
 }
 }
 
 
 void RepeatedStringFieldGenerator::
 void RepeatedStringFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
-  printer->Print(variables_,
-    "inline const ::std::string& $classname$::$name$(int index) const {\n"
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                  bool is_inline) const {
+  map<string, string> variables(variables_);
+  variables["inline"] = is_inline ? "inline" : "";
+  printer->Print(variables,
+    "$inline$ const ::std::string& $classname$::$name$(int index) const {\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  return $name$_.$cppget$(index);\n"
     "  return $name$_.$cppget$(index);\n"
     "}\n"
     "}\n"
-    "inline ::std::string* $classname$::mutable_$name$(int index) {\n"
+    "$inline$ ::std::string* $classname$::mutable_$name$(int index) {\n"
     "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
     "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
     "  return $name$_.Mutable(index);\n"
     "  return $name$_.Mutable(index);\n"
     "}\n"
     "}\n"
-    "inline void $classname$::set_$name$(int index, const ::std::string& value) {\n"
+    "$inline$ void $classname$::set_$name$(int index, const ::std::string& value) {\n"
     "  // @@protoc_insertion_point(field_set:$full_name$)\n"
     "  // @@protoc_insertion_point(field_set:$full_name$)\n"
     "  $name$_.Mutable(index)->assign(value);\n"
     "  $name$_.Mutable(index)->assign(value);\n"
     "}\n"
     "}\n"
-    "inline void $classname$::set_$name$(int index, const char* value) {\n"
+    "$inline$ void $classname$::set_$name$(int index, const char* value) {\n"
     "  $name$_.Mutable(index)->assign(value);\n"
     "  $name$_.Mutable(index)->assign(value);\n"
     "  // @@protoc_insertion_point(field_set_char:$full_name$)\n"
     "  // @@protoc_insertion_point(field_set_char:$full_name$)\n"
     "}\n"
     "}\n"
-    "inline void "
+    "$inline$ void "
     "$classname$::set_$name$"
     "$classname$::set_$name$"
     "(int index, const $pointer_type$* value, size_t size) {\n"
     "(int index, const $pointer_type$* value, size_t size) {\n"
     "  $name$_.Mutable(index)->assign(\n"
     "  $name$_.Mutable(index)->assign(\n"
     "    reinterpret_cast<const char*>(value), size);\n"
     "    reinterpret_cast<const char*>(value), size);\n"
     "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
     "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
     "}\n"
     "}\n"
-    "inline ::std::string* $classname$::add_$name$() {\n"
+    "$inline$ ::std::string* $classname$::add_$name$() {\n"
     "  return $name$_.Add();\n"
     "  return $name$_.Add();\n"
     "}\n"
     "}\n"
-    "inline void $classname$::add_$name$(const ::std::string& value) {\n"
+    "$inline$ void $classname$::add_$name$(const ::std::string& value) {\n"
     "  $name$_.Add()->assign(value);\n"
     "  $name$_.Add()->assign(value);\n"
     "  // @@protoc_insertion_point(field_add:$full_name$)\n"
     "  // @@protoc_insertion_point(field_add:$full_name$)\n"
     "}\n"
     "}\n"
-    "inline void $classname$::add_$name$(const char* value) {\n"
+    "$inline$ void $classname$::add_$name$(const char* value) {\n"
     "  $name$_.Add()->assign(value);\n"
     "  $name$_.Add()->assign(value);\n"
     "  // @@protoc_insertion_point(field_add_char:$full_name$)\n"
     "  // @@protoc_insertion_point(field_add_char:$full_name$)\n"
     "}\n"
     "}\n"
-    "inline void "
+    "$inline$ void "
     "$classname$::add_$name$(const $pointer_type$* value, size_t size) {\n"
     "$classname$::add_$name$(const $pointer_type$* value, size_t size) {\n"
     "  $name$_.Add()->assign(reinterpret_cast<const char*>(value), size);\n"
     "  $name$_.Add()->assign(reinterpret_cast<const char*>(value), size);\n"
     "  // @@protoc_insertion_point(field_add_pointer:$full_name$)\n"
     "  // @@protoc_insertion_point(field_add_pointer:$full_name$)\n"
     "}\n");
     "}\n");
-  printer->Print(variables_,
-    "inline const ::google::protobuf::RepeatedPtrField< ::std::string>&\n"
+  printer->Print(variables,
+    "$inline$ const ::google::protobuf::RepeatedPtrField< ::std::string>&\n"
     "$classname$::$name$() const {\n"
     "$classname$::$name$() const {\n"
     "  // @@protoc_insertion_point(field_list:$full_name$)\n"
     "  // @@protoc_insertion_point(field_list:$full_name$)\n"
     "  return $name$_;\n"
     "  return $name$_;\n"
     "}\n"
     "}\n"
-    "inline ::google::protobuf::RepeatedPtrField< ::std::string>*\n"
+    "$inline$ ::google::protobuf::RepeatedPtrField< ::std::string>*\n"
     "$classname$::mutable_$name$() {\n"
     "$classname$::mutable_$name$() {\n"
     "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
     "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
     "  return &$name$_;\n"
     "  return &$name$_;\n"

+ 6 - 3
src/google/protobuf/compiler/cpp/cpp_string_field.h

@@ -54,7 +54,8 @@ class StringFieldGenerator : public FieldGenerator {
   void GeneratePrivateMembers(io::Printer* printer) const;
   void GeneratePrivateMembers(io::Printer* printer) const;
   void GenerateStaticMembers(io::Printer* printer) const;
   void GenerateStaticMembers(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
-  void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                         bool is_inline) const;
   void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const;
   void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
@@ -83,7 +84,8 @@ class StringOneofFieldGenerator : public StringFieldGenerator {
   ~StringOneofFieldGenerator();
   ~StringOneofFieldGenerator();
 
 
   // implements FieldGenerator ---------------------------------------
   // implements FieldGenerator ---------------------------------------
-  void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                         bool is_inline) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
   void GenerateConstructorCode(io::Printer* printer) const;
   void GenerateConstructorCode(io::Printer* printer) const;
@@ -103,7 +105,8 @@ class RepeatedStringFieldGenerator : public FieldGenerator {
   // implements FieldGenerator ---------------------------------------
   // implements FieldGenerator ---------------------------------------
   void GeneratePrivateMembers(io::Printer* printer) const;
   void GeneratePrivateMembers(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
-  void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
+  void GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                         bool is_inline) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;

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

@@ -83,6 +83,7 @@ class ImmutableFieldGenerator {
   virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0;
   virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0;
   virtual void GenerateFieldBuilderInitializationCode(io::Printer* printer)
   virtual void GenerateFieldBuilderInitializationCode(io::Printer* printer)
       const = 0;
       const = 0;
+  virtual void GenerateStaticInitializationCode(io::Printer* printer) const {}
 
 
   virtual void GenerateEqualsCode(io::Printer* printer) const = 0;
   virtual void GenerateEqualsCode(io::Printer* printer) const = 0;
   virtual void GenerateHashCode(io::Printer* printer) const = 0;
   virtual void GenerateHashCode(io::Printer* printer) const = 0;

+ 2 - 2
src/google/protobuf/compiler/java/java_helpers.cc

@@ -690,8 +690,8 @@ const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) {
   for (int i = 0; i < descriptor->field_count(); i++) {
   for (int i = 0; i < descriptor->field_count(); i++) {
     fields[i] = descriptor->field(i);
     fields[i] = descriptor->field(i);
   }
   }
-  sort(fields, fields + descriptor->field_count(),
-       FieldOrderingByNumber());
+  std::sort(fields, fields + descriptor->field_count(),
+            FieldOrderingByNumber());
   return fields;
   return fields;
 }
 }
 
 

+ 10 - 0
src/google/protobuf/compiler/java/java_helpers.h

@@ -297,6 +297,16 @@ struct ExtensionRangeOrdering {
 // and return it. The caller should delete the returned array.
 // and return it. The caller should delete the returned array.
 const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor);
 const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor);
 
 
+// Does this message class have any packed fields?
+inline bool HasPackedFields(const Descriptor* descriptor) {
+  for (int i = 0; i < descriptor->field_count(); i++) {
+    if (descriptor->field(i)->is_packed()) {
+      return true;
+    }
+  }
+  return false;
+}
+
 // Check a message type and its sub-message types recursively to see if any of
 // Check a message type and its sub-message types recursively to see if any of
 // them has a required field. Return true if a required field is found.
 // them has a required field. Return true if a required field is found.
 bool HasRequiredFields(const Descriptor* descriptor);
 bool HasRequiredFields(const Descriptor* descriptor);

+ 4 - 6
src/google/protobuf/compiler/java/java_lazy_message_field.cc

@@ -243,9 +243,8 @@ GenerateBuildingCode(io::Printer* printer) const {
       "}\n");
       "}\n");
 
 
   printer->Print(variables_,
   printer->Print(variables_,
-      "result.$name$_.setByteString(\n"
-      "    $name$_.toByteString(),\n"
-      "    $name$_.getExtensionRegistry());\n");
+      "result.$name$_.set(\n"
+      "    $name$_);\n");
 }
 }
 
 
 void ImmutableLazyMessageFieldGenerator::
 void ImmutableLazyMessageFieldGenerator::
@@ -425,9 +424,8 @@ GenerateBuildingCode(io::Printer* printer) const {
 
 
   printer->Print(variables_,
   printer->Print(variables_,
       "result.$oneof_name$_ = new $lazy_type$();\n"
       "result.$oneof_name$_ = new $lazy_type$();\n"
-      "(($lazy_type$) result.$oneof_name$_).setByteString(\n"
-      "    (($lazy_type$) $oneof_name$_).toByteString(),\n"
-      "    (($lazy_type$) $oneof_name$_).getExtensionRegistry());\n");
+      "(($lazy_type$) result.$oneof_name$_).set(\n"
+      "    (($lazy_type$) $oneof_name$_));\n");
   printer->Outdent();
   printer->Outdent();
   printer->Print("}\n");
   printer->Print("}\n");
 }
 }

+ 65 - 36
src/google/protobuf/compiler/java/java_map_field.cc

@@ -197,26 +197,39 @@ GenerateInterfaceMembers(io::Printer* printer) const {
   }
   }
 }
 }
 
 
+void ImmutableMapFieldGenerator::
+GenerateStaticInitializationCode(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "$name$DefaultEntry =\n"
+      "    com.google.protobuf.MapEntry$lite$\n"
+      "    .<$type_parameters$>newDefaultInstance(\n"
+      "        $descriptor$\n"
+      "        $key_wire_type$,\n"
+      "        $key_default_value$,\n"
+      "        $value_wire_type$,\n"
+      "        $value_default_value$);\n"
+      "\n");
+}
+
 void ImmutableMapFieldGenerator::
 void ImmutableMapFieldGenerator::
 GenerateMembers(io::Printer* printer) const {
 GenerateMembers(io::Printer* printer) const {
   printer->Print(
   printer->Print(
       variables_,
       variables_,
       "private static final com.google.protobuf.MapEntry$lite$<\n"
       "private static final com.google.protobuf.MapEntry$lite$<\n"
-      "    $type_parameters$> $name$DefaultEntry =\n"
-      "        com.google.protobuf.MapEntry$lite$\n"
-      "        .<$type_parameters$>newDefaultInstance(\n"
-      "            $descriptor$\n"
-      "            $key_wire_type$,\n"
-      "            $key_default_value$,\n"
-      "            $value_wire_type$,\n"
-      "            $value_default_value$);\n");
+      "    $type_parameters$> $name$DefaultEntry;\n");
   printer->Print(
   printer->Print(
       variables_,
       variables_,
       "private com.google.protobuf.MapField$lite$<\n"
       "private com.google.protobuf.MapField$lite$<\n"
-      "    $type_parameters$> $name$_ =\n"
-      "        com.google.protobuf.MapField$lite$.emptyMapField(\n"
-      "            $map_field_parameter$);\n"
-      "\n");
+      "    $type_parameters$> $name$_;\n"
+      "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
+      "internalGet$capitalized_name$() {\n"
+      "  if ($name$_ == null) {\n"
+      "    return com.google.protobuf.MapField$lite$.emptyMapField(\n"
+      "        $map_field_parameter$);\n"
+      " }\n"
+      "  return $name$_;\n"
+      "}\n");
   if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
   if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
     printer->Print(
     printer->Print(
         variables_,
         variables_,
@@ -233,7 +246,7 @@ GenerateMembers(io::Printer* printer) const {
           "$deprecation$\n"
           "$deprecation$\n"
           "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
           "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
           "get$capitalized_name$Value() {\n"
           "get$capitalized_name$Value() {\n"
-          "  return $name$_.getMap();\n"
+          "  return internalGet$capitalized_name$().getMap();\n"
           "}\n");
           "}\n");
     }
     }
     WriteFieldDocComment(printer, descriptor_);
     WriteFieldDocComment(printer, descriptor_);
@@ -244,7 +257,8 @@ GenerateMembers(io::Printer* printer) const {
         "get$capitalized_name$() {\n"
         "get$capitalized_name$() {\n"
         "  return new com.google.protobuf.Internal.MapAdapter<\n"
         "  return new com.google.protobuf.Internal.MapAdapter<\n"
         "      $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
         "      $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
-        "          $name$_.getMap(), $name$ValueConverter);\n"
+        "          internalGet$capitalized_name$().getMap(),\n"
+        "          $name$ValueConverter);\n"
         "}\n");
         "}\n");
   } else {
   } else {
     WriteFieldDocComment(printer, descriptor_);
     WriteFieldDocComment(printer, descriptor_);
@@ -252,7 +266,7 @@ GenerateMembers(io::Printer* printer) const {
         variables_,
         variables_,
         "$deprecation$\n"
         "$deprecation$\n"
         "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
         "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
-        "  return $name$_.getMap();\n"
+        "  return internalGet$capitalized_name$().getMap();\n"
         "}\n");
         "}\n");
   }
   }
 }
 }
@@ -262,10 +276,24 @@ GenerateBuilderMembers(io::Printer* printer) const {
   printer->Print(
   printer->Print(
       variables_,
       variables_,
       "private com.google.protobuf.MapField$lite$<\n"
       "private com.google.protobuf.MapField$lite$<\n"
-      "    $type_parameters$> $name$_ =\n"
-      "        com.google.protobuf.MapField$lite$.newMapField(\n"
-      "            $map_field_parameter$);\n"
-      "\n");
+      "    $type_parameters$> $name$_;\n"
+      "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
+      "internalGet$capitalized_name$() {\n"
+      "  if ($name$_ == null) {\n"
+      "    return com.google.protobuf.MapField$lite$.emptyMapField(\n"
+      "        $map_field_parameter$);\n"
+      " }\n"
+      "  return $name$_;\n"
+      "}\n"
+      "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
+      "internalGetMutable$capitalized_name$() {\n"
+      "  $on_changed$;\n"
+      "  if ($name$_ == null) {\n"
+      "    $name$_ = com.google.protobuf.MapField$lite$.newMapField(\n"
+      "        $map_field_parameter$);\n"
+      " }\n"
+      "  return $name$_;\n"
+      "}\n");
   if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
   if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
     WriteFieldDocComment(printer, descriptor_);
     WriteFieldDocComment(printer, descriptor_);
     printer->Print(
     printer->Print(
@@ -275,7 +303,8 @@ GenerateBuilderMembers(io::Printer* printer) const {
         "get$capitalized_name$() {\n"
         "get$capitalized_name$() {\n"
         "  return new com.google.protobuf.Internal.MapAdapter<\n"
         "  return new com.google.protobuf.Internal.MapAdapter<\n"
         "      $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
         "      $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
-        "          $name$_.getMap(), $name$ValueConverter);\n"
+        "          internalGet$capitalized_name$().getMap(),\n"
+        "          $name$ValueConverter);\n"
         "}\n");
         "}\n");
     WriteFieldDocComment(printer, descriptor_);
     WriteFieldDocComment(printer, descriptor_);
     printer->Print(
     printer->Print(
@@ -283,10 +312,10 @@ GenerateBuilderMembers(io::Printer* printer) const {
         "$deprecation$\n"
         "$deprecation$\n"
         "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
         "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
         "getMutable$capitalized_name$() {\n"
         "getMutable$capitalized_name$() {\n"
-        "  $on_changed$\n"
         "  return new com.google.protobuf.Internal.MapAdapter<\n"
         "  return new com.google.protobuf.Internal.MapAdapter<\n"
         "      $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
         "      $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
-        "          $name$_.getMutableMap(), $name$ValueConverter);\n"
+        "          internalGetMutable$capitalized_name$().getMutableMap(),\n"
+        "          $name$ValueConverter);\n"
         "}\n");
         "}\n");
     if (SupportUnknownEnumValue(descriptor_->file())) {
     if (SupportUnknownEnumValue(descriptor_->file())) {
       WriteFieldDocComment(printer, descriptor_);
       WriteFieldDocComment(printer, descriptor_);
@@ -295,7 +324,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
           "$deprecation$\n"
           "$deprecation$\n"
           "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
           "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
           "get$capitalized_name$Value() {\n"
           "get$capitalized_name$Value() {\n"
-          "  return $name$_.getMap();\n"
+          "  return internalGet$capitalized_name$().getMap();\n"
           "}\n");
           "}\n");
       WriteFieldDocComment(printer, descriptor_);
       WriteFieldDocComment(printer, descriptor_);
       printer->Print(
       printer->Print(
@@ -303,8 +332,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
           "$deprecation$\n"
           "$deprecation$\n"
           "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
           "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
           "getMutable$capitalized_name$Value() {\n"
           "getMutable$capitalized_name$Value() {\n"
-          "  $on_changed$\n"
-          "  return $name$_.getMutableMap();\n"
+          "  return internalGetMutable$capitalized_name$().getMutableMap();\n"
           "}\n");
           "}\n");
     }
     }
   } else {
   } else {
@@ -312,15 +340,14 @@ GenerateBuilderMembers(io::Printer* printer) const {
     printer->Print(
     printer->Print(
         variables_,
         variables_,
         "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
         "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
-        "  return $name$_.getMap();\n"
+        "  return internalGet$capitalized_name$().getMap();\n"
         "}\n");
         "}\n");
     WriteFieldDocComment(printer, descriptor_);
     WriteFieldDocComment(printer, descriptor_);
     printer->Print(
     printer->Print(
         variables_,
         variables_,
         "public java.util.Map<$type_parameters$>\n"
         "public java.util.Map<$type_parameters$>\n"
         "getMutable$capitalized_name$() {\n"
         "getMutable$capitalized_name$() {\n"
-        "  $on_changed$\n"
-        "  return $name$_.getMutableMap();\n"
+        "  return internalGetMutable$capitalized_name$().getMutableMap();\n"
         "}\n");
         "}\n");
   }
   }
 }
 }
@@ -339,14 +366,15 @@ void ImmutableMapFieldGenerator::
 GenerateBuilderClearCode(io::Printer* printer) const {
 GenerateBuilderClearCode(io::Printer* printer) const {
   printer->Print(
   printer->Print(
       variables_,
       variables_,
-      "$name$_.clear();\n");
+      "internalGetMutable$capitalized_name$().clear();\n");
 }
 }
 
 
 void ImmutableMapFieldGenerator::
 void ImmutableMapFieldGenerator::
 GenerateMergingCode(io::Printer* printer) const {
 GenerateMergingCode(io::Printer* printer) const {
   printer->Print(
   printer->Print(
       variables_,
       variables_,
-      "$name$_.mergeFrom(other.$name$_);\n");
+      "internalGetMutable$capitalized_name$().mergeFrom(\n"
+      "    other.internalGet$capitalized_name$());\n");
 }
 }
 
 
 void ImmutableMapFieldGenerator::
 void ImmutableMapFieldGenerator::
@@ -356,7 +384,7 @@ GenerateBuildingCode(io::Printer* printer) const {
       // We do a copy of the map field to ensure that the built result is
       // We do a copy of the map field to ensure that the built result is
       // immutable. Implementation of this copy() method can do copy-on-write
       // immutable. Implementation of this copy() method can do copy-on-write
       // to defer this copy until further modifications are made on the field.
       // to defer this copy until further modifications are made on the field.
-      "result.$name$_ = $name$_.copy();\n");
+      "result.$name$_ = internalGet$capitalized_name$().copy();\n");
 }
 }
 
 
 void ImmutableMapFieldGenerator::
 void ImmutableMapFieldGenerator::
@@ -402,7 +430,7 @@ GenerateSerializationCode(io::Printer* printer) const {
   printer->Print(
   printer->Print(
       variables_,
       variables_,
       "for (java.util.Map.Entry<$type_parameters$> entry\n"
       "for (java.util.Map.Entry<$type_parameters$> entry\n"
-      "     : $name$_.getMap().entrySet()) {\n"
+      "     : internalGet$capitalized_name$().getMap().entrySet()) {\n"
       "  com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
       "  com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
       "  $name$ = $name$DefaultEntry.newBuilderForType()\n"
       "  $name$ = $name$DefaultEntry.newBuilderForType()\n"
       "      .setKey(entry.getKey())\n"
       "      .setKey(entry.getKey())\n"
@@ -417,7 +445,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
   printer->Print(
   printer->Print(
       variables_,
       variables_,
       "for (java.util.Map.Entry<$type_parameters$> entry\n"
       "for (java.util.Map.Entry<$type_parameters$> entry\n"
-      "     : $name$_.getMap().entrySet()) {\n"
+      "     : internalGet$capitalized_name$().getMap().entrySet()) {\n"
       "  com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
       "  com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
       "  $name$ = $name$DefaultEntry.newBuilderForType()\n"
       "  $name$ = $name$DefaultEntry.newBuilderForType()\n"
       "      .setKey(entry.getKey())\n"
       "      .setKey(entry.getKey())\n"
@@ -432,16 +460,17 @@ void ImmutableMapFieldGenerator::
 GenerateEqualsCode(io::Printer* printer) const {
 GenerateEqualsCode(io::Printer* printer) const {
   printer->Print(
   printer->Print(
       variables_,
       variables_,
-      "result = result && $name$_.equals(other.$name$_);\n");
+      "result = result && internalGet$capitalized_name$().equals(\n"
+      "    other.internalGet$capitalized_name$());\n");
 }
 }
 
 
 void ImmutableMapFieldGenerator::
 void ImmutableMapFieldGenerator::
 GenerateHashCode(io::Printer* printer) const {
 GenerateHashCode(io::Printer* printer) const {
   printer->Print(
   printer->Print(
       variables_,
       variables_,
-      "if (!$name$_.getMap().isEmpty()) {\n"
+      "if (!internalGet$capitalized_name$().getMap().isEmpty()) {\n"
       "  hash = (37 * hash) + $constant_name$;\n"
       "  hash = (37 * hash) + $constant_name$;\n"
-      "  hash = (53 * hash) + $name$_.hashCode();\n"
+      "  hash = (53 * hash) + internalGet$capitalized_name$().hashCode();\n"
       "}\n");
       "}\n");
 }
 }
 
 

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

@@ -60,6 +60,7 @@ class ImmutableMapFieldGenerator : public ImmutableFieldGenerator {
   void GenerateSerializationCode(io::Printer* printer) const;
   void GenerateSerializationCode(io::Printer* printer) const;
   void GenerateSerializedSizeCode(io::Printer* printer) const;
   void GenerateSerializedSizeCode(io::Printer* printer) const;
   void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
   void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
+  void GenerateStaticInitializationCode(io::Printer* printer) const;
   void GenerateEqualsCode(io::Printer* printer) const;
   void GenerateEqualsCode(io::Printer* printer) const;
   void GenerateHashCode(io::Printer* printer) const;
   void GenerateHashCode(io::Printer* printer) const;
 
 

+ 201 - 83
src/google/protobuf/compiler/java/java_message.cc

@@ -234,7 +234,8 @@ void ImmutableMessageGenerator::GenerateInterface(io::Printer* printer) {
         "public interface $classname$OrBuilder extends \n"
         "public interface $classname$OrBuilder extends \n"
         "    $extra_interfaces$\n"
         "    $extra_interfaces$\n"
         "     com.google.protobuf.GeneratedMessageLite.\n"
         "     com.google.protobuf.GeneratedMessageLite.\n"
-        "          ExtendableMessageOrBuilder<$classname$> {\n",
+        "          ExtendableMessageOrBuilder<\n"
+        "              $classname$, $classname$.Builder> {\n",
         "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
         "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
         "classname", descriptor_->name());
         "classname", descriptor_->name());
     }
     }
@@ -285,22 +286,41 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) {
   // The builder_type stores the super type name of the nested Builder class.
   // The builder_type stores the super type name of the nested Builder class.
   string builder_type;
   string builder_type;
   if (descriptor_->extension_range_count() > 0) {
   if (descriptor_->extension_range_count() > 0) {
-    printer->Print(variables,
-      "public $static$final class $classname$ extends\n"
-      "    com.google.protobuf.GeneratedMessage$lite$.ExtendableMessage<\n"
-      "      $classname$> implements\n"
-      "    $extra_interfaces$\n"
-      "    $classname$OrBuilder {\n");
+    if (HasDescriptorMethods(descriptor_)) {
+      printer->Print(variables,
+        "public $static$final class $classname$ extends\n"
+        "    com.google.protobuf.GeneratedMessage.ExtendableMessage<\n"
+        "      $classname$> implements\n"
+        "    $extra_interfaces$\n"
+        "    $classname$OrBuilder {\n");
+    } else {
+      printer->Print(variables,
+        "public $static$final class $classname$ extends\n"
+        "    com.google.protobuf.GeneratedMessageLite.ExtendableMessage<\n"
+        "      $classname$, $classname$.Builder> implements\n"
+        "    $extra_interfaces$\n"
+        "    $classname$OrBuilder {\n");
+    }
     builder_type = strings::Substitute(
     builder_type = strings::Substitute(
-        "com.google.protobuf.GeneratedMessage$1.ExtendableBuilder<$0, ?>",
-        name_resolver_->GetImmutableClassName(descriptor_),
-        variables["lite"]);
+             "com.google.protobuf.GeneratedMessage$1.ExtendableBuilder<$0, ?>",
+             name_resolver_->GetImmutableClassName(descriptor_),
+             variables["lite"]);
   } else {
   } else {
-    printer->Print(variables,
-      "public $static$final class $classname$ extends\n"
-      "    com.google.protobuf.GeneratedMessage$lite$ implements\n"
-      "    $extra_interfaces$\n"
-      "    $classname$OrBuilder {\n");
+    if (HasDescriptorMethods(descriptor_)) {
+      printer->Print(variables,
+        "public $static$final class $classname$ extends\n"
+        "    com.google.protobuf.GeneratedMessage implements\n"
+        "    $extra_interfaces$\n"
+        "    $classname$OrBuilder {\n");
+    } else {
+      printer->Print(variables,
+              "public $static$final class $classname$ extends\n"
+              "    com.google.protobuf.GeneratedMessageLite<\n"
+              "        $classname$, $classname$.Builder> implements\n"
+              "    $extra_interfaces$\n"
+              "    $classname$OrBuilder {\n");
+    }
+
     builder_type = strings::Substitute(
     builder_type = strings::Substitute(
         "com.google.protobuf.GeneratedMessage$0.Builder",
         "com.google.protobuf.GeneratedMessage$0.Builder",
         variables["lite"]);
         variables["lite"]);
@@ -349,7 +369,7 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) {
     GenerateParsingConstructor(printer);
     GenerateParsingConstructor(printer);
   }
   }
 
 
-  GenerateDescriptorMethods(printer);
+  GenerateDescriptorMethods(printer, false);
   GenerateParser(printer);
   GenerateParser(printer);
 
 
   // Nested types
   // Nested types
@@ -481,7 +501,7 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) {
   // Carefully initialize the default instance in such a way that it doesn't
   // Carefully initialize the default instance in such a way that it doesn't
   // conflict with other initialization.
   // conflict with other initialization.
   printer->Print(
   printer->Print(
-    "private static final $classname$ defaultInstance;",
+    "private static final $classname$ defaultInstance;\n",
     "classname", name_resolver_->GetImmutableClassName(descriptor_));
     "classname", name_resolver_->GetImmutableClassName(descriptor_));
   if (HasDescriptorMethods(descriptor_)) {
   if (HasDescriptorMethods(descriptor_)) {
     printer->Print(
     printer->Print(
@@ -494,15 +514,11 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) {
     // LITE_RUNTIME only has one constructor.
     // LITE_RUNTIME only has one constructor.
     printer->Print(
     printer->Print(
       "static {\n"
       "static {\n"
-      "  try {\n"
-      "    defaultInstance = new $classname$(\n"
-      "        com.google.protobuf.Internal\n"
-      "            .EMPTY_CODED_INPUT_STREAM,\n"
-      "        com.google.protobuf.ExtensionRegistryLite\n"
-      "            .getEmptyRegistry());\n"
-      "  } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
-      "    throw new ExceptionInInitializerError(e);\n"
-      "  }\n"
+      "  defaultInstance = new $classname$(\n"
+      "      com.google.protobuf.Internal\n"
+      "          .EMPTY_CODED_INPUT_STREAM,\n"
+      "      com.google.protobuf.ExtensionRegistryLite\n"
+      "          .getEmptyRegistry());\n"
       "}\n"
       "}\n"
       "\n",
       "\n",
       "classname", descriptor_->name());
       "classname", descriptor_->name());
@@ -511,12 +527,30 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) {
       "public static $classname$ getDefaultInstance() {\n"
       "public static $classname$ getDefaultInstance() {\n"
       "  return defaultInstance;\n"
       "  return defaultInstance;\n"
       "}\n"
       "}\n"
-      "\n"
+      "\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  if (HasDescriptorMethods(descriptor_)) {
+    // LITE_RUNTIME implements this at the GeneratedMessageLite level.
+    printer->Print(
       "public $classname$ getDefaultInstanceForType() {\n"
       "public $classname$ getDefaultInstanceForType() {\n"
       "  return defaultInstance;\n"
       "  return defaultInstance;\n"
       "}\n"
       "}\n"
       "\n",
       "\n",
       "classname", name_resolver_->GetImmutableClassName(descriptor_));
       "classname", name_resolver_->GetImmutableClassName(descriptor_));
+  } else {
+    // LITE_RUNTIME uses this to implement the *ForType methods at the
+    // GeneratedMessageLite level.
+    printer->Print(
+      "static {"
+      "  com.google.protobuf.GeneratedMessageLite.onLoad(\n"
+      "      $classname$.class, new com.google.protobuf.GeneratedMessageLite\n"
+      "          .PrototypeHolder<$classname$, Builder>(\n"
+      "              defaultInstance, PARSER));"
+      "}\n"
+      "\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_));
+  }
 
 
   // Extensions must be declared after the defaultInstance is initialized
   // Extensions must be declared after the defaultInstance is initialized
   // because the defaultInstance is used by the extension to lazily retrieve
   // because the defaultInstance is used by the extension to lazily retrieve
@@ -526,6 +560,19 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) {
         .Generate(printer);
         .Generate(printer);
   }
   }
 
 
+  // Some fields also have static members that must be initialized after we
+  // have the default instance available.
+  printer->Print(
+      "static {\n");
+  printer->Indent();
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    field_generators_.get(descriptor_->field(i))
+        .GenerateStaticInitializationCode(printer);
+  }
+  printer->Outdent();
+  printer->Print(
+      "}\n");
+
   printer->Outdent();
   printer->Outdent();
   printer->Print("}\n\n");
   printer->Print("}\n\n");
 }
 }
@@ -542,37 +589,55 @@ GenerateMessageSerializationMethods(io::Printer* printer) {
   for (int i = 0; i < descriptor_->extension_range_count(); ++i) {
   for (int i = 0; i < descriptor_->extension_range_count(); ++i) {
     sorted_extensions.push_back(descriptor_->extension_range(i));
     sorted_extensions.push_back(descriptor_->extension_range(i));
   }
   }
-  sort(sorted_extensions.begin(), sorted_extensions.end(),
-       ExtensionRangeOrdering());
+  std::sort(sorted_extensions.begin(), sorted_extensions.end(),
+            ExtensionRangeOrdering());
 
 
   printer->Print(
   printer->Print(
     "public void writeTo(com.google.protobuf.CodedOutputStream output)\n"
     "public void writeTo(com.google.protobuf.CodedOutputStream output)\n"
     "                    throws java.io.IOException {\n");
     "                    throws java.io.IOException {\n");
   printer->Indent();
   printer->Indent();
-  // writeTo(CodedOutputStream output) might be invoked without
-  // getSerializedSize() ever being called, but we need the memoized
-  // sizes in case this message has packed fields. Rather than emit checks for
-  // each packed field, just call getSerializedSize() up front for all messages.
-  // In most cases, getSerializedSize() will have already been called anyway by
-  // one of the wrapper writeTo() methods, making this call cheap.
-  printer->Print(
-    "getSerializedSize();\n");
+  if (HasPackedFields(descriptor_)) {
+    // writeTo(CodedOutputStream output) might be invoked without
+    // getSerializedSize() ever being called, but we need the memoized
+    // sizes in case this message has packed fields. Rather than emit checks for
+    // each packed field, just call getSerializedSize() up front.
+    // In most cases, getSerializedSize() will have already been called anyway
+    // by one of the wrapper writeTo() methods, making this call cheap.
+    printer->Print(
+      "getSerializedSize();\n");
+  }
 
 
   if (descriptor_->extension_range_count() > 0) {
   if (descriptor_->extension_range_count() > 0) {
     if (descriptor_->options().message_set_wire_format()) {
     if (descriptor_->options().message_set_wire_format()) {
-      printer->Print(
-        "com.google.protobuf.GeneratedMessage$lite$\n"
-        "  .ExtendableMessage<$classname$>.ExtensionWriter extensionWriter =\n"
-        "    newMessageSetExtensionWriter();\n",
-        "lite", HasDescriptorMethods(descriptor_) ? "" : "Lite",
-        "classname", name_resolver_->GetImmutableClassName(descriptor_));
+      if (HasDescriptorMethods(descriptor_)) {
+        printer->Print(
+          "com.google.protobuf.GeneratedMessage\n"
+          "  .ExtendableMessage<$classname$>.ExtensionWriter\n"
+          "    extensionWriter = newMessageSetExtensionWriter();\n",
+          "classname", name_resolver_->GetImmutableClassName(descriptor_));
+      } else {
+        printer->Print(
+          "com.google.protobuf.GeneratedMessageLite\n"
+          "  .ExtendableMessage<$classname$, $classname$.Builder>\n"
+          "    .ExtensionWriter extensionWriter =\n"
+          "      newMessageSetExtensionWriter();\n",
+          "classname", name_resolver_->GetImmutableClassName(descriptor_));
+      }
     } else {
     } else {
-      printer->Print(
-        "com.google.protobuf.GeneratedMessage$lite$\n"
-        "  .ExtendableMessage<$classname$>.ExtensionWriter extensionWriter =\n"
-        "    newExtensionWriter();\n",
-        "lite", HasDescriptorMethods(descriptor_) ? "" : "Lite",
-        "classname", name_resolver_->GetImmutableClassName(descriptor_));
+      if (HasDescriptorMethods(descriptor_)) {
+        printer->Print(
+          "com.google.protobuf.GeneratedMessage\n"
+          "  .ExtendableMessage<$classname$>.ExtensionWriter\n"
+          "    extensionWriter = newExtensionWriter();\n",
+          "classname", name_resolver_->GetImmutableClassName(descriptor_));
+      } else {
+        printer->Print(
+          "com.google.protobuf.GeneratedMessageLite\n"
+          "  .ExtendableMessage<$classname$, $classname$.Builder>\n"
+          "    .ExtensionWriter extensionWriter =\n"
+          "      newExtensionWriter();\n",
+          "classname", name_resolver_->GetImmutableClassName(descriptor_));
+      }
     }
     }
   }
   }
 
 
@@ -727,13 +792,23 @@ void ImmutableMessageGenerator::GenerateSerializeOneExtensionRange(
 // ===================================================================
 // ===================================================================
 
 
 void ImmutableMessageGenerator::GenerateBuilder(io::Printer* printer) {
 void ImmutableMessageGenerator::GenerateBuilder(io::Printer* printer) {
+  if (HasDescriptorMethods(descriptor_)) {
+    // LITE_RUNTIME implements this at the GeneratedMessageLite level.
+    printer->Print(
+      "public Builder newBuilderForType() { return newBuilder(); }\n");
+  }
+
   printer->Print(
   printer->Print(
-    "public static Builder newBuilder() { return new Builder(); }\n"
-    "public Builder newBuilderForType() { return newBuilder(); }\n"
+    "public static Builder newBuilder() {\n"
+    "  return defaultInstance.toBuilder();\n"
+    "}\n"
     "public static Builder newBuilder($classname$ prototype) {\n"
     "public static Builder newBuilder($classname$ prototype) {\n"
-    "  return newBuilder().mergeFrom(prototype);\n"
+    "  return defaultInstance.toBuilder().mergeFrom(prototype);\n"
+    "}\n"
+    "public Builder toBuilder() {\n"
+    "  return this == defaultInstance\n"
+    "      ? new Builder() : new Builder().mergeFrom(this);\n"
     "}\n"
     "}\n"
-    "public Builder toBuilder() { return newBuilder(this); }\n"
     "\n",
     "\n",
     "classname", name_resolver_->GetImmutableClassName(descriptor_));
     "classname", name_resolver_->GetImmutableClassName(descriptor_));
 
 
@@ -792,7 +867,7 @@ void ImmutableMessageGenerator::GenerateBuilder(io::Printer* printer) {
   }
   }
   printer->Indent();
   printer->Indent();
 
 
-  GenerateDescriptorMethods(printer);
+  GenerateDescriptorMethods(printer, true);
   GenerateCommonBuilderMethods(printer);
   GenerateCommonBuilderMethods(printer);
 
 
   if (HasGeneratedMethods(descriptor_)) {
   if (HasGeneratedMethods(descriptor_)) {
@@ -876,7 +951,7 @@ void ImmutableMessageGenerator::GenerateBuilder(io::Printer* printer) {
 }
 }
 
 
 void ImmutableMessageGenerator::
 void ImmutableMessageGenerator::
-GenerateDescriptorMethods(io::Printer* printer) {
+GenerateDescriptorMethods(io::Printer* printer, bool is_builder) {
   if (HasDescriptorMethods(descriptor_)) {
   if (HasDescriptorMethods(descriptor_)) {
     if (!descriptor_->options().no_standard_descriptor_accessor()) {
     if (!descriptor_->options().no_standard_descriptor_accessor()) {
       printer->Print(
       printer->Print(
@@ -909,9 +984,9 @@ GenerateDescriptorMethods(io::Printer* printer) {
         const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
         const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
         printer->Print(
         printer->Print(
           "case $number$:\n"
           "case $number$:\n"
-          "  return $name$_;\n",
+          "  return internalGet$capitalized_name$();\n",
           "number", SimpleItoa(field->number()),
           "number", SimpleItoa(field->number()),
-          "name", info->name);
+          "capitalized_name", info->capitalized_name);
       }
       }
       printer->Print(
       printer->Print(
           "default:\n"
           "default:\n"
@@ -922,6 +997,34 @@ GenerateDescriptorMethods(io::Printer* printer) {
       printer->Print(
       printer->Print(
           "  }\n"
           "  }\n"
           "}\n");
           "}\n");
+      if (is_builder) {
+        printer->Print(
+          "@SuppressWarnings({\"rawtypes\"})\n"
+          "protected com.google.protobuf.MapField internalGetMutableMapField(\n"
+          "    int number) {\n"
+          "  switch (number) {\n");
+        printer->Indent();
+        printer->Indent();
+        for (int i = 0; i < map_fields.size(); ++i) {
+          const FieldDescriptor* field = map_fields[i];
+          const FieldGeneratorInfo* info =
+              context_->GetFieldGeneratorInfo(field);
+          printer->Print(
+            "case $number$:\n"
+            "  return internalGetMutable$capitalized_name$();\n",
+            "number", SimpleItoa(field->number()),
+            "capitalized_name", info->capitalized_name);
+        }
+        printer->Print(
+            "default:\n"
+            "  throw new RuntimeException(\n"
+            "      \"Invalid map field number: \" + number);\n");
+        printer->Outdent();
+        printer->Outdent();
+        printer->Print(
+            "  }\n"
+            "}\n");
+      }
     }
     }
     printer->Print(
     printer->Print(
       "protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
       "protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
@@ -959,7 +1062,7 @@ GenerateCommonBuilderMethods(io::Printer* printer) {
       "classname", name_resolver_->GetImmutableClassName(descriptor_));
       "classname", name_resolver_->GetImmutableClassName(descriptor_));
   } else {
   } else {
     // LITE runtime passes along the default instance to implement
     // LITE runtime passes along the default instance to implement
-    // getDefaultInstanceForType() at the GneratedMessageLite level.
+    // getDefaultInstanceForType() at the GeneratedMessageLite level.
     printer->Print(
     printer->Print(
         "// Construct using $classname$.newBuilder()\n"
         "// Construct using $classname$.newBuilder()\n"
         "private Builder() {\n"
         "private Builder() {\n"
@@ -1062,22 +1165,17 @@ GenerateCommonBuilderMethods(io::Printer* printer) {
   if (HasDescriptorMethods(descriptor_)) {
   if (HasDescriptorMethods(descriptor_)) {
     printer->Print(
     printer->Print(
         "public $classname$ buildPartial() {\n"
         "public $classname$ buildPartial() {\n"
-            "  $classname$ result = new $classname$(this);\n",
-         "classname", name_resolver_->GetImmutableClassName(descriptor_));
+        "  $classname$ result = new $classname$(this);\n",
+        "classname", name_resolver_->GetImmutableClassName(descriptor_));
   } else {
   } else {
     // LITE_RUNTIME only provides a single message constructor.
     // LITE_RUNTIME only provides a single message constructor.
     printer->Print(
     printer->Print(
         "public $classname$ buildPartial() {\n"
         "public $classname$ buildPartial() {\n"
-        "  $classname$ result = null;\n"
-        "  try {\n"
-        "    result = new $classname$(\n"
-        "        com.google.protobuf.Internal\n"
-        "            .EMPTY_CODED_INPUT_STREAM,\n"
-        "        com.google.protobuf.ExtensionRegistryLite\n"
-        "            .getEmptyRegistry());\n"
-        "  } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
-        "    throw new RuntimeException(e);\n"
-        "  }\n"
+        "  $classname$ result = new $classname$(\n"
+        "      com.google.protobuf.Internal\n"
+        "          .EMPTY_CODED_INPUT_STREAM,\n"
+        "      com.google.protobuf.ExtensionRegistryLite\n"
+        "          .getEmptyRegistry());\n"
         "  result.unknownFields = this.unknownFields;\n",
         "  result.unknownFields = this.unknownFields;\n",
         "classname", name_resolver_->GetImmutableClassName(descriptor_));
         "classname", name_resolver_->GetImmutableClassName(descriptor_));
 
 
@@ -1271,6 +1369,12 @@ GenerateBuilderParsingMethods(io::Printer* printer) {
 
 
 void ImmutableMessageGenerator::GenerateIsInitialized(
 void ImmutableMessageGenerator::GenerateIsInitialized(
     io::Printer* printer, UseMemoization useMemoization) {
     io::Printer* printer, UseMemoization useMemoization) {
+  // LITE_RUNTIME avoids generating isInitialized if it's not needed.
+  if (!HasDescriptorMethods(descriptor_)
+      && !HasRequiredFields(descriptor_)) {
+    return;
+  }
+
   bool memoization = useMemoization == MEMOIZE;
   bool memoization = useMemoization == MEMOIZE;
   if (memoization) {
   if (memoization) {
     // Memoizes whether the protocol buffer is fully initialized (has all
     // Memoizes whether the protocol buffer is fully initialized (has all
@@ -1558,8 +1662,7 @@ GenerateParsingConstructor(io::Printer* printer) {
   printer->Print(
   printer->Print(
       "private $classname$(\n"
       "private $classname$(\n"
       "    com.google.protobuf.CodedInputStream input,\n"
       "    com.google.protobuf.CodedInputStream input,\n"
-      "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
-      "    throws com.google.protobuf.InvalidProtocolBufferException {\n",
+      "    com.google.protobuf.ExtensionRegistryLite extensionRegistry) {\n",
       "classname", descriptor_->name());
       "classname", descriptor_->name());
   printer->Indent();
   printer->Indent();
 
 
@@ -1695,10 +1798,11 @@ GenerateParsingConstructor(io::Printer* printer) {
   printer->Outdent();
   printer->Outdent();
   printer->Print(
   printer->Print(
       "} catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
       "} catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
-      "  throw e.setUnfinishedMessage(this);\n"
+      "  throw new RuntimeException(e.setUnfinishedMessage(this));\n"
       "} catch (java.io.IOException e) {\n"
       "} catch (java.io.IOException e) {\n"
-      "  throw new com.google.protobuf.InvalidProtocolBufferException(\n"
-      "      e.getMessage()).setUnfinishedMessage(this);\n"
+      "  throw new RuntimeException(\n"
+      "      new com.google.protobuf.InvalidProtocolBufferException(\n"
+      "          e.getMessage()).setUnfinishedMessage(this));\n"
       "} finally {\n");
       "} finally {\n");
   printer->Indent();
   printer->Indent();
 
 
@@ -1747,8 +1851,19 @@ void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) {
       "    throws com.google.protobuf.InvalidProtocolBufferException {\n",
       "    throws com.google.protobuf.InvalidProtocolBufferException {\n",
       "classname", descriptor_->name());
       "classname", descriptor_->name());
   if (HasGeneratedMethods(descriptor_)) {
   if (HasGeneratedMethods(descriptor_)) {
+    // The parsing constructor throws an InvalidProtocolBufferException via a
+    // RuntimeException to aid in method pruning. We unwrap it here.
     printer->Print(
     printer->Print(
-        "  return new $classname$(input, extensionRegistry);\n",
+        "  try {\n"
+        "    return new $classname$(input, extensionRegistry);\n"
+        "  } catch (RuntimeException e) {\n"
+        "    if (e.getCause() instanceof\n"
+        "        com.google.protobuf.InvalidProtocolBufferException) {\n"
+        "      throw (com.google.protobuf.InvalidProtocolBufferException)\n"
+        "          e.getCause();\n"
+        "    }\n"
+        "    throw e;\n"
+        "  }\n",
         "classname", descriptor_->name());
         "classname", descriptor_->name());
   } else {
   } else {
     // When parsing constructor isn't generated, use builder to parse messages.
     // When parsing constructor isn't generated, use builder to parse messages.
@@ -1775,13 +1890,16 @@ void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) {
       "};\n"
       "};\n"
       "\n");
       "\n");
 
 
-  printer->Print(
-      "@java.lang.Override\n"
-      "public com.google.protobuf.Parser<$classname$> getParserForType() {\n"
-      "  return PARSER;\n"
-      "}\n"
-      "\n",
-      "classname", descriptor_->name());
+  if (HasDescriptorMethods(descriptor_)) {
+    // LITE_RUNTIME implements this at the GeneratedMessageLite level.
+    printer->Print(
+        "@java.lang.Override\n"
+        "public com.google.protobuf.Parser<$classname$> getParserForType() {\n"
+        "  return PARSER;\n"
+        "}\n"
+        "\n",
+        "classname", descriptor_->name());
+  }
 }
 }
 
 
 // ===================================================================
 // ===================================================================

+ 1 - 1
src/google/protobuf/compiler/java/java_message.h

@@ -117,7 +117,7 @@ class ImmutableMessageGenerator : public MessageGenerator {
 
 
   void GenerateBuilder(io::Printer* printer);
   void GenerateBuilder(io::Printer* printer);
   void GenerateCommonBuilderMethods(io::Printer* printer);
   void GenerateCommonBuilderMethods(io::Printer* printer);
-  void GenerateDescriptorMethods(io::Printer* printer);
+  void GenerateDescriptorMethods(io::Printer* printer, bool is_builder);
   void GenerateBuilderParsingMethods(io::Printer* printer);
   void GenerateBuilderParsingMethods(io::Printer* printer);
   void GenerateIsInitialized(io::Printer* printer,
   void GenerateIsInitialized(io::Printer* printer,
       UseMemoization useMemoization);
       UseMemoization useMemoization);

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

@@ -772,6 +772,9 @@ GenerateParsingDoneCode(io::Printer* printer) const {
 void RepeatedImmutablePrimitiveFieldGenerator::
 void RepeatedImmutablePrimitiveFieldGenerator::
 GenerateSerializationCode(io::Printer* printer) const {
 GenerateSerializationCode(io::Printer* printer) const {
   if (descriptor_->options().packed()) {
   if (descriptor_->options().packed()) {
+    // We invoke getSerializedSize in writeTo for messages that have packed
+    // fields in ImmutableMessageGenerator::GenerateMessageSerializationMethods.
+    // That makes it safe to rely on the memoized size here.
     printer->Print(variables_,
     printer->Print(variables_,
       "if (get$capitalized_name$List().size() > 0) {\n"
       "if (get$capitalized_name$List().size() > 0) {\n"
       "  output.writeRawVarint32($tag$);\n"
       "  output.writeRawVarint32($tag$);\n"

+ 1 - 1
src/google/protobuf/compiler/java/java_shared_code_generator.cc

@@ -171,7 +171,7 @@ void SharedCodeGenerator::GenerateDescriptors(io::Printer* printer) {
       string classname = FileJavaPackage(file_->dependency(i)) + "." +
       string classname = FileJavaPackage(file_->dependency(i)) + "." +
                          name_resolver_->GetDescriptorClassName(
                          name_resolver_->GetDescriptorClassName(
                              file_->dependency(i));
                              file_->dependency(i));
-      dependencies.push_back(make_pair(filename, classname));
+      dependencies.push_back(std::make_pair(filename, classname));
     }
     }
   }
   }
 
 

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

@@ -667,7 +667,7 @@ GenerateParsingCode(io::Printer* printer) const {
     printer->Print(variables_,
     printer->Print(variables_,
       "String s = input.readStringRequireUtf8();\n"
       "String s = input.readStringRequireUtf8();\n"
       "$set_oneof_case_message$;\n"
       "$set_oneof_case_message$;\n"
-      "$oneof_name$_ = s;\n}\n");
+      "$oneof_name$_ = s;\n");
   } else if (!HasDescriptorMethods(descriptor_->file())) {
   } else if (!HasDescriptorMethods(descriptor_->file())) {
     // Lite runtime should attempt to reduce allocations by attempting to
     // Lite runtime should attempt to reduce allocations by attempting to
     // construct the string directly from the input stream buffer. This avoids
     // construct the string directly from the input stream buffer. This avoids

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

@@ -133,10 +133,10 @@ bool MockCodeGenerator::Generate(
         *error = "Saw message type MockCodeGenerator_Error.";
         *error = "Saw message type MockCodeGenerator_Error.";
         return false;
         return false;
       } else if (command == "Exit") {
       } else if (command == "Exit") {
-        cerr << "Saw message type MockCodeGenerator_Exit." << endl;
+        std::cerr << "Saw message type MockCodeGenerator_Exit." << std::endl;
         exit(123);
         exit(123);
       } else if (command == "Abort") {
       } else if (command == "Abort") {
-        cerr << "Saw message type MockCodeGenerator_Abort." << endl;
+        std::cerr << "Saw message type MockCodeGenerator_Abort." << std::endl;
         abort();
         abort();
       } else if (command == "HasSourceCodeInfo") {
       } else if (command == "HasSourceCodeInfo") {
         FileDescriptorProto file_descriptor_proto;
         FileDescriptorProto file_descriptor_proto;
@@ -144,8 +144,8 @@ bool MockCodeGenerator::Generate(
         bool has_source_code_info =
         bool has_source_code_info =
             file_descriptor_proto.has_source_code_info() &&
             file_descriptor_proto.has_source_code_info() &&
             file_descriptor_proto.source_code_info().location_size() > 0;
             file_descriptor_proto.source_code_info().location_size() > 0;
-        cerr << "Saw message type MockCodeGenerator_HasSourceCodeInfo: "
-             << has_source_code_info << "." << endl;
+        std::cerr << "Saw message type MockCodeGenerator_HasSourceCodeInfo: "
+                  << has_source_code_info << "." << std::endl;
         abort();
         abort();
       } else {
       } else {
         GOOGLE_LOG(FATAL) << "Unknown MockCodeGenerator command: " << command;
         GOOGLE_LOG(FATAL) << "Unknown MockCodeGenerator command: " << command;

+ 64 - 30
src/google/protobuf/compiler/parser.cc

@@ -277,27 +277,39 @@ bool Parser::ConsumeString(string* output, const char* error) {
   }
   }
 }
 }
 
 
-bool Parser::TryConsumeEndOfDeclaration(const char* text,
-                                        const LocationRecorder* location) {
+bool Parser::TryConsumeEndOfDeclaration(
+    const char* text, const LocationRecorder* location) {
   if (LookingAt(text)) {
   if (LookingAt(text)) {
     string leading, trailing;
     string leading, trailing;
-    input_->NextWithComments(&trailing, NULL, &leading);
+    vector<string> detached;
+    input_->NextWithComments(&trailing, &detached, &leading);
 
 
     // Save the leading comments for next time, and recall the leading comments
     // Save the leading comments for next time, and recall the leading comments
     // from last time.
     // from last time.
     leading.swap(upcoming_doc_comments_);
     leading.swap(upcoming_doc_comments_);
 
 
     if (location != NULL) {
     if (location != NULL) {
-      location->AttachComments(&leading, &trailing);
+      upcoming_detached_comments_.swap(detached);
+      location->AttachComments(&leading, &trailing, &detached);
+    } else if (strcmp(text, "}") == 0) {
+      // If the current location is null and we are finishing the current scope,
+      // drop pending upcoming detached comments.
+      upcoming_detached_comments_.swap(detached);
+    } else {
+      // Otherwise, append the new detached comments to the existing upcoming
+      // detached comments.
+      upcoming_detached_comments_.insert(upcoming_detached_comments_.end(),
+                                         detached.begin(), detached.end());
     }
     }
+
     return true;
     return true;
   } else {
   } else {
     return false;
     return false;
   }
   }
 }
 }
 
 
-bool Parser::ConsumeEndOfDeclaration(const char* text,
-                                     const LocationRecorder* location) {
+bool Parser::ConsumeEndOfDeclaration(
+    const char* text, const LocationRecorder* location) {
   if (TryConsumeEndOfDeclaration(text, location)) {
   if (TryConsumeEndOfDeclaration(text, location)) {
     return true;
     return true;
   } else {
   } else {
@@ -390,7 +402,8 @@ void Parser::LocationRecorder::RecordLegacyLocation(const Message* descriptor,
 }
 }
 
 
 void Parser::LocationRecorder::AttachComments(
 void Parser::LocationRecorder::AttachComments(
-    string* leading, string* trailing) const {
+    string* leading, string* trailing,
+    vector<string>* detached_comments) const {
   GOOGLE_CHECK(!location_->has_leading_comments());
   GOOGLE_CHECK(!location_->has_leading_comments());
   GOOGLE_CHECK(!location_->has_trailing_comments());
   GOOGLE_CHECK(!location_->has_trailing_comments());
 
 
@@ -400,6 +413,11 @@ void Parser::LocationRecorder::AttachComments(
   if (!trailing->empty()) {
   if (!trailing->empty()) {
     location_->mutable_trailing_comments()->swap(*trailing);
     location_->mutable_trailing_comments()->swap(*trailing);
   }
   }
+  for (int i = 0; i < detached_comments->size(); ++i) {
+    location_->add_leading_detached_comments()->swap(
+        (*detached_comments)[i]);
+  }
+  detached_comments->clear();
 }
 }
 
 
 // -------------------------------------------------------------------
 // -------------------------------------------------------------------
@@ -451,16 +469,18 @@ bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) {
   SourceCodeInfo source_code_info;
   SourceCodeInfo source_code_info;
   source_code_info_ = &source_code_info;
   source_code_info_ = &source_code_info;
 
 
+  vector<string> top_doc_comments;
   if (LookingAtType(io::Tokenizer::TYPE_START)) {
   if (LookingAtType(io::Tokenizer::TYPE_START)) {
     // Advance to first token.
     // Advance to first token.
-    input_->NextWithComments(NULL, NULL, &upcoming_doc_comments_);
+    input_->NextWithComments(NULL, &upcoming_detached_comments_,
+                             &upcoming_doc_comments_);
   }
   }
 
 
   {
   {
     LocationRecorder root_location(this);
     LocationRecorder root_location(this);
 
 
     if (require_syntax_identifier_ || LookingAt("syntax")) {
     if (require_syntax_identifier_ || LookingAt("syntax")) {
-      if (!ParseSyntaxIdentifier()) {
+      if (!ParseSyntaxIdentifier(root_location)) {
         // Don't attempt to parse the file if we didn't recognize the syntax
         // Don't attempt to parse the file if we didn't recognize the syntax
         // identifier.
         // identifier.
         return false;
         return false;
@@ -469,9 +489,9 @@ bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) {
       if (file != NULL) file->set_syntax(syntax_identifier_);
       if (file != NULL) file->set_syntax(syntax_identifier_);
     } else if (!stop_after_syntax_identifier_) {
     } else if (!stop_after_syntax_identifier_) {
       GOOGLE_LOG(WARNING) << "No syntax specified for the proto file. "
       GOOGLE_LOG(WARNING) << "No syntax specified for the proto file. "
-                          << "Please use 'syntax = \"proto2\";' or "
-                          << "'syntax = \"proto3\";' to specify a syntax "
-                          << "version. (Defaulted to proto2 syntax.)";
+                   << "Please use 'syntax = \"proto2\";' or "
+                   << "'syntax = \"proto3\";' to specify a syntax "
+                   << "version. (Defaulted to proto2 syntax.)";
       syntax_identifier_ = "proto2";
       syntax_identifier_ = "proto2";
     }
     }
 
 
@@ -486,7 +506,8 @@ bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) {
 
 
         if (LookingAt("}")) {
         if (LookingAt("}")) {
           AddError("Unmatched \"}\".");
           AddError("Unmatched \"}\".");
-          input_->NextWithComments(NULL, NULL, &upcoming_doc_comments_);
+          input_->NextWithComments(NULL, &upcoming_detached_comments_,
+                                   &upcoming_doc_comments_);
         }
         }
       }
       }
     }
     }
@@ -498,7 +519,9 @@ bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) {
   return !had_errors_;
   return !had_errors_;
 }
 }
 
 
-bool Parser::ParseSyntaxIdentifier() {
+bool Parser::ParseSyntaxIdentifier(const LocationRecorder& parent) {
+  LocationRecorder syntax_location(parent,
+                                   FileDescriptorProto::kSyntaxFieldNumber);
   DO(Consume(
   DO(Consume(
       "syntax",
       "syntax",
       "File must begin with a syntax statement, e.g. 'syntax = \"proto2\";'."));
       "File must begin with a syntax statement, e.g. 'syntax = \"proto2\";'."));
@@ -506,7 +529,7 @@ bool Parser::ParseSyntaxIdentifier() {
   io::Tokenizer::Token syntax_token = input_->current();
   io::Tokenizer::Token syntax_token = input_->current();
   string syntax;
   string syntax;
   DO(ConsumeString(&syntax, "Expected syntax identifier."));
   DO(ConsumeString(&syntax, "Expected syntax identifier."));
-  DO(ConsumeEndOfDeclaration(";", NULL));
+  DO(ConsumeEndOfDeclaration(";", &syntax_location));
 
 
   syntax_identifier_ = syntax;
   syntax_identifier_ = syntax;
 
 
@@ -1271,7 +1294,6 @@ bool Parser::ParseOption(Message* options,
     DO(ConsumeEndOfDeclaration(";", &location));
     DO(ConsumeEndOfDeclaration(";", &location));
   }
   }
 
 
-
   return true;
   return true;
 }
 }
 
 
@@ -1636,8 +1658,14 @@ bool Parser::ParseServiceMethod(MethodDescriptorProto* method,
   // Parse input type.
   // Parse input type.
   DO(Consume("("));
   DO(Consume("("));
   {
   {
-    if (TryConsume("stream")) {
+    if (LookingAt("stream")) {
+      LocationRecorder location(
+          method_location, MethodDescriptorProto::kClientStreamingFieldNumber);
+      location.RecordLegacyLocation(
+          method, DescriptorPool::ErrorCollector::OTHER);
       method->set_client_streaming(true);
       method->set_client_streaming(true);
+      DO(Consume("stream"));
+
     }
     }
     LocationRecorder location(method_location,
     LocationRecorder location(method_location,
                               MethodDescriptorProto::kInputTypeFieldNumber);
                               MethodDescriptorProto::kInputTypeFieldNumber);
@@ -1651,8 +1679,14 @@ bool Parser::ParseServiceMethod(MethodDescriptorProto* method,
   DO(Consume("returns"));
   DO(Consume("returns"));
   DO(Consume("("));
   DO(Consume("("));
   {
   {
-    if (TryConsume("stream")) {
+    if (LookingAt("stream")) {
+      LocationRecorder location(
+          method_location, MethodDescriptorProto::kServerStreamingFieldNumber);
+      location.RecordLegacyLocation(
+          method, DescriptorPool::ErrorCollector::OTHER);
+      DO(Consume("stream"));
       method->set_server_streaming(true);
       method->set_server_streaming(true);
+
     }
     }
     LocationRecorder location(method_location,
     LocationRecorder location(method_location,
                               MethodDescriptorProto::kOutputTypeFieldNumber);
                               MethodDescriptorProto::kOutputTypeFieldNumber);
@@ -1664,10 +1698,9 @@ bool Parser::ParseServiceMethod(MethodDescriptorProto* method,
 
 
   if (LookingAt("{")) {
   if (LookingAt("{")) {
     // Options!
     // Options!
-    DO(ParseOptions(method_location,
-                    containing_file,
-                    MethodDescriptorProto::kOptionsFieldNumber,
-                    method->mutable_options()));
+    DO(ParseMethodOptions(method_location, containing_file,
+                          MethodDescriptorProto::kOptionsFieldNumber,
+                          method->mutable_options()));
   } else {
   } else {
     DO(ConsumeEndOfDeclaration(";", &method_location));
     DO(ConsumeEndOfDeclaration(";", &method_location));
   }
   }
@@ -1676,10 +1709,10 @@ bool Parser::ParseServiceMethod(MethodDescriptorProto* method,
 }
 }
 
 
 
 
-bool Parser::ParseOptions(const LocationRecorder& parent_location,
-                          const FileDescriptorProto* containing_file,
-                          const int optionsFieldNumber,
-                          Message* mutable_options) {
+bool Parser::ParseMethodOptions(const LocationRecorder& parent_location,
+                                const FileDescriptorProto* containing_file,
+                                const int optionsFieldNumber,
+                                Message* mutable_options) {
   // Options!
   // Options!
   ConsumeEndOfDeclaration("{", &parent_location);
   ConsumeEndOfDeclaration("{", &parent_location);
   while (!TryConsumeEndOfDeclaration("}", NULL)) {
   while (!TryConsumeEndOfDeclaration("}", NULL)) {
@@ -1693,8 +1726,8 @@ bool Parser::ParseOptions(const LocationRecorder& parent_location,
     } else {
     } else {
       LocationRecorder location(parent_location,
       LocationRecorder location(parent_location,
                                 optionsFieldNumber);
                                 optionsFieldNumber);
-      if (!ParseOption(mutable_options, location, containing_file,
-                       OPTION_STATEMENT)) {
+      if (!ParseOption(mutable_options, location,
+                       containing_file, OPTION_STATEMENT)) {
         // This statement failed to parse.  Skip it, but keep looping to
         // This statement failed to parse.  Skip it, but keep looping to
         // parse other statements.
         // parse other statements.
         SkipStatement();
         SkipStatement();
@@ -1847,7 +1880,7 @@ bool SourceLocationTable::Find(
     DescriptorPool::ErrorCollector::ErrorLocation location,
     DescriptorPool::ErrorCollector::ErrorLocation location,
     int* line, int* column) const {
     int* line, int* column) const {
   const pair<int, int>* result =
   const pair<int, int>* result =
-    FindOrNull(location_map_, make_pair(descriptor, location));
+      FindOrNull(location_map_, std::make_pair(descriptor, location));
   if (result == NULL) {
   if (result == NULL) {
     *line   = -1;
     *line   = -1;
     *column = 0;
     *column = 0;
@@ -1863,7 +1896,8 @@ void SourceLocationTable::Add(
     const Message* descriptor,
     const Message* descriptor,
     DescriptorPool::ErrorCollector::ErrorLocation location,
     DescriptorPool::ErrorCollector::ErrorLocation location,
     int line, int column) {
     int line, int column) {
-  location_map_[make_pair(descriptor, location)] = make_pair(line, column);
+  location_map_[std::make_pair(descriptor, location)] =
+      std::make_pair(line, column);
 }
 }
 
 
 void SourceLocationTable::Clear() {
 void SourceLocationTable::Clear() {

+ 24 - 13
src/google/protobuf/compiler/parser.h

@@ -185,10 +185,13 @@ class LIBPROTOBUF_EXPORT Parser {
   //   have been passed around by const reference, for no particularly good
   //   have been passed around by const reference, for no particularly good
   //   reason.  We should probably go through and change them all to mutable
   //   reason.  We should probably go through and change them all to mutable
   //   pointer to make this more intuitive.
   //   pointer to make this more intuitive.
-  bool TryConsumeEndOfDeclaration(const char* text,
-                                  const LocationRecorder* location);
-  bool ConsumeEndOfDeclaration(const char* text,
-                               const LocationRecorder* location);
+  bool TryConsumeEndOfDeclaration(
+      const char* text, const LocationRecorder* location);
+  bool TryConsumeEndOfDeclarationFinishScope(
+      const char* text, const LocationRecorder* location);
+
+  bool ConsumeEndOfDeclaration(
+      const char* text, const LocationRecorder* location);
 
 
   // -----------------------------------------------------------------
   // -----------------------------------------------------------------
   // Error logging helpers
   // Error logging helpers
@@ -253,9 +256,13 @@ class LIBPROTOBUF_EXPORT Parser {
     //
     //
     // TODO(kenton):  See comment on TryConsumeEndOfDeclaration(), above, for
     // TODO(kenton):  See comment on TryConsumeEndOfDeclaration(), above, for
     //   why this is const.
     //   why this is const.
-    void AttachComments(string* leading, string* trailing) const;
+    void AttachComments(string* leading, string* trailing,
+                        vector<string>* detached_comments) const;
 
 
    private:
    private:
+    // Indexes of parent and current location in the parent
+    // SourceCodeInfo.location repeated field. For top-level elements,
+    // parent_index_ is -1.
     Parser* parser_;
     Parser* parser_;
     SourceCodeInfo::Location* location_;
     SourceCodeInfo::Location* location_;
 
 
@@ -268,7 +275,7 @@ class LIBPROTOBUF_EXPORT Parser {
   // Parses the "syntax = \"proto2\";" line at the top of the file.  Returns
   // Parses the "syntax = \"proto2\";" line at the top of the file.  Returns
   // false if it failed to parse or if the syntax identifier was not
   // false if it failed to parse or if the syntax identifier was not
   // recognized.
   // recognized.
-  bool ParseSyntaxIdentifier();
+  bool ParseSyntaxIdentifier(const LocationRecorder& parent);
 
 
   // These methods parse various individual bits of code.  They return
   // These methods parse various individual bits of code.  They return
   // false if they completely fail to parse the construct.  In this case,
   // false if they completely fail to parse the construct.  In this case,
@@ -302,9 +309,6 @@ class LIBPROTOBUF_EXPORT Parser {
                    RepeatedField<int32>* weak_dependency,
                    RepeatedField<int32>* weak_dependency,
                    const LocationRecorder& root_location,
                    const LocationRecorder& root_location,
                    const FileDescriptorProto* containing_file);
                    const FileDescriptorProto* containing_file);
-  bool ParseOption(Message* options,
-                   const LocationRecorder& options_location,
-                   const FileDescriptorProto* containing_file);
 
 
   // These methods parse the contents of a message, enum, or service type and
   // These methods parse the contents of a message, enum, or service type and
   // add them to the given object.  They consume the entire block including
   // add them to the given object.  They consume the entire block including
@@ -397,10 +401,10 @@ class LIBPROTOBUF_EXPORT Parser {
 
 
 
 
   // Parse options of a single method or stream.
   // Parse options of a single method or stream.
-  bool ParseOptions(const LocationRecorder& parent_location,
-                    const FileDescriptorProto* containing_file,
-                    const int optionsFieldNumber,
-                    Message* mutable_options);
+  bool ParseMethodOptions(const LocationRecorder& parent_location,
+                          const FileDescriptorProto* containing_file,
+                          const int optionsFieldNumber,
+                          Message* mutable_options);
 
 
   // Parse "required", "optional", or "repeated" and fill in "label"
   // Parse "required", "optional", or "repeated" and fill in "label"
   // with the value. Returns true if shuch a label is consumed.
   // with the value. Returns true if shuch a label is consumed.
@@ -497,6 +501,13 @@ class LIBPROTOBUF_EXPORT Parser {
   // yet; use ConsumeEndOfDeclaration() to get the complete comments.
   // yet; use ConsumeEndOfDeclaration() to get the complete comments.
   string upcoming_doc_comments_;
   string upcoming_doc_comments_;
 
 
+  // Detached comments are not connected to any syntax entities. Elements in
+  // this vector are paragraphs of comments separated by empty lines. The
+  // detached comments will be put into the leading_detached_comments field for
+  // the next element (See SourceCodeInfo.Location in descriptor.proto), when
+  // ConsumeEndOfDeclaration() is called.
+  vector<string> upcoming_detached_comments_;
+
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Parser);
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Parser);
 };
 };
 
 

+ 165 - 41
src/google/protobuf/compiler/parser_unittest.cc

@@ -1571,7 +1571,7 @@ void SortMessages(DescriptorProto *descriptor_proto) {
   }
   }
   DescriptorProto **data =
   DescriptorProto **data =
     descriptor_proto->mutable_nested_type()->mutable_data();
     descriptor_proto->mutable_nested_type()->mutable_data();
-  sort(data, data + size, CompareDescriptorNames());
+  std::sort(data, data + size, CompareDescriptorNames());
 }
 }
 
 
 // Sorts DescriptorProtos belonging to a FileDescriptorProto, by name.
 // Sorts DescriptorProtos belonging to a FileDescriptorProto, by name.
@@ -1583,7 +1583,7 @@ void SortMessages(FileDescriptorProto *file_descriptor_proto) {
   }
   }
   DescriptorProto **data =
   DescriptorProto **data =
     file_descriptor_proto->mutable_message_type()->mutable_data();
     file_descriptor_proto->mutable_message_type()->mutable_data();
-  sort(data, data + size, CompareDescriptorNames());
+  std::sort(data, data + size, CompareDescriptorNames());
 }
 }
 
 
 // Strips the message and enum field type names for comparison purpose only.
 // Strips the message and enum field type names for comparison purpose only.
@@ -1703,25 +1703,52 @@ TEST_F(ParseDescriptorDebugTest, TestCustomOptions) {
 // places.
 // places.
 TEST_F(ParseDescriptorDebugTest, TestCommentsInDebugString) {
 TEST_F(ParseDescriptorDebugTest, TestCommentsInDebugString) {
   SetupParser(
   SetupParser(
+      "// Detached comment before syntax.\n"
+      "\n"
+      "// Syntax comment.\n"
+      "syntax = \"proto2\";\n"
+      "\n"
+      "// Detached comment before package.\n"
+      "\n"
+      "// Package comment.\n"
+      "package comment_test;\n"
+      "\n"
+      "// Detached comment before TestMessage1.\n"
+      "\n"
       "// Message comment.\n"
       "// Message comment.\n"
       "message TestMessage1 {\n"
       "message TestMessage1 {\n"
+      "\n"
+      "  // Detached comment before foo.\n"
+      "\n"
       "  // Field comment.\n"
       "  // Field comment.\n"
       "  optional int32 foo = 1;\n"
       "  optional int32 foo = 1;\n"
       "\n"
       "\n"
+      "  // Detached comment before NestedMessage.\n"
+      "\n"
       "  // Nested-message comment.\n"
       "  // Nested-message comment.\n"
       "  message NestedMessage {\n"
       "  message NestedMessage {\n"
       "    optional int32 bar = 1;\n"
       "    optional int32 bar = 1;\n"
       "  }\n"
       "  }\n"
       "}\n"
       "}\n"
       "\n"
       "\n"
+      "// Detached comment before MyEnumType.\n"
+      "\n"
       "// Enum comment.\n"
       "// Enum comment.\n"
       "enum MyEnumType {\n"
       "enum MyEnumType {\n"
+      "\n"
+      "  // Detached comment before ASDF.\n"
+      "\n"
       "  // Enum-value comment.\n"
       "  // Enum-value comment.\n"
       "  ASDF = 1;\n"
       "  ASDF = 1;\n"
       "}\n"
       "}\n"
       "\n"
       "\n"
+      "// Detached comment before MyService.\n"
+      "\n"
       "// Service comment.\n"
       "// Service comment.\n"
       "service MyService {\n"
       "service MyService {\n"
+      "\n"
+      "  // Detached comment before MyRPCCall.\n"
+      "\n"
       "  // RPC comment.\n"
       "  // RPC comment.\n"
       "  rpc MyRPCCall(TestMessage1) returns (TestMessage1) { }\n"
       "  rpc MyRPCCall(TestMessage1) returns (TestMessage1) { }\n"
       "}\n");
       "}\n");
@@ -1745,22 +1772,34 @@ TEST_F(ParseDescriptorDebugTest, TestCommentsInDebugString) {
   const string debug_string =
   const string debug_string =
       descriptor->DebugStringWithOptions(debug_string_options);
       descriptor->DebugStringWithOptions(debug_string_options);
 
 
-  // Ensure that each of the comments appears somewhere in the DebugString(),
-  // and that these comments appear in order. We don't test the exact comment
-  // placement or formatting, because we do not want to be too fragile here.
+  // Ensure that each of the comments appears somewhere in the DebugString().
+  // We don't test the exact comment placement or formatting, because we do not
+  // want to be too fragile here.
   const char* expected_comments[] = {
   const char* expected_comments[] = {
+    "Detached comment before syntax.",
+    "Syntax comment.",
+    "Detached comment before package.",
+    "Package comment.",
+    "Detached comment before TestMessage1.",
     "Message comment.",
     "Message comment.",
+    "Detached comment before foo.",
     "Field comment",
     "Field comment",
+    "Detached comment before NestedMessage.",
     "Nested-message comment",
     "Nested-message comment",
+    "Detached comment before MyEnumType.",
     "Enum comment",
     "Enum comment",
+    "Detached comment before ASDF.",
     "Enum-value comment",
     "Enum-value comment",
+    "Detached comment before MyService.",
     "Service comment",
     "Service comment",
+    "Detached comment before MyRPCCall.",
     "RPC comment",
     "RPC comment",
   };
   };
 
 
   for (int i = 0; i < GOOGLE_ARRAYSIZE(expected_comments); ++i) {
   for (int i = 0; i < GOOGLE_ARRAYSIZE(expected_comments); ++i) {
     string::size_type found_pos = debug_string.find(expected_comments[i]);
     string::size_type found_pos = debug_string.find(expected_comments[i]);
-    ASSERT_TRUE(found_pos != string::npos);
+    EXPECT_TRUE(found_pos != string::npos)
+        << "\"" << expected_comments[i] << "\" not found.";
   }
   }
 }
 }
 
 
@@ -1930,8 +1969,8 @@ class SourceInfoTest : public ParserTest {
         return false;
         return false;
       }
       }
 
 
-      spans_.insert(make_pair(SpanKey(*descriptor_proto, field, index),
-                              &location));
+      spans_.insert(
+          std::make_pair(SpanKey(*descriptor_proto, field, index), &location));
     }
     }
 
 
     return true;
     return true;
@@ -1952,16 +1991,18 @@ class SourceInfoTest : public ParserTest {
   bool HasSpan(char start_marker, char end_marker,
   bool HasSpan(char start_marker, char end_marker,
                const Message& descriptor_proto) {
                const Message& descriptor_proto) {
     return HasSpanWithComment(
     return HasSpanWithComment(
-        start_marker, end_marker, descriptor_proto, NULL, -1, NULL, NULL);
+        start_marker, end_marker, descriptor_proto, NULL, -1, NULL, NULL, NULL);
   }
   }
 
 
   bool HasSpanWithComment(char start_marker, char end_marker,
   bool HasSpanWithComment(char start_marker, char end_marker,
                           const Message& descriptor_proto,
                           const Message& descriptor_proto,
                           const char* expected_leading_comments,
                           const char* expected_leading_comments,
-                          const char* expected_trailing_comments) {
+                          const char* expected_trailing_comments,
+                          const char* expected_leading_detached_comments) {
     return HasSpanWithComment(
     return HasSpanWithComment(
         start_marker, end_marker, descriptor_proto, NULL, -1,
         start_marker, end_marker, descriptor_proto, NULL, -1,
-        expected_leading_comments, expected_trailing_comments);
+        expected_leading_comments, expected_trailing_comments,
+        expected_leading_detached_comments);
   }
   }
 
 
   bool HasSpan(char start_marker, char end_marker,
   bool HasSpan(char start_marker, char end_marker,
@@ -1973,14 +2014,15 @@ class SourceInfoTest : public ParserTest {
                const Message& descriptor_proto, const string& field_name,
                const Message& descriptor_proto, const string& field_name,
                int index) {
                int index) {
     return HasSpan(start_marker, end_marker, descriptor_proto,
     return HasSpan(start_marker, end_marker, descriptor_proto,
-                   field_name, index, NULL, NULL);
+                   field_name, index, NULL, NULL, NULL);
   }
   }
 
 
   bool HasSpan(char start_marker, char end_marker,
   bool HasSpan(char start_marker, char end_marker,
                const Message& descriptor_proto,
                const Message& descriptor_proto,
                const string& field_name, int index,
                const string& field_name, int index,
                const char* expected_leading_comments,
                const char* expected_leading_comments,
-               const char* expected_trailing_comments) {
+               const char* expected_trailing_comments,
+               const char* expected_leading_detached_comments) {
     const FieldDescriptor* field =
     const FieldDescriptor* field =
         descriptor_proto.GetDescriptor()->FindFieldByName(field_name);
         descriptor_proto.GetDescriptor()->FindFieldByName(field_name);
     if (field == NULL) {
     if (field == NULL) {
@@ -1991,12 +2033,13 @@ class SourceInfoTest : public ParserTest {
 
 
     return HasSpanWithComment(
     return HasSpanWithComment(
         start_marker, end_marker, descriptor_proto, field, index,
         start_marker, end_marker, descriptor_proto, field, index,
-        expected_leading_comments, expected_trailing_comments);
+        expected_leading_comments, expected_trailing_comments,
+        expected_leading_detached_comments);
   }
   }
 
 
   bool HasSpan(const Message& descriptor_proto) {
   bool HasSpan(const Message& descriptor_proto) {
     return HasSpanWithComment(
     return HasSpanWithComment(
-        '\0', '\0', descriptor_proto, NULL, -1, NULL, NULL);
+        '\0', '\0', descriptor_proto, NULL, -1, NULL, NULL, NULL);
   }
   }
 
 
   bool HasSpan(const Message& descriptor_proto, const string& field_name) {
   bool HasSpan(const Message& descriptor_proto, const string& field_name) {
@@ -2008,11 +2051,12 @@ class SourceInfoTest : public ParserTest {
     return HasSpan('\0', '\0', descriptor_proto, field_name, index);
     return HasSpan('\0', '\0', descriptor_proto, field_name, index);
   }
   }
 
 
-  bool HasSpanWithComment(char start_marker, char end_marker,
-                          const Message& descriptor_proto,
-                          const FieldDescriptor* field, int index,
-                          const char* expected_leading_comments,
-                          const char* expected_trailing_comments) {
+  bool HasSpanWithComment(
+      char start_marker, char end_marker, const Message& descriptor_proto,
+      const FieldDescriptor* field, int index,
+      const char* expected_leading_comments,
+      const char* expected_trailing_comments,
+      const char* expected_leading_detached_comments) {
     pair<SpanMap::iterator, SpanMap::iterator> range =
     pair<SpanMap::iterator, SpanMap::iterator> range =
         spans_.equal_range(SpanKey(descriptor_proto, field, index));
         spans_.equal_range(SpanKey(descriptor_proto, field, index));
 
 
@@ -2051,6 +2095,13 @@ class SourceInfoTest : public ParserTest {
             EXPECT_EQ(expected_trailing_comments,
             EXPECT_EQ(expected_trailing_comments,
                       iter->second->trailing_comments());
                       iter->second->trailing_comments());
           }
           }
+          if (expected_leading_detached_comments == NULL) {
+            EXPECT_EQ(0, iter->second->leading_detached_comments_size());
+          } else {
+            EXPECT_EQ(
+                expected_leading_detached_comments,
+                Join(iter->second->leading_detached_comments(), "\n"));
+          }
 
 
           spans_.erase(iter);
           spans_.erase(iter);
           return true;
           return true;
@@ -2101,7 +2152,7 @@ class SourceInfoTest : public ParserTest {
           text_without_markers_ += '$';
           text_without_markers_ += '$';
           ++column;
           ++column;
         } else {
         } else {
-          markers_[*text] = make_pair(line, column);
+          markers_[*text] = std::make_pair(line, column);
           ++text;
           ++text;
           GOOGLE_CHECK_EQ('$', *text);
           GOOGLE_CHECK_EQ('$', *text);
         }
         }
@@ -2120,7 +2171,7 @@ class SourceInfoTest : public ParserTest {
 
 
 TEST_F(SourceInfoTest, BasicFileDecls) {
 TEST_F(SourceInfoTest, BasicFileDecls) {
   EXPECT_TRUE(Parse(
   EXPECT_TRUE(Parse(
-      "$a$syntax = \"proto2\";\n"
+      "$a$syntax = \"proto2\";$i$\n"
       "package $b$foo.bar$c$;\n"
       "package $b$foo.bar$c$;\n"
       "import $d$\"baz.proto\"$e$;\n"
       "import $d$\"baz.proto\"$e$;\n"
       "import $f$\"qux.proto\"$g$;$h$\n"
       "import $f$\"qux.proto\"$g$;$h$\n"
@@ -2131,6 +2182,7 @@ TEST_F(SourceInfoTest, BasicFileDecls) {
   EXPECT_TRUE(HasSpan('b', 'c', file_, "package"));
   EXPECT_TRUE(HasSpan('b', 'c', file_, "package"));
   EXPECT_TRUE(HasSpan('d', 'e', file_, "dependency", 0));
   EXPECT_TRUE(HasSpan('d', 'e', file_, "dependency", 0));
   EXPECT_TRUE(HasSpan('f', 'g', file_, "dependency", 1));
   EXPECT_TRUE(HasSpan('f', 'g', file_, "dependency", 1));
+  EXPECT_TRUE(HasSpan('a', 'i', file_, "syntax"));
 }
 }
 
 
 TEST_F(SourceInfoTest, Messages) {
 TEST_F(SourceInfoTest, Messages) {
@@ -2561,6 +2613,9 @@ TEST_F(SourceInfoTest, ScopedOptions) {
     "  rpc M(X) returns(Y) {\n"
     "  rpc M(X) returns(Y) {\n"
     "    $g$option mopt = 1;$h$\n"
     "    $g$option mopt = 1;$h$\n"
     "  }\n"
     "  }\n"
+    "  rpc MS4($1$stream$2$ X) returns($3$stream$4$ Y) {\n"
+    "    $k$option mopt = 1;$l$\n"
+    "  }\n"
     "}\n"));
     "}\n"));
 
 
   EXPECT_TRUE(HasSpan('a', 'b', file_.message_type(0).options()));
   EXPECT_TRUE(HasSpan('a', 'b', file_.message_type(0).options()));
@@ -2620,6 +2675,26 @@ TEST_F(SourceInfoTest, ScopedOptions) {
                       .uninterpreted_option(0).name(0), "name_part"));
                       .uninterpreted_option(0).name(0), "name_part"));
   EXPECT_TRUE(HasSpan(file_.service(0).method(0).options()
   EXPECT_TRUE(HasSpan(file_.service(0).method(0).options()
                       .uninterpreted_option(0), "positive_int_value"));
                       .uninterpreted_option(0), "positive_int_value"));
+
+  EXPECT_TRUE(HasSpan('k', 'l', file_.service(0).method(1).options()));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(1)));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(1), "name"));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(1), "input_type"));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(1), "output_type"));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
+                      .uninterpreted_option(0)));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
+                      .uninterpreted_option(0), "name"));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
+                      .uninterpreted_option(0).name(0)));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
+                      .uninterpreted_option(0).name(0), "name_part"));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(1).options()
+                      .uninterpreted_option(0), "positive_int_value"));
+  EXPECT_TRUE(HasSpan('1', '2', file_.service(0).method(1),
+                      "client_streaming"));
+  EXPECT_TRUE(HasSpan('3', '4', file_.service(0).method(1),
+                      "server_streaming"));
 }
 }
 
 
 TEST_F(SourceInfoTest, FieldOptions) {
 TEST_F(SourceInfoTest, FieldOptions) {
@@ -2705,7 +2780,7 @@ TEST_F(SourceInfoTest, DocComments) {
       "  // Foo trailing\n"
       "  // Foo trailing\n"
       "  // line 2\n"
       "  // line 2\n"
       "\n"
       "\n"
-      "  // ignored\n"
+      "  // detached\n"
       "\n"
       "\n"
       "  // bar leading\n"
       "  // bar leading\n"
       "  $b$optional int32 bar = 1;$c$\n"
       "  $b$optional int32 bar = 1;$c$\n"
@@ -2719,10 +2794,12 @@ TEST_F(SourceInfoTest, DocComments) {
 
 
   EXPECT_TRUE(HasSpanWithComment('a', 'd', foo,
   EXPECT_TRUE(HasSpanWithComment('a', 'd', foo,
       " Foo leading\n line 2\n",
       " Foo leading\n line 2\n",
-      " Foo trailing\n line 2\n"));
+      " Foo trailing\n line 2\n",
+      NULL));
   EXPECT_TRUE(HasSpanWithComment('b', 'c', bar,
   EXPECT_TRUE(HasSpanWithComment('b', 'c', bar,
       " bar leading\n",
       " bar leading\n",
-      " bar trailing\n"));
+      " bar trailing\n",
+      " detached\n"));
 
 
   // Ignore these.
   // Ignore these.
   EXPECT_TRUE(HasSpan(file_));
   EXPECT_TRUE(HasSpan(file_));
@@ -2735,21 +2812,23 @@ TEST_F(SourceInfoTest, DocComments) {
 
 
 TEST_F(SourceInfoTest, DocComments2) {
 TEST_F(SourceInfoTest, DocComments2) {
   EXPECT_TRUE(Parse(
   EXPECT_TRUE(Parse(
-      "// ignored\n"
-      "syntax = \"proto2\";\n"
+      "// detached before message.\n"
+      "\n"
       "// Foo leading\n"
       "// Foo leading\n"
       "// line 2\n"
       "// line 2\n"
       "$a$message Foo {\n"
       "$a$message Foo {\n"
       "  /* Foo trailing\n"
       "  /* Foo trailing\n"
       "   * line 2 */\n"
       "   * line 2 */\n"
-      "  // ignored\n"
+      "  // detached\n"
       "  /* bar leading\n"
       "  /* bar leading\n"
       "   */"
       "   */"
       "  $b$optional int32 bar = 1;$c$  // bar trailing\n"
       "  $b$optional int32 bar = 1;$c$  // bar trailing\n"
-      "  // ignored\n"
+      "  // ignored detached\n"
       "}$d$\n"
       "}$d$\n"
       "// ignored\n"
       "// ignored\n"
       "\n"
       "\n"
+      "// detached before option\n"
+      "\n"
       "// option leading\n"
       "// option leading\n"
       "$e$option baz = 123;$f$\n"
       "$e$option baz = 123;$f$\n"
       "// option trailing\n"
       "// option trailing\n"
@@ -2761,13 +2840,16 @@ TEST_F(SourceInfoTest, DocComments2) {
 
 
   EXPECT_TRUE(HasSpanWithComment('a', 'd', foo,
   EXPECT_TRUE(HasSpanWithComment('a', 'd', foo,
       " Foo leading\n line 2\n",
       " Foo leading\n line 2\n",
-      " Foo trailing\n line 2 "));
+      " Foo trailing\n line 2 ",
+      " detached before message.\n"));
   EXPECT_TRUE(HasSpanWithComment('b', 'c', bar,
   EXPECT_TRUE(HasSpanWithComment('b', 'c', bar,
       " bar leading\n",
       " bar leading\n",
-      " bar trailing\n"));
+      " bar trailing\n",
+      " detached\n"));
   EXPECT_TRUE(HasSpanWithComment('e', 'f', baz,
   EXPECT_TRUE(HasSpanWithComment('e', 'f', baz,
       " option leading\n",
       " option leading\n",
-      " option trailing\n"));
+      " option trailing\n",
+      " detached before option\n"));
 
 
   // Ignore these.
   // Ignore these.
   EXPECT_TRUE(HasSpan(file_));
   EXPECT_TRUE(HasSpan(file_));
@@ -2798,7 +2880,8 @@ TEST_F(SourceInfoTest, DocComments3) {
 
 
   EXPECT_TRUE(HasSpanWithComment('b', 'c', bar,
   EXPECT_TRUE(HasSpanWithComment('b', 'c', bar,
       " bar leading\n",
       " bar leading\n",
-      " bar trailing\n"));
+      " bar trailing\n",
+      NULL));
 
 
   // Ignore these.
   // Ignore these.
   EXPECT_TRUE(HasSpan(file_));
   EXPECT_TRUE(HasSpan(file_));
@@ -2818,25 +2901,63 @@ TEST_F(SourceInfoTest, DocComments3) {
       bar.options().uninterpreted_option(0), "aggregate_value"));
       bar.options().uninterpreted_option(0), "aggregate_value"));
 }
 }
 
 
+TEST_F(SourceInfoTest, DocCommentsTopLevel) {
+  EXPECT_TRUE(Parse(
+      "// detached before syntax paragraph 1\n"
+      "\n"
+      "// detached before syntax paragraph 2\n"
+      "\n"
+      "// syntax leading\n"
+      "$a$syntax = \"proto2\";$b$\n"
+      "// syntax trailing\n"
+      "\n"
+      "// syntax-package detached comments\n"
+      "\n"
+      ";\n"
+      "\n"
+      "// detached after empty before package\n"
+      "\n"
+      "// package leading\n"
+      "package $c$foo$d$;\n"
+      "// package trailing\n"
+      "\n"
+      "// ignored detach\n"
+      "\n"));
+
+  EXPECT_TRUE(HasSpan('a', 'b', file_, "syntax", -1,
+      " syntax leading\n",
+      " syntax trailing\n",
+      " detached before syntax paragraph 1\n"
+      "\n"
+      " detached before syntax paragraph 2\n"));
+  EXPECT_TRUE(HasSpan('c', 'd', file_, "package", -1,
+      " package leading\n",
+      " package trailing\n",
+      " syntax-package detached comments\n"
+      "\n"
+      " detached after empty before package\n"));
+
+  // ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+}
+
 TEST_F(SourceInfoTest, DocCommentsOneof) {
 TEST_F(SourceInfoTest, DocCommentsOneof) {
   EXPECT_TRUE(Parse(
   EXPECT_TRUE(Parse(
-      "// ignored\n"
-      "syntax = \"proto2\";\n"
       "// Foo leading\n"
       "// Foo leading\n"
       "$a$message Foo {\n"
       "$a$message Foo {\n"
       "  /* Foo trailing\n"
       "  /* Foo trailing\n"
       "   */\n"
       "   */\n"
-      "  // ignored\n"
+      "  // detached before oneof\n"
       "  /* bar leading\n"
       "  /* bar leading\n"
       "   * line 2 */\n"
       "   * line 2 */\n"
       "  $b$oneof bar {\n"
       "  $b$oneof bar {\n"
       "  /* bar trailing\n"
       "  /* bar trailing\n"
       "   * line 2 */\n"
       "   * line 2 */\n"
-      "  // ignored\n"
+      "  // detached before bar_int\n"
       "  /* bar_int leading\n"
       "  /* bar_int leading\n"
       "   */\n"
       "   */\n"
       "  $c$int32 bar_int = 1;$d$  // bar_int trailing\n"
       "  $c$int32 bar_int = 1;$d$  // bar_int trailing\n"
-      "  // ignored\n"
+      "  // detach comment ignored\n"
       "  }$e$\n"
       "  }$e$\n"
       "}$f$\n"));
       "}$f$\n"));
 
 
@@ -2846,13 +2967,16 @@ TEST_F(SourceInfoTest, DocCommentsOneof) {
 
 
   EXPECT_TRUE(HasSpanWithComment('a', 'f', foo,
   EXPECT_TRUE(HasSpanWithComment('a', 'f', foo,
       " Foo leading\n",
       " Foo leading\n",
-      " Foo trailing\n"));
+      " Foo trailing\n",
+      NULL));
   EXPECT_TRUE(HasSpanWithComment('b', 'e', bar,
   EXPECT_TRUE(HasSpanWithComment('b', 'e', bar,
       " bar leading\n line 2 ",
       " bar leading\n line 2 ",
-      " bar trailing\n line 2 "));
+      " bar trailing\n line 2 ",
+      " detached before oneof\n"));
   EXPECT_TRUE(HasSpanWithComment('c', 'd', bar_int,
   EXPECT_TRUE(HasSpanWithComment('c', 'd', bar_int,
       " bar_int leading\n",
       " bar_int leading\n",
-      " bar_int trailing\n"));
+      " bar_int trailing\n",
+      " detached before bar_int\n"));
 
 
   // Ignore these.
   // Ignore these.
   EXPECT_TRUE(HasSpan(file_));
   EXPECT_TRUE(HasSpan(file_));

+ 7 - 6
src/google/protobuf/compiler/plugin.cc

@@ -95,7 +95,7 @@ class GeneratorResponseContext : public GeneratorContext {
 int PluginMain(int argc, char* argv[], const CodeGenerator* generator) {
 int PluginMain(int argc, char* argv[], const CodeGenerator* generator) {
 
 
   if (argc > 1) {
   if (argc > 1) {
-    cerr << argv[0] << ": Unknown option: " << argv[1] << endl;
+    std::cerr << argv[0] << ": Unknown option: " << argv[1] << std::endl;
     return 1;
     return 1;
   }
   }
 
 
@@ -106,7 +106,8 @@ int PluginMain(int argc, char* argv[], const CodeGenerator* generator) {
 
 
   CodeGeneratorRequest request;
   CodeGeneratorRequest request;
   if (!request.ParseFromFileDescriptor(STDIN_FILENO)) {
   if (!request.ParseFromFileDescriptor(STDIN_FILENO)) {
-    cerr << argv[0] << ": protoc sent unparseable request to plugin." << endl;
+    std::cerr << argv[0] << ": protoc sent unparseable request to plugin."
+              << std::endl;
     return 1;
     return 1;
   }
   }
 
 
@@ -123,9 +124,9 @@ int PluginMain(int argc, char* argv[], const CodeGenerator* generator) {
   for (int i = 0; i < request.file_to_generate_size(); i++) {
   for (int i = 0; i < request.file_to_generate_size(); i++) {
     parsed_files.push_back(pool.FindFileByName(request.file_to_generate(i)));
     parsed_files.push_back(pool.FindFileByName(request.file_to_generate(i)));
     if (parsed_files.back() == NULL) {
     if (parsed_files.back() == NULL) {
-      cerr << argv[0] << ": protoc asked plugin to generate a file but "
-              "did not provide a descriptor for the file: "
-           << request.file_to_generate(i) << endl;
+      std::cerr << argv[0] << ": protoc asked plugin to generate a file but "
+                              "did not provide a descriptor for the file: "
+                << request.file_to_generate(i) << std::endl;
       return 1;
       return 1;
     }
     }
   }
   }
@@ -151,7 +152,7 @@ int PluginMain(int argc, char* argv[], const CodeGenerator* generator) {
   }
   }
 
 
   if (!response.SerializeToFileDescriptor(STDOUT_FILENO)) {
   if (!response.SerializeToFileDescriptor(STDOUT_FILENO)) {
-    cerr << argv[0] << ": Error writing to stdout." << endl;
+    std::cerr << argv[0] << ": Error writing to stdout." << std::endl;
     return 1;
     return 1;
   }
   }
 
 

+ 393 - 2
src/google/protobuf/compiler/plugin.pb.cc

@@ -140,8 +140,8 @@ void protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() {
     "\01324.google.protobuf.compiler.CodeGenerat"
     "\01324.google.protobuf.compiler.CodeGenerat"
     "orResponse.File\032>\n\004File\022\014\n\004name\030\001 \001(\t\022\027\n"
     "orResponse.File\032>\n\004File\022\014\n\004name\030\001 \001(\t\022\027\n"
     "\017insertion_point\030\002 \001(\t\022\017\n\007content\030\017 \001(\tB"
     "\017insertion_point\030\002 \001(\t\022\017\n\007content\030\017 \001(\tB"
-    ",\n\034com.google.protobuf.compilerB\014PluginP"
-    "rotos", 445);
+    "7\n\034com.google.protobuf.compilerB\014PluginP"
+    "rotosZ\tplugin_go", 456);
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
     "google/protobuf/compiler/plugin.proto", &protobuf_RegisterTypes);
     "google/protobuf/compiler/plugin.proto", &protobuf_RegisterTypes);
   CodeGeneratorRequest::default_instance_ = new CodeGeneratorRequest();
   CodeGeneratorRequest::default_instance_ = new CodeGeneratorRequest();
@@ -509,6 +509,147 @@ void CodeGeneratorRequest::InternalSwap(CodeGeneratorRequest* other) {
   return metadata;
   return metadata;
 }
 }
 
 
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// CodeGeneratorRequest
+
+// repeated string file_to_generate = 1;
+ int CodeGeneratorRequest::file_to_generate_size() const {
+  return file_to_generate_.size();
+}
+ void CodeGeneratorRequest::clear_file_to_generate() {
+  file_to_generate_.Clear();
+}
+ const ::std::string& CodeGeneratorRequest::file_to_generate(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+  return file_to_generate_.Get(index);
+}
+ ::std::string* CodeGeneratorRequest::mutable_file_to_generate(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+  return file_to_generate_.Mutable(index);
+}
+ void CodeGeneratorRequest::set_file_to_generate(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+  file_to_generate_.Mutable(index)->assign(value);
+}
+ void CodeGeneratorRequest::set_file_to_generate(int index, const char* value) {
+  file_to_generate_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+}
+ void CodeGeneratorRequest::set_file_to_generate(int index, const char* value, size_t size) {
+  file_to_generate_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+}
+ ::std::string* CodeGeneratorRequest::add_file_to_generate() {
+  return file_to_generate_.Add();
+}
+ void CodeGeneratorRequest::add_file_to_generate(const ::std::string& value) {
+  file_to_generate_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+}
+ void CodeGeneratorRequest::add_file_to_generate(const char* value) {
+  file_to_generate_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+}
+ void CodeGeneratorRequest::add_file_to_generate(const char* value, size_t size) {
+  file_to_generate_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+}
+ const ::google::protobuf::RepeatedPtrField< ::std::string>&
+CodeGeneratorRequest::file_to_generate() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+  return file_to_generate_;
+}
+ ::google::protobuf::RepeatedPtrField< ::std::string>*
+CodeGeneratorRequest::mutable_file_to_generate() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate)
+  return &file_to_generate_;
+}
+
+// optional string parameter = 2;
+ bool CodeGeneratorRequest::has_parameter() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+ void CodeGeneratorRequest::set_has_parameter() {
+  _has_bits_[0] |= 0x00000002u;
+}
+ void CodeGeneratorRequest::clear_has_parameter() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+ void CodeGeneratorRequest::clear_parameter() {
+  parameter_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_parameter();
+}
+ const ::std::string& CodeGeneratorRequest::parameter() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+  return parameter_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorRequest::set_parameter(const ::std::string& value) {
+  set_has_parameter();
+  parameter_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+}
+ void CodeGeneratorRequest::set_parameter(const char* value) {
+  set_has_parameter();
+  parameter_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+}
+ void CodeGeneratorRequest::set_parameter(const char* value, size_t size) {
+  set_has_parameter();
+  parameter_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+}
+ ::std::string* CodeGeneratorRequest::mutable_parameter() {
+  set_has_parameter();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+  return parameter_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* CodeGeneratorRequest::release_parameter() {
+  clear_has_parameter();
+  return parameter_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorRequest::set_allocated_parameter(::std::string* parameter) {
+  if (parameter != NULL) {
+    set_has_parameter();
+  } else {
+    clear_has_parameter();
+  }
+  parameter_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), parameter);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorRequest.parameter)
+}
+
+// repeated .google.protobuf.FileDescriptorProto proto_file = 15;
+ int CodeGeneratorRequest::proto_file_size() const {
+  return proto_file_.size();
+}
+ void CodeGeneratorRequest::clear_proto_file() {
+  proto_file_.Clear();
+}
+ const ::google::protobuf::FileDescriptorProto& CodeGeneratorRequest::proto_file(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
+  return proto_file_.Get(index);
+}
+ ::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::mutable_proto_file(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
+  return proto_file_.Mutable(index);
+}
+ ::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::add_proto_file() {
+  // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
+  return proto_file_.Add();
+}
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
+CodeGeneratorRequest::proto_file() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
+  return proto_file_;
+}
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
+CodeGeneratorRequest::mutable_proto_file() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
+  return &proto_file_;
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 
 // ===================================================================
 // ===================================================================
 
 
@@ -1162,6 +1303,256 @@ void CodeGeneratorResponse::InternalSwap(CodeGeneratorResponse* other) {
   return metadata;
   return metadata;
 }
 }
 
 
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// CodeGeneratorResponse_File
+
+// optional string name = 1;
+ bool CodeGeneratorResponse_File::has_name() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+ void CodeGeneratorResponse_File::set_has_name() {
+  _has_bits_[0] |= 0x00000001u;
+}
+ void CodeGeneratorResponse_File::clear_has_name() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+ void CodeGeneratorResponse_File::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_name();
+}
+ const ::std::string& CodeGeneratorResponse_File::name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse_File::set_name(const ::std::string& value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+}
+ void CodeGeneratorResponse_File::set_name(const char* value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+}
+ void CodeGeneratorResponse_File::set_name(const char* value, size_t size) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+}
+ ::std::string* CodeGeneratorResponse_File::mutable_name() {
+  set_has_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* CodeGeneratorResponse_File::release_name() {
+  clear_has_name();
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse_File::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    set_has_name();
+  } else {
+    clear_has_name();
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.name)
+}
+
+// optional string insertion_point = 2;
+ bool CodeGeneratorResponse_File::has_insertion_point() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+ void CodeGeneratorResponse_File::set_has_insertion_point() {
+  _has_bits_[0] |= 0x00000002u;
+}
+ void CodeGeneratorResponse_File::clear_has_insertion_point() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+ void CodeGeneratorResponse_File::clear_insertion_point() {
+  insertion_point_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_insertion_point();
+}
+ const ::std::string& CodeGeneratorResponse_File::insertion_point() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+  return insertion_point_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse_File::set_insertion_point(const ::std::string& value) {
+  set_has_insertion_point();
+  insertion_point_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+}
+ void CodeGeneratorResponse_File::set_insertion_point(const char* value) {
+  set_has_insertion_point();
+  insertion_point_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+}
+ void CodeGeneratorResponse_File::set_insertion_point(const char* value, size_t size) {
+  set_has_insertion_point();
+  insertion_point_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+}
+ ::std::string* CodeGeneratorResponse_File::mutable_insertion_point() {
+  set_has_insertion_point();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+  return insertion_point_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* CodeGeneratorResponse_File::release_insertion_point() {
+  clear_has_insertion_point();
+  return insertion_point_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse_File::set_allocated_insertion_point(::std::string* insertion_point) {
+  if (insertion_point != NULL) {
+    set_has_insertion_point();
+  } else {
+    clear_has_insertion_point();
+  }
+  insertion_point_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), insertion_point);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
+}
+
+// optional string content = 15;
+ bool CodeGeneratorResponse_File::has_content() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+ void CodeGeneratorResponse_File::set_has_content() {
+  _has_bits_[0] |= 0x00000004u;
+}
+ void CodeGeneratorResponse_File::clear_has_content() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+ void CodeGeneratorResponse_File::clear_content() {
+  content_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_content();
+}
+ const ::std::string& CodeGeneratorResponse_File::content() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+  return content_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse_File::set_content(const ::std::string& value) {
+  set_has_content();
+  content_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+}
+ void CodeGeneratorResponse_File::set_content(const char* value) {
+  set_has_content();
+  content_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+}
+ void CodeGeneratorResponse_File::set_content(const char* value, size_t size) {
+  set_has_content();
+  content_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+}
+ ::std::string* CodeGeneratorResponse_File::mutable_content() {
+  set_has_content();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+  return content_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* CodeGeneratorResponse_File::release_content() {
+  clear_has_content();
+  return content_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse_File::set_allocated_content(::std::string* content) {
+  if (content != NULL) {
+    set_has_content();
+  } else {
+    clear_has_content();
+  }
+  content_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), content);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.File.content)
+}
+
+// -------------------------------------------------------------------
+
+// CodeGeneratorResponse
+
+// optional string error = 1;
+ bool CodeGeneratorResponse::has_error() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+ void CodeGeneratorResponse::set_has_error() {
+  _has_bits_[0] |= 0x00000001u;
+}
+ void CodeGeneratorResponse::clear_has_error() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+ void CodeGeneratorResponse::clear_error() {
+  error_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_error();
+}
+ const ::std::string& CodeGeneratorResponse::error() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.error)
+  return error_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse::set_error(const ::std::string& value) {
+  set_has_error();
+  error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.compiler.CodeGeneratorResponse.error)
+}
+ void CodeGeneratorResponse::set_error(const char* value) {
+  set_has_error();
+  error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.error)
+}
+ void CodeGeneratorResponse::set_error(const char* value, size_t size) {
+  set_has_error();
+  error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.error)
+}
+ ::std::string* CodeGeneratorResponse::mutable_error() {
+  set_has_error();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.error)
+  return error_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* CodeGeneratorResponse::release_error() {
+  clear_has_error();
+  return error_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void CodeGeneratorResponse::set_allocated_error(::std::string* error) {
+  if (error != NULL) {
+    set_has_error();
+  } else {
+    clear_has_error();
+  }
+  error_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), error);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.compiler.CodeGeneratorResponse.error)
+}
+
+// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
+ int CodeGeneratorResponse::file_size() const {
+  return file_.size();
+}
+ void CodeGeneratorResponse::clear_file() {
+  file_.Clear();
+}
+ const ::google::protobuf::compiler::CodeGeneratorResponse_File& CodeGeneratorResponse::file(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.file)
+  return file_.Get(index);
+}
+ ::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::mutable_file(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.file)
+  return file_.Mutable(index);
+}
+ ::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::add_file() {
+  // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorResponse.file)
+  return file_.Add();
+}
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >&
+CodeGeneratorResponse::file() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorResponse.file)
+  return file_;
+}
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >*
+CodeGeneratorResponse::mutable_file() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorResponse.file)
+  return &file_;
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 
 // @@protoc_insertion_point(namespace_scope)
 // @@protoc_insertion_point(namespace_scope)
 
 

+ 74 - 81
src/google/protobuf/compiler/plugin.pb.h

@@ -110,43 +110,43 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message
   // accessors -------------------------------------------------------
   // accessors -------------------------------------------------------
 
 
   // repeated string file_to_generate = 1;
   // repeated string file_to_generate = 1;
-  inline int file_to_generate_size() const;
-  inline void clear_file_to_generate();
+  int file_to_generate_size() const;
+  void clear_file_to_generate();
   static const int kFileToGenerateFieldNumber = 1;
   static const int kFileToGenerateFieldNumber = 1;
-  inline const ::std::string& file_to_generate(int index) const;
-  inline ::std::string* mutable_file_to_generate(int index);
-  inline void set_file_to_generate(int index, const ::std::string& value);
-  inline void set_file_to_generate(int index, const char* value);
-  inline void set_file_to_generate(int index, const char* value, size_t size);
-  inline ::std::string* add_file_to_generate();
-  inline void add_file_to_generate(const ::std::string& value);
-  inline void add_file_to_generate(const char* value);
-  inline void add_file_to_generate(const char* value, size_t size);
-  inline const ::google::protobuf::RepeatedPtrField< ::std::string>& file_to_generate() const;
-  inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_file_to_generate();
+  const ::std::string& file_to_generate(int index) const;
+  ::std::string* mutable_file_to_generate(int index);
+  void set_file_to_generate(int index, const ::std::string& value);
+  void set_file_to_generate(int index, const char* value);
+  void set_file_to_generate(int index, const char* value, size_t size);
+  ::std::string* add_file_to_generate();
+  void add_file_to_generate(const ::std::string& value);
+  void add_file_to_generate(const char* value);
+  void add_file_to_generate(const char* value, size_t size);
+  const ::google::protobuf::RepeatedPtrField< ::std::string>& file_to_generate() const;
+  ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_file_to_generate();
 
 
   // optional string parameter = 2;
   // optional string parameter = 2;
-  inline bool has_parameter() const;
-  inline void clear_parameter();
+  bool has_parameter() const;
+  void clear_parameter();
   static const int kParameterFieldNumber = 2;
   static const int kParameterFieldNumber = 2;
-  inline const ::std::string& parameter() const;
-  inline void set_parameter(const ::std::string& value);
-  inline void set_parameter(const char* value);
-  inline void set_parameter(const char* value, size_t size);
-  inline ::std::string* mutable_parameter();
-  inline ::std::string* release_parameter();
-  inline void set_allocated_parameter(::std::string* parameter);
+  const ::std::string& parameter() const;
+  void set_parameter(const ::std::string& value);
+  void set_parameter(const char* value);
+  void set_parameter(const char* value, size_t size);
+  ::std::string* mutable_parameter();
+  ::std::string* release_parameter();
+  void set_allocated_parameter(::std::string* parameter);
 
 
   // repeated .google.protobuf.FileDescriptorProto proto_file = 15;
   // repeated .google.protobuf.FileDescriptorProto proto_file = 15;
-  inline int proto_file_size() const;
-  inline void clear_proto_file();
+  int proto_file_size() const;
+  void clear_proto_file();
   static const int kProtoFileFieldNumber = 15;
   static const int kProtoFileFieldNumber = 15;
-  inline const ::google::protobuf::FileDescriptorProto& proto_file(int index) const;
-  inline ::google::protobuf::FileDescriptorProto* mutable_proto_file(int index);
-  inline ::google::protobuf::FileDescriptorProto* add_proto_file();
-  inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
+  const ::google::protobuf::FileDescriptorProto& proto_file(int index) const;
+  ::google::protobuf::FileDescriptorProto* mutable_proto_file(int index);
+  ::google::protobuf::FileDescriptorProto* add_proto_file();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
       proto_file() const;
       proto_file() const;
-  inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
       mutable_proto_file();
       mutable_proto_file();
 
 
   // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorRequest)
   // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorRequest)
@@ -234,40 +234,40 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M
   // accessors -------------------------------------------------------
   // accessors -------------------------------------------------------
 
 
   // optional string name = 1;
   // optional string name = 1;
-  inline bool has_name() const;
-  inline void clear_name();
+  bool has_name() const;
+  void clear_name();
   static const int kNameFieldNumber = 1;
   static const int kNameFieldNumber = 1;
-  inline const ::std::string& name() const;
-  inline void set_name(const ::std::string& value);
-  inline void set_name(const char* value);
-  inline void set_name(const char* value, size_t size);
-  inline ::std::string* mutable_name();
-  inline ::std::string* release_name();
-  inline void set_allocated_name(::std::string* name);
+  const ::std::string& name() const;
+  void set_name(const ::std::string& value);
+  void set_name(const char* value);
+  void set_name(const char* value, size_t size);
+  ::std::string* mutable_name();
+  ::std::string* release_name();
+  void set_allocated_name(::std::string* name);
 
 
   // optional string insertion_point = 2;
   // optional string insertion_point = 2;
-  inline bool has_insertion_point() const;
-  inline void clear_insertion_point();
+  bool has_insertion_point() const;
+  void clear_insertion_point();
   static const int kInsertionPointFieldNumber = 2;
   static const int kInsertionPointFieldNumber = 2;
-  inline const ::std::string& insertion_point() const;
-  inline void set_insertion_point(const ::std::string& value);
-  inline void set_insertion_point(const char* value);
-  inline void set_insertion_point(const char* value, size_t size);
-  inline ::std::string* mutable_insertion_point();
-  inline ::std::string* release_insertion_point();
-  inline void set_allocated_insertion_point(::std::string* insertion_point);
+  const ::std::string& insertion_point() const;
+  void set_insertion_point(const ::std::string& value);
+  void set_insertion_point(const char* value);
+  void set_insertion_point(const char* value, size_t size);
+  ::std::string* mutable_insertion_point();
+  ::std::string* release_insertion_point();
+  void set_allocated_insertion_point(::std::string* insertion_point);
 
 
   // optional string content = 15;
   // optional string content = 15;
-  inline bool has_content() const;
-  inline void clear_content();
+  bool has_content() const;
+  void clear_content();
   static const int kContentFieldNumber = 15;
   static const int kContentFieldNumber = 15;
-  inline const ::std::string& content() const;
-  inline void set_content(const ::std::string& value);
-  inline void set_content(const char* value);
-  inline void set_content(const char* value, size_t size);
-  inline ::std::string* mutable_content();
-  inline ::std::string* release_content();
-  inline void set_allocated_content(::std::string* content);
+  const ::std::string& content() const;
+  void set_content(const ::std::string& value);
+  void set_content(const char* value);
+  void set_content(const char* value, size_t size);
+  ::std::string* mutable_content();
+  ::std::string* release_content();
+  void set_allocated_content(::std::string* content);
 
 
   // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse.File)
   // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse.File)
  private:
  private:
@@ -360,27 +360,27 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag
   // accessors -------------------------------------------------------
   // accessors -------------------------------------------------------
 
 
   // optional string error = 1;
   // optional string error = 1;
-  inline bool has_error() const;
-  inline void clear_error();
+  bool has_error() const;
+  void clear_error();
   static const int kErrorFieldNumber = 1;
   static const int kErrorFieldNumber = 1;
-  inline const ::std::string& error() const;
-  inline void set_error(const ::std::string& value);
-  inline void set_error(const char* value);
-  inline void set_error(const char* value, size_t size);
-  inline ::std::string* mutable_error();
-  inline ::std::string* release_error();
-  inline void set_allocated_error(::std::string* error);
+  const ::std::string& error() const;
+  void set_error(const ::std::string& value);
+  void set_error(const char* value);
+  void set_error(const char* value, size_t size);
+  ::std::string* mutable_error();
+  ::std::string* release_error();
+  void set_allocated_error(::std::string* error);
 
 
   // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
   // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
-  inline int file_size() const;
-  inline void clear_file();
+  int file_size() const;
+  void clear_file();
   static const int kFileFieldNumber = 15;
   static const int kFileFieldNumber = 15;
-  inline const ::google::protobuf::compiler::CodeGeneratorResponse_File& file(int index) const;
-  inline ::google::protobuf::compiler::CodeGeneratorResponse_File* mutable_file(int index);
-  inline ::google::protobuf::compiler::CodeGeneratorResponse_File* add_file();
-  inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >&
+  const ::google::protobuf::compiler::CodeGeneratorResponse_File& file(int index) const;
+  ::google::protobuf::compiler::CodeGeneratorResponse_File* mutable_file(int index);
+  ::google::protobuf::compiler::CodeGeneratorResponse_File* add_file();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >&
       file() const;
       file() const;
-  inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >*
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >*
       mutable_file();
       mutable_file();
 
 
   // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse)
   // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse)
@@ -405,6 +405,7 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag
 
 
 // ===================================================================
 // ===================================================================
 
 
+#if !PROTOBUF_INLINE_NOT_IN_HEADERS
 // CodeGeneratorRequest
 // CodeGeneratorRequest
 
 
 // repeated string file_to_generate = 1;
 // repeated string file_to_generate = 1;
@@ -794,6 +795,7 @@ CodeGeneratorResponse::mutable_file() {
   return &file_;
   return &file_;
 }
 }
 
 
+#endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
 
 
 // @@protoc_insertion_point(namespace_scope)
 // @@protoc_insertion_point(namespace_scope)
 
 
@@ -801,15 +803,6 @@ CodeGeneratorResponse::mutable_file() {
 }  // namespace protobuf
 }  // namespace protobuf
 }  // namespace google
 }  // namespace google
 
 
-#ifndef SWIG
-namespace google {
-namespace protobuf {
-
-
-}  // namespace protobuf
-}  // namespace google
-#endif  // SWIG
-
 // @@protoc_insertion_point(global_scope)
 // @@protoc_insertion_point(global_scope)
 
 
 #endif  // PROTOBUF_google_2fprotobuf_2fcompiler_2fplugin_2eproto__INCLUDED
 #endif  // PROTOBUF_google_2fprotobuf_2fcompiler_2fplugin_2eproto__INCLUDED

+ 2 - 0
src/google/protobuf/compiler/plugin.proto

@@ -49,6 +49,8 @@ package google.protobuf.compiler;
 option java_package = "com.google.protobuf.compiler";
 option java_package = "com.google.protobuf.compiler";
 option java_outer_classname = "PluginProtos";
 option java_outer_classname = "PluginProtos";
 
 
+option go_package = "plugin_go";
+
 import "google/protobuf/descriptor.proto";
 import "google/protobuf/descriptor.proto";
 
 
 // An encoded CodeGeneratorRequest is written to the plugin's stdin.
 // An encoded CodeGeneratorRequest is written to the plugin's stdin.

+ 60 - 28
src/google/protobuf/descriptor.cc

@@ -783,7 +783,7 @@ inline const FileDescriptor* DescriptorPool::Tables::FindFile(
 
 
 inline const FieldDescriptor* FileDescriptorTables::FindFieldByNumber(
 inline const FieldDescriptor* FileDescriptorTables::FindFieldByNumber(
     const Descriptor* parent, int number) const {
     const Descriptor* parent, int number) const {
-  return FindPtrOrNull(fields_by_number_, make_pair(parent, number));
+  return FindPtrOrNull(fields_by_number_, std::make_pair(parent, number));
 }
 }
 
 
 inline const FieldDescriptor* FileDescriptorTables::FindFieldByLowercaseName(
 inline const FieldDescriptor* FileDescriptorTables::FindFieldByLowercaseName(
@@ -800,7 +800,7 @@ inline const FieldDescriptor* FileDescriptorTables::FindFieldByCamelcaseName(
 
 
 inline const EnumValueDescriptor* FileDescriptorTables::FindEnumValueByNumber(
 inline const EnumValueDescriptor* FileDescriptorTables::FindEnumValueByNumber(
     const EnumDescriptor* parent, int number) const {
     const EnumDescriptor* parent, int number) const {
-  return FindPtrOrNull(enum_values_by_number_, make_pair(parent, number));
+  return FindPtrOrNull(enum_values_by_number_, std::make_pair(parent, number));
 }
 }
 
 
 inline const EnumValueDescriptor*
 inline const EnumValueDescriptor*
@@ -808,8 +808,8 @@ FileDescriptorTables::FindEnumValueByNumberCreatingIfUnknown(
     const EnumDescriptor* parent, int number) const {
     const EnumDescriptor* parent, int number) const {
   // First try, with map of compiled-in values.
   // First try, with map of compiled-in values.
   {
   {
-    const EnumValueDescriptor* desc = FindPtrOrNull(
-        enum_values_by_number_, make_pair(parent, number));
+    const EnumValueDescriptor* desc =
+        FindPtrOrNull(enum_values_by_number_, std::make_pair(parent, number));
     if (desc != NULL) {
     if (desc != NULL) {
       return desc;
       return desc;
     }
     }
@@ -818,7 +818,7 @@ FileDescriptorTables::FindEnumValueByNumberCreatingIfUnknown(
   {
   {
     ReaderMutexLock l(&unknown_enum_values_mu_);
     ReaderMutexLock l(&unknown_enum_values_mu_);
     const EnumValueDescriptor* desc = FindPtrOrNull(
     const EnumValueDescriptor* desc = FindPtrOrNull(
-        unknown_enum_values_by_number_, make_pair(parent, number));
+        unknown_enum_values_by_number_, std::make_pair(parent, number));
     if (desc != NULL) {
     if (desc != NULL) {
       return desc;
       return desc;
     }
     }
@@ -828,7 +828,7 @@ FileDescriptorTables::FindEnumValueByNumberCreatingIfUnknown(
   {
   {
     WriterMutexLock l(&unknown_enum_values_mu_);
     WriterMutexLock l(&unknown_enum_values_mu_);
     const EnumValueDescriptor* desc = FindPtrOrNull(
     const EnumValueDescriptor* desc = FindPtrOrNull(
-        unknown_enum_values_by_number_, make_pair(parent, number));
+        unknown_enum_values_by_number_, std::make_pair(parent, number));
     if (desc != NULL) {
     if (desc != NULL) {
       return desc;
       return desc;
     }
     }
@@ -850,8 +850,7 @@ FileDescriptorTables::FindEnumValueByNumberCreatingIfUnknown(
     result->type_ = parent;
     result->type_ = parent;
     result->options_ = &EnumValueOptions::default_instance();
     result->options_ = &EnumValueOptions::default_instance();
     InsertIfNotPresent(&unknown_enum_values_by_number_,
     InsertIfNotPresent(&unknown_enum_values_by_number_,
-                       make_pair(parent, number),
-                       result);
+                       std::make_pair(parent, number), result);
     return result;
     return result;
   }
   }
 }
 }
@@ -859,13 +858,13 @@ FileDescriptorTables::FindEnumValueByNumberCreatingIfUnknown(
 
 
 inline const FieldDescriptor* DescriptorPool::Tables::FindExtension(
 inline const FieldDescriptor* DescriptorPool::Tables::FindExtension(
     const Descriptor* extendee, int number) {
     const Descriptor* extendee, int number) {
-  return FindPtrOrNull(extensions_, make_pair(extendee, number));
+  return FindPtrOrNull(extensions_, std::make_pair(extendee, number));
 }
 }
 
 
 inline void DescriptorPool::Tables::FindAllExtensions(
 inline void DescriptorPool::Tables::FindAllExtensions(
     const Descriptor* extendee, vector<const FieldDescriptor*>* out) const {
     const Descriptor* extendee, vector<const FieldDescriptor*>* out) const {
   ExtensionsGroupedByDescriptorMap::const_iterator it =
   ExtensionsGroupedByDescriptorMap::const_iterator it =
-      extensions_.lower_bound(make_pair(extendee, 0));
+      extensions_.lower_bound(std::make_pair(extendee, 0));
   for (; it != extensions_.end() && it->first.first == extendee; ++it) {
   for (; it != extensions_.end() && it->first.first == extendee; ++it) {
     out->push_back(it->second);
     out->push_back(it->second);
   }
   }
@@ -993,7 +992,7 @@ void FileDescriptorTables::BuildLocationsByPath(
 const SourceCodeInfo_Location* FileDescriptorTables::GetSourceLocation(
 const SourceCodeInfo_Location* FileDescriptorTables::GetSourceLocation(
     const vector<int>& path, const SourceCodeInfo* info) const {
     const vector<int>& path, const SourceCodeInfo* info) const {
   pair<const FileDescriptorTables*, const SourceCodeInfo*> p(
   pair<const FileDescriptorTables*, const SourceCodeInfo*> p(
-      make_pair(this, info));
+      std::make_pair(this, info));
   locations_by_path_once_.Init(&FileDescriptorTables::BuildLocationsByPath, &p);
   locations_by_path_once_.Init(&FileDescriptorTables::BuildLocationsByPath, &p);
   return FindPtrOrNull(locations_by_path_, Join(path, ","));
   return FindPtrOrNull(locations_by_path_, Join(path, ","));
 }
 }
@@ -1929,9 +1928,9 @@ bool FormatLineOptions(int depth, const Message &options, string *output) {
   return !all_options.empty();
   return !all_options.empty();
 }
 }
 
 
-template<typename DescType>
 class SourceLocationCommentPrinter {
 class SourceLocationCommentPrinter {
  public:
  public:
+  template<typename DescType>
   SourceLocationCommentPrinter(const DescType* desc,
   SourceLocationCommentPrinter(const DescType* desc,
                                const string& prefix,
                                const string& prefix,
                                const DebugStringOptions& options)
                                const DebugStringOptions& options)
@@ -1941,9 +1940,27 @@ class SourceLocationCommentPrinter {
     have_source_loc_ = options.include_comments &&
     have_source_loc_ = options.include_comments &&
         desc->GetSourceLocation(&source_loc_);
         desc->GetSourceLocation(&source_loc_);
   }
   }
+  SourceLocationCommentPrinter(const FileDescriptor* file,
+                               const vector<int>& path,
+                               const string& prefix,
+                               const DebugStringOptions& options)
+      : options_(options), prefix_(prefix) {
+    // Perform the SourceLocation lookup only if we're including user comments,
+    // because the lookup is fairly expensive.
+    have_source_loc_ = options.include_comments &&
+        file->GetSourceLocation(path, &source_loc_);
+  }
   void AddPreComment(string* output) {
   void AddPreComment(string* output) {
-    if (have_source_loc_ && source_loc_.leading_comments.size() > 0) {
-      *output += FormatComment(source_loc_.leading_comments);
+    if (have_source_loc_) {
+      // Detached leading comments.
+      for (int i = 0 ; i < source_loc_.leading_detached_comments.size(); ++i) {
+        *output += FormatComment(source_loc_.leading_detached_comments[i]);
+        *output += "\n";
+      }
+      // Attached leading comments.
+      if (!source_loc_.leading_comments.empty()) {
+        *output += FormatComment(source_loc_.leading_comments);
+      }
     }
     }
   }
   }
   void AddPostComment(string* output) {
   void AddPostComment(string* output) {
@@ -1967,7 +1984,6 @@ class SourceLocationCommentPrinter {
   }
   }
 
 
  private:
  private:
-  const DescType* desc_;
   bool have_source_loc_;
   bool have_source_loc_;
   SourceLocation source_loc_;
   SourceLocation source_loc_;
   DebugStringOptions options_;
   DebugStringOptions options_;
@@ -1984,10 +2000,18 @@ string FileDescriptor::DebugString() const {
 string FileDescriptor::DebugStringWithOptions(
 string FileDescriptor::DebugStringWithOptions(
     const DebugStringOptions& debug_string_options) const {
     const DebugStringOptions& debug_string_options) const {
   string contents;
   string contents;
-  strings::SubstituteAndAppend(&contents, "syntax = \"$0\";\n\n",
-                               SyntaxName(syntax()));
+  {
+    vector<int> path;
+    path.push_back(FileDescriptorProto::kSyntaxFieldNumber);
+    SourceLocationCommentPrinter syntax_comment(
+        this, path, "", debug_string_options);
+    syntax_comment.AddPreComment(&contents);
+    strings::SubstituteAndAppend(&contents, "syntax = \"$0\";\n\n",
+                                 SyntaxName(syntax()));
+    syntax_comment.AddPostComment(&contents);
+  }
 
 
-  SourceLocationCommentPrinter<FileDescriptor>
+  SourceLocationCommentPrinter
       comment_printer(this, "", debug_string_options);
       comment_printer(this, "", debug_string_options);
   comment_printer.AddPreComment(&contents);
   comment_printer.AddPreComment(&contents);
 
 
@@ -2012,7 +2036,13 @@ string FileDescriptor::DebugStringWithOptions(
   }
   }
 
 
   if (!package().empty()) {
   if (!package().empty()) {
+    vector<int> path;
+    path.push_back(FileDescriptorProto::kPackageFieldNumber);
+    SourceLocationCommentPrinter package_comment(
+        this, path, "", debug_string_options);
+    package_comment.AddPreComment(&contents);
     strings::SubstituteAndAppend(&contents, "package $0;\n\n", package());
     strings::SubstituteAndAppend(&contents, "package $0;\n\n", package());
+    package_comment.AddPostComment(&contents);
   }
   }
 
 
   if (FormatLineOptions(0, options(), &contents)) {
   if (FormatLineOptions(0, options(), &contents)) {
@@ -2087,7 +2117,7 @@ void Descriptor::DebugString(int depth, string *contents,
   string prefix(depth * 2, ' ');
   string prefix(depth * 2, ' ');
   ++depth;
   ++depth;
 
 
-  SourceLocationCommentPrinter<Descriptor>
+  SourceLocationCommentPrinter
       comment_printer(this, prefix, debug_string_options);
       comment_printer(this, prefix, debug_string_options);
   comment_printer.AddPreComment(contents);
   comment_printer.AddPreComment(contents);
 
 
@@ -2217,7 +2247,7 @@ void FieldDescriptor::DebugString(int depth,
     label.push_back(' ');
     label.push_back(' ');
   }
   }
 
 
-  SourceLocationCommentPrinter<FieldDescriptor>
+  SourceLocationCommentPrinter
       comment_printer(this, prefix, debug_string_options);
       comment_printer(this, prefix, debug_string_options);
   comment_printer.AddPreComment(contents);
   comment_printer.AddPreComment(contents);
 
 
@@ -2274,7 +2304,7 @@ void OneofDescriptor::DebugString(int depth, string* contents,
                                   debug_string_options) const {
                                   debug_string_options) const {
   string prefix(depth * 2, ' ');
   string prefix(depth * 2, ' ');
   ++depth;
   ++depth;
-  SourceLocationCommentPrinter<OneofDescriptor>
+  SourceLocationCommentPrinter
       comment_printer(this, prefix, debug_string_options);
       comment_printer(this, prefix, debug_string_options);
   comment_printer.AddPreComment(contents);
   comment_printer.AddPreComment(contents);
   strings::SubstituteAndAppend(
   strings::SubstituteAndAppend(
@@ -2305,7 +2335,7 @@ void EnumDescriptor::DebugString(int depth, string *contents,
   string prefix(depth * 2, ' ');
   string prefix(depth * 2, ' ');
   ++depth;
   ++depth;
 
 
-  SourceLocationCommentPrinter<EnumDescriptor>
+  SourceLocationCommentPrinter
       comment_printer(this, prefix, debug_string_options);
       comment_printer(this, prefix, debug_string_options);
   comment_printer.AddPreComment(contents);
   comment_printer.AddPreComment(contents);
 
 
@@ -2339,7 +2369,7 @@ void EnumValueDescriptor::DebugString(int depth, string *contents,
                                       debug_string_options) const {
                                       debug_string_options) const {
   string prefix(depth * 2, ' ');
   string prefix(depth * 2, ' ');
 
 
-  SourceLocationCommentPrinter<EnumValueDescriptor>
+  SourceLocationCommentPrinter
       comment_printer(this, prefix, debug_string_options);
       comment_printer(this, prefix, debug_string_options);
   comment_printer.AddPreComment(contents);
   comment_printer.AddPreComment(contents);
 
 
@@ -2370,7 +2400,7 @@ string ServiceDescriptor::DebugStringWithOptions(
 void ServiceDescriptor::DebugString(string *contents,
 void ServiceDescriptor::DebugString(string *contents,
                                     const DebugStringOptions&
                                     const DebugStringOptions&
                                     debug_string_options) const {
                                     debug_string_options) const {
-  SourceLocationCommentPrinter<ServiceDescriptor>
+  SourceLocationCommentPrinter
       comment_printer(this, /* prefix */ "", debug_string_options);
       comment_printer(this, /* prefix */ "", debug_string_options);
   comment_printer.AddPreComment(contents);
   comment_printer.AddPreComment(contents);
 
 
@@ -2405,7 +2435,7 @@ void MethodDescriptor::DebugString(int depth, string *contents,
   string prefix(depth * 2, ' ');
   string prefix(depth * 2, ' ');
   ++depth;
   ++depth;
 
 
-  SourceLocationCommentPrinter<MethodDescriptor>
+  SourceLocationCommentPrinter
       comment_printer(this, prefix, debug_string_options);
       comment_printer(this, prefix, debug_string_options);
   comment_printer.AddPreComment(contents);
   comment_printer.AddPreComment(contents);
 
 
@@ -2445,6 +2475,9 @@ bool FileDescriptor::GetSourceLocation(const vector<int>& path,
 
 
         out_location->leading_comments = loc->leading_comments();
         out_location->leading_comments = loc->leading_comments();
         out_location->trailing_comments = loc->trailing_comments();
         out_location->trailing_comments = loc->trailing_comments();
+        out_location->leading_detached_comments.assign(
+            loc->leading_detached_comments().begin(),
+            loc->leading_detached_comments().end());
         return true;
         return true;
       }
       }
     }
     }
@@ -3697,7 +3730,6 @@ const FileDescriptor* DescriptorBuilder::BuildFile(
              "Unrecognized syntax: " + proto.syntax());
              "Unrecognized syntax: " + proto.syntax());
   }
   }
 
 
-
   result->name_ = tables_->AllocateString(proto.name());
   result->name_ = tables_->AllocateString(proto.name());
   if (proto.has_package()) {
   if (proto.has_package()) {
     result->package_ = tables_->AllocateString(proto.package());
     result->package_ = tables_->AllocateString(proto.package());
@@ -5110,7 +5142,7 @@ bool DescriptorBuilder::ValidateMapEntry(FieldDescriptor* field,
     case FieldDescriptor::TYPE_SFIXED64:
     case FieldDescriptor::TYPE_SFIXED64:
       // Legal cases
       // Legal cases
       break;
       break;
-    // Do not add a default, so that the compiler will complian when new types
+    // Do not add a default, so that the compiler will complain when new types
     // are added.
     // are added.
   }
   }
 
 
@@ -5123,7 +5155,7 @@ void DescriptorBuilder::DetectMapConflicts(const Descriptor* message,
   for (int i = 0; i < message->nested_type_count(); ++i) {
   for (int i = 0; i < message->nested_type_count(); ++i) {
     const Descriptor* nested = message->nested_type(i);
     const Descriptor* nested = message->nested_type(i);
     pair<map<string, const Descriptor*>::iterator, bool> result =
     pair<map<string, const Descriptor*>::iterator, bool> result =
-        seen_types.insert(make_pair(nested->name(), nested));
+        seen_types.insert(std::make_pair(nested->name(), nested));
     if (!result.second) {
     if (!result.second) {
       if (result.first->second->options().map_entry() ||
       if (result.first->second->options().map_entry() ||
           nested->options().map_entry()) {
           nested->options().map_entry()) {

+ 12 - 12
src/google/protobuf/descriptor.h

@@ -117,8 +117,10 @@ struct SourceLocation {
   int end_column;
   int end_column;
 
 
   // Doc comments found at the source location.
   // Doc comments found at the source location.
+  // See the comments in SourceCodeInfo.Location (descriptor.proto) for details.
   string leading_comments;
   string leading_comments;
   string trailing_comments;
   string trailing_comments;
+  vector<string> leading_detached_comments;
 };
 };
 
 
 // Options when generating machine-parsable output from a descriptor with
 // Options when generating machine-parsable output from a descriptor with
@@ -312,7 +314,7 @@ class LIBPROTOBUF_EXPORT Descriptor {
 
 
   // Walks up the descriptor tree to generate the source location path
   // Walks up the descriptor tree to generate the source location path
   // to this descriptor from the file root.
   // to this descriptor from the file root.
-  void GetLocationPath(vector<int>* output) const;
+  void GetLocationPath(std::vector<int>* output) const;
 
 
   const string* name_;
   const string* name_;
   const string* full_name_;
   const string* full_name_;
@@ -594,7 +596,7 @@ class LIBPROTOBUF_EXPORT FieldDescriptor {
 
 
   // Walks up the descriptor tree to generate the source location path
   // Walks up the descriptor tree to generate the source location path
   // to this descriptor from the file root.
   // to this descriptor from the file root.
-  void GetLocationPath(vector<int>* output) const;
+  void GetLocationPath(std::vector<int>* output) const;
 
 
   const string* name_;
   const string* name_;
   const string* full_name_;
   const string* full_name_;
@@ -688,7 +690,7 @@ class LIBPROTOBUF_EXPORT OneofDescriptor {
 
 
   // Walks up the descriptor tree to generate the source location path
   // Walks up the descriptor tree to generate the source location path
   // to this descriptor from the file root.
   // to this descriptor from the file root.
-  void GetLocationPath(vector<int>* output) const;
+  void GetLocationPath(std::vector<int>* output) const;
 
 
   const string* name_;
   const string* name_;
   const string* full_name_;
   const string* full_name_;
@@ -790,7 +792,7 @@ class LIBPROTOBUF_EXPORT EnumDescriptor {
 
 
   // Walks up the descriptor tree to generate the source location path
   // Walks up the descriptor tree to generate the source location path
   // to this descriptor from the file root.
   // to this descriptor from the file root.
-  void GetLocationPath(vector<int>* output) const;
+  void GetLocationPath(std::vector<int>* output) const;
 
 
   const string* name_;
   const string* name_;
   const string* full_name_;
   const string* full_name_;
@@ -874,7 +876,7 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptor {
 
 
   // Walks up the descriptor tree to generate the source location path
   // Walks up the descriptor tree to generate the source location path
   // to this descriptor from the file root.
   // to this descriptor from the file root.
-  void GetLocationPath(vector<int>* output) const;
+  void GetLocationPath(std::vector<int>* output) const;
 
 
   const string* name_;
   const string* name_;
   const string* full_name_;
   const string* full_name_;
@@ -949,7 +951,7 @@ class LIBPROTOBUF_EXPORT ServiceDescriptor {
 
 
   // Walks up the descriptor tree to generate the source location path
   // Walks up the descriptor tree to generate the source location path
   // to this descriptor from the file root.
   // to this descriptor from the file root.
-  void GetLocationPath(vector<int>* output) const;
+  void GetLocationPath(std::vector<int>* output) const;
 
 
   const string* name_;
   const string* name_;
   const string* full_name_;
   const string* full_name_;
@@ -1028,7 +1030,7 @@ class LIBPROTOBUF_EXPORT MethodDescriptor {
 
 
   // Walks up the descriptor tree to generate the source location path
   // Walks up the descriptor tree to generate the source location path
   // to this descriptor from the file root.
   // to this descriptor from the file root.
-  void GetLocationPath(vector<int>* output) const;
+  void GetLocationPath(std::vector<int>* output) const;
 
 
   const string* name_;
   const string* name_;
   const string* full_name_;
   const string* full_name_;
@@ -1173,17 +1175,15 @@ class LIBPROTOBUF_EXPORT FileDescriptor {
   // this file declaration (namely, the empty path).
   // this file declaration (namely, the empty path).
   bool GetSourceLocation(SourceLocation* out_location) const;
   bool GetSourceLocation(SourceLocation* out_location) const;
 
 
- private:
-  // Source Location ---------------------------------------------------
-
   // Updates |*out_location| to the source location of the complete
   // Updates |*out_location| to the source location of the complete
   // extent of the declaration or declaration-part denoted by |path|.
   // extent of the declaration or declaration-part denoted by |path|.
   // Returns false and leaves |*out_location| unchanged iff location
   // Returns false and leaves |*out_location| unchanged iff location
   // information was not available.  (See SourceCodeInfo for
   // information was not available.  (See SourceCodeInfo for
   // description of path encoding.)
   // description of path encoding.)
-  bool GetSourceLocation(const vector<int>& path,
+  bool GetSourceLocation(const std::vector<int>& path,
                          SourceLocation* out_location) const;
                          SourceLocation* out_location) const;
 
 
+ private:
   typedef FileOptions OptionsType;
   typedef FileOptions OptionsType;
 
 
   const string* name_;
   const string* name_;
@@ -1326,7 +1326,7 @@ class LIBPROTOBUF_EXPORT DescriptorPool {
   // found: extensions defined in the fallback database might not be found
   // found: extensions defined in the fallback database might not be found
   // depending on the database implementation.
   // depending on the database implementation.
   void FindAllExtensions(const Descriptor* extendee,
   void FindAllExtensions(const Descriptor* extendee,
-                         vector<const FieldDescriptor*>* out) const;
+                         std::vector<const FieldDescriptor*>* out) const;
 
 
   // Building descriptors --------------------------------------------
   // Building descriptors --------------------------------------------
 
 

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 905 - 54
src/google/protobuf/descriptor.pb.cc


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 419 - 407
src/google/protobuf/descriptor.pb.h


+ 19 - 4
src/google/protobuf/descriptor.proto

@@ -172,9 +172,7 @@ message FieldDescriptorProto {
   optional string default_value = 7;
   optional string default_value = 7;
 
 
   // If set, gives the index of a oneof in the containing type's oneof_decl
   // If set, gives the index of a oneof in the containing type's oneof_decl
-  // list.  This field is a member of that oneof.  Extensions of a oneof should
-  // not set this since the oneof to which they belong will be inferred based
-  // on the extension range containing the extension's field number.
+  // list.  This field is a member of that oneof.
   optional int32 oneof_index = 9;
   optional int32 oneof_index = 9;
 
 
   optional FieldOptions options = 8;
   optional FieldOptions options = 8;
@@ -344,12 +342,15 @@ message FileOptions {
   // least, this is a formalization for deprecating files.
   // least, this is a formalization for deprecating files.
   optional bool deprecated = 23 [default=false];
   optional bool deprecated = 23 [default=false];
 
 
-
   // Enables the use of arenas for the proto messages in this file. This applies
   // Enables the use of arenas for the proto messages in this file. This applies
   // only to generated classes for C++.
   // only to generated classes for C++.
   optional bool cc_enable_arenas = 31 [default=false];
   optional bool cc_enable_arenas = 31 [default=false];
 
 
 
 
+  // Sets the objective c class prefix which is prepended to all objective c
+  // generated classes from this .proto. There is no default.
+  optional string objc_class_prefix = 36;
+
   // The parser stores options it doesn't recognize here. See above.
   // The parser stores options it doesn't recognize here. See above.
   repeated UninterpretedOption uninterpreted_option = 999;
   repeated UninterpretedOption uninterpreted_option = 999;
 
 
@@ -681,6 +682,11 @@ message SourceCodeInfo {
     // A series of line comments appearing on consecutive lines, with no other
     // A series of line comments appearing on consecutive lines, with no other
     // tokens appearing on those lines, will be treated as a single comment.
     // tokens appearing on those lines, will be treated as a single comment.
     //
     //
+    // leading_detached_comments will keep paragraphs of comments that appear
+    // before (but not connected to) the current element. Each paragraph,
+    // separated by empty lines, will be one comment element in the repeated
+    // field.
+    //
     // Only the comment content is provided; comment markers (e.g. //) are
     // Only the comment content is provided; comment markers (e.g. //) are
     // stripped out.  For block comments, leading whitespace and an asterisk
     // stripped out.  For block comments, leading whitespace and an asterisk
     // will be stripped from the beginning of each line other than the first.
     // will be stripped from the beginning of each line other than the first.
@@ -701,6 +707,12 @@ message SourceCodeInfo {
     //   // Another line attached to qux.
     //   // Another line attached to qux.
     //   optional double qux = 4;
     //   optional double qux = 4;
     //
     //
+    //   // Detached comment for corge. This is not leading or trailing comments
+    //   // to qux or corge because there are blank lines separating it from
+    //   // both.
+    //
+    //   // Detached comment for corge paragraph 2.
+    //
     //   optional string corge = 5;
     //   optional string corge = 5;
     //   /* Block comment attached
     //   /* Block comment attached
     //    * to corge.  Leading asterisks
     //    * to corge.  Leading asterisks
@@ -708,7 +720,10 @@ message SourceCodeInfo {
     //   /* Block comment attached to
     //   /* Block comment attached to
     //    * grault. */
     //    * grault. */
     //   optional int32 grault = 6;
     //   optional int32 grault = 6;
+    //
+    //   // ignored detached comments.
     optional string leading_comments = 3;
     optional string leading_comments = 3;
     optional string trailing_comments = 4;
     optional string trailing_comments = 4;
+    repeated string leading_detached_comments = 6;
   }
   }
 }
 }

+ 14 - 14
src/google/protobuf/descriptor_database.cc

@@ -153,10 +153,10 @@ bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddExtension(
   if (!field.extendee().empty() && field.extendee()[0] == '.') {
   if (!field.extendee().empty() && field.extendee()[0] == '.') {
     // The extension is fully-qualified.  We can use it as a lookup key in
     // The extension is fully-qualified.  We can use it as a lookup key in
     // the by_symbol_ table.
     // the by_symbol_ table.
-    if (!InsertIfNotPresent(&by_extension_,
-                            make_pair(field.extendee().substr(1),
-                                      field.number()),
-                            value)) {
+    if (!InsertIfNotPresent(
+            &by_extension_,
+            std::make_pair(field.extendee().substr(1), field.number()),
+            value)) {
       GOOGLE_LOG(ERROR) << "Extension conflicts with extension already in database: "
       GOOGLE_LOG(ERROR) << "Extension conflicts with extension already in database: "
                     "extend " << field.extendee() << " { "
                     "extend " << field.extendee() << " { "
                  << field.name() << " = " << field.number() << " }";
                  << field.name() << " = " << field.number() << " }";
@@ -189,17 +189,16 @@ template <typename Value>
 Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindExtension(
 Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindExtension(
     const string& containing_type,
     const string& containing_type,
     int field_number) {
     int field_number) {
-  return FindWithDefault(by_extension_,
-                         make_pair(containing_type, field_number),
-                         Value());
+  return FindWithDefault(
+      by_extension_, std::make_pair(containing_type, field_number), Value());
 }
 }
 
 
 template <typename Value>
 template <typename Value>
 bool SimpleDescriptorDatabase::DescriptorIndex<Value>::FindAllExtensionNumbers(
 bool SimpleDescriptorDatabase::DescriptorIndex<Value>::FindAllExtensionNumbers(
     const string& containing_type,
     const string& containing_type,
     vector<int>* output) {
     vector<int>* output) {
-  typename map<pair<string, int>, Value >::const_iterator it =
-      by_extension_.lower_bound(make_pair(containing_type, 0));
+  typename map<pair<string, int>, Value>::const_iterator it =
+      by_extension_.lower_bound(std::make_pair(containing_type, 0));
   bool success = false;
   bool success = false;
 
 
   for (; it != by_extension_.end() && it->first.first == containing_type;
   for (; it != by_extension_.end() && it->first.first == containing_type;
@@ -310,7 +309,7 @@ bool EncodedDescriptorDatabase::Add(
     const void* encoded_file_descriptor, int size) {
     const void* encoded_file_descriptor, int size) {
   FileDescriptorProto file;
   FileDescriptorProto file;
   if (file.ParseFromArray(encoded_file_descriptor, size)) {
   if (file.ParseFromArray(encoded_file_descriptor, size)) {
-    return index_.AddFile(file, make_pair(encoded_file_descriptor, size));
+    return index_.AddFile(file, std::make_pair(encoded_file_descriptor, size));
   } else {
   } else {
     GOOGLE_LOG(ERROR) << "Invalid file descriptor data passed to "
     GOOGLE_LOG(ERROR) << "Invalid file descriptor data passed to "
                   "EncodedDescriptorDatabase::Add().";
                   "EncodedDescriptorDatabase::Add().";
@@ -525,15 +524,16 @@ bool MergedDescriptorDatabase::FindAllExtensionNumbers(
 
 
   for (int i = 0; i < sources_.size(); i++) {
   for (int i = 0; i < sources_.size(); i++) {
     if (sources_[i]->FindAllExtensionNumbers(extendee_type, &results)) {
     if (sources_[i]->FindAllExtensionNumbers(extendee_type, &results)) {
-      copy(results.begin(), results.end(),
-           insert_iterator<set<int> >(merged_results, merged_results.begin()));
+      std::copy(
+          results.begin(), results.end(),
+          insert_iterator<set<int> >(merged_results, merged_results.begin()));
       success = true;
       success = true;
     }
     }
     results.clear();
     results.clear();
   }
   }
 
 
-  copy(merged_results.begin(), merged_results.end(),
-       insert_iterator<vector<int> >(*output, output->end()));
+  std::copy(merged_results.begin(), merged_results.end(),
+            insert_iterator<vector<int> >(*output, output->end()));
 
 
   return success;
   return success;
 }
 }

+ 3 - 3
src/google/protobuf/descriptor_database_unittest.cc

@@ -408,7 +408,7 @@ TEST_P(DescriptorDatabaseTest, FindAllExtensionNumbers) {
     vector<int> numbers;
     vector<int> numbers;
     EXPECT_TRUE(database_->FindAllExtensionNumbers("Foo", &numbers));
     EXPECT_TRUE(database_->FindAllExtensionNumbers("Foo", &numbers));
     ASSERT_EQ(2, numbers.size());
     ASSERT_EQ(2, numbers.size());
-    sort(numbers.begin(), numbers.end());
+    std::sort(numbers.begin(), numbers.end());
     EXPECT_EQ(5, numbers[0]);
     EXPECT_EQ(5, numbers[0]);
     EXPECT_EQ(32, numbers[1]);
     EXPECT_EQ(32, numbers[1]);
   }
   }
@@ -722,7 +722,7 @@ TEST_F(MergedDescriptorDatabaseTest, FindAllExtensionNumbers) {
     vector<int> numbers;
     vector<int> numbers;
     EXPECT_TRUE(forward_merged_.FindAllExtensionNumbers("Baz", &numbers));
     EXPECT_TRUE(forward_merged_.FindAllExtensionNumbers("Baz", &numbers));
     ASSERT_EQ(2, numbers.size());
     ASSERT_EQ(2, numbers.size());
-    sort(numbers.begin(), numbers.end());
+    std::sort(numbers.begin(), numbers.end());
     EXPECT_EQ(12, numbers[0]);
     EXPECT_EQ(12, numbers[0]);
     EXPECT_EQ(13, numbers[1]);
     EXPECT_EQ(13, numbers[1]);
   }
   }
@@ -731,7 +731,7 @@ TEST_F(MergedDescriptorDatabaseTest, FindAllExtensionNumbers) {
     vector<int> numbers;
     vector<int> numbers;
     EXPECT_TRUE(reverse_merged_.FindAllExtensionNumbers("Baz", &numbers));
     EXPECT_TRUE(reverse_merged_.FindAllExtensionNumbers("Baz", &numbers));
     ASSERT_EQ(2, numbers.size());
     ASSERT_EQ(2, numbers.size());
-    sort(numbers.begin(), numbers.end());
+    std::sort(numbers.begin(), numbers.end());
     EXPECT_EQ(12, numbers[0]);
     EXPECT_EQ(12, numbers[0]);
     EXPECT_EQ(13, numbers[1]);
     EXPECT_EQ(13, numbers[1]);
   }
   }

+ 0 - 54
src/google/protobuf/descriptor_pb2_test.py

@@ -1,54 +0,0 @@
-#! /usr/bin/python
-#
-# 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.
-
-# Verify that prebuild and checkedin version of descriptor_pb2.py is up to date.
-
-from google3.pyglib import resources
-from google.apputils import basetest
-
-_DESC = 'google3/net/proto2/proto/descriptor_pb2.'
-_OLD = _DESC + 'py-prebuilt'
-_NEW = _DESC + 'compiled'
-
-
-class PregeneratedFileChanged(basetest.TestCase):
-
-  def testSameText(self):
-    generated = resources.GetResource(_NEW)
-    checkedin = resources.GetResource(_OLD)
-    self.assertMultiLineEqual(
-        generated, checkedin, 'It seems that protoc _pb2 generator changed. '
-        'Please run google/protobuf/generate_descriptor_proto.sh to '
-        'regnerate a new version of %s and add it to your CL' % _OLD)
-
-if __name__ == '__main__':
-  basetest.main()

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

@@ -6104,9 +6104,9 @@ TEST_F(CopySourceCodeInfoToTest, CopySourceCodeInfoTo) {
 
 
   file_desc->CopySourceCodeInfoTo(&file_desc_proto);
   file_desc->CopySourceCodeInfoTo(&file_desc_proto);
   const SourceCodeInfo& info = file_desc_proto.source_code_info();
   const SourceCodeInfo& info = file_desc_proto.source_code_info();
-  ASSERT_EQ(3, info.location_size());
+  ASSERT_EQ(4, info.location_size());
   // Get the Foo message location
   // Get the Foo message location
-  const SourceCodeInfo_Location& foo_location = info.location(1);
+  const SourceCodeInfo_Location& foo_location = info.location(2);
   ASSERT_EQ(2, foo_location.path_size());
   ASSERT_EQ(2, foo_location.path_size());
   EXPECT_EQ(FileDescriptorProto::kMessageTypeFieldNumber, foo_location.path(0));
   EXPECT_EQ(FileDescriptorProto::kMessageTypeFieldNumber, foo_location.path(0));
   EXPECT_EQ(0, foo_location.path(1));      // Foo is the first message defined
   EXPECT_EQ(0, foo_location.path(1));      // Foo is the first message defined

+ 10 - 6
src/google/protobuf/extension_set.cc

@@ -97,7 +97,7 @@ void Register(const MessageLite* containing_type,
               int number, ExtensionInfo info) {
               int number, ExtensionInfo info) {
   ::google::protobuf::GoogleOnceInit(&registry_init_, &InitRegistry);
   ::google::protobuf::GoogleOnceInit(&registry_init_, &InitRegistry);
 
 
-  if (!InsertIfNotPresent(registry_, make_pair(containing_type, number),
+  if (!InsertIfNotPresent(registry_, std::make_pair(containing_type, number),
                           info)) {
                           info)) {
     GOOGLE_LOG(FATAL) << "Multiple extension registrations for type \""
     GOOGLE_LOG(FATAL) << "Multiple extension registrations for type \""
                << containing_type->GetTypeName()
                << containing_type->GetTypeName()
@@ -107,8 +107,9 @@ void Register(const MessageLite* containing_type,
 
 
 const ExtensionInfo* FindRegisteredExtension(
 const ExtensionInfo* FindRegisteredExtension(
     const MessageLite* containing_type, int number) {
     const MessageLite* containing_type, int number) {
-  return (registry_ == NULL) ? NULL :
-         FindOrNull(*registry_, make_pair(containing_type, number));
+  return (registry_ == NULL)
+             ? NULL
+             : FindOrNull(*registry_, std::make_pair(containing_type, number));
 }
 }
 
 
 }  // namespace
 }  // namespace
@@ -1032,7 +1033,7 @@ void ExtensionSet::SwapExtension(ExtensionSet* other,
 
 
   if (this_iter == extensions_.end()) {
   if (this_iter == extensions_.end()) {
     if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
     if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
-      extensions_.insert(make_pair(number, other_iter->second));
+      extensions_.insert(std::make_pair(number, other_iter->second));
     } else {
     } else {
       InternalExtensionMergeFrom(number, other_iter->second);
       InternalExtensionMergeFrom(number, other_iter->second);
     }
     }
@@ -1042,7 +1043,7 @@ void ExtensionSet::SwapExtension(ExtensionSet* other,
 
 
   if (other_iter == other->extensions_.end()) {
   if (other_iter == other->extensions_.end()) {
     if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
     if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
-      other->extensions_.insert(make_pair(number, this_iter->second));
+      other->extensions_.insert(std::make_pair(number, this_iter->second));
     } else {
     } else {
       other->InternalExtensionMergeFrom(number, this_iter->second);
       other->InternalExtensionMergeFrom(number, this_iter->second);
     }
     }
@@ -1175,6 +1176,9 @@ bool ExtensionSet::ParseFieldWithExtensionInfo(
                   extension.enum_validity_check.arg, value)) {
                   extension.enum_validity_check.arg, value)) {
             AddEnum(number, WireFormatLite::TYPE_ENUM, extension.is_packed,
             AddEnum(number, WireFormatLite::TYPE_ENUM, extension.is_packed,
                     value, extension.descriptor);
                     value, extension.descriptor);
+          } else {
+            // Invalid value.  Treat as unknown.
+            field_skipper->SkipUnknownEnum(number, value);
           }
           }
         }
         }
         break;
         break;
@@ -1337,7 +1341,7 @@ bool ExtensionSet::MaybeNewExtension(int number,
                                      const FieldDescriptor* descriptor,
                                      const FieldDescriptor* descriptor,
                                      Extension** result) {
                                      Extension** result) {
   pair<map<int, Extension>::iterator, bool> insert_result =
   pair<map<int, Extension>::iterator, bool> insert_result =
-    extensions_.insert(make_pair(number, Extension()));
+      extensions_.insert(std::make_pair(number, Extension()));
   *result = &insert_result.first->second;
   *result = &insert_result.first->second;
   (*result)->descriptor = descriptor;
   (*result)->descriptor = descriptor;
   return insert_result.second;
   return insert_result.second;

+ 4 - 3
src/google/protobuf/extension_set_heavy.cc

@@ -91,9 +91,10 @@ class DescriptorPoolExtensionFinder : public ExtensionFinder {
   const Descriptor* containing_type_;
   const Descriptor* containing_type_;
 };
 };
 
 
-void ExtensionSet::AppendToList(const Descriptor* containing_type,
-                                const DescriptorPool* pool,
-                                vector<const FieldDescriptor*>* output) const {
+void ExtensionSet::AppendToList(
+    const Descriptor* containing_type,
+    const DescriptorPool* pool,
+    std::vector<const FieldDescriptor*>* output) const {
   for (map<int, Extension>::const_iterator iter = extensions_.begin();
   for (map<int, Extension>::const_iterator iter = extensions_.begin();
        iter != extensions_.end(); ++iter) {
        iter != extensions_.end(); ++iter) {
     bool has = false;
     bool has = false;

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

@@ -42,6 +42,7 @@
 #include <string>
 #include <string>
 
 
 #include <google/protobuf/stubs/template_util.h>
 #include <google/protobuf/stubs/template_util.h>
+#include <google/protobuf/generated_enum_util.h>
 
 
 namespace google {
 namespace google {
 namespace protobuf {
 namespace protobuf {
@@ -50,10 +51,6 @@ namespace protobuf {
 
 
 namespace protobuf {
 namespace protobuf {
 
 
-// This type trait can be used to cause templates to only match proto2 enum
-// types.
-template <typename T> struct is_proto_enum : ::google::protobuf::internal::false_type {};
-
 // Returns the EnumDescriptor for enum type E, which must be a
 // Returns the EnumDescriptor for enum type E, which must be a
 // proto-declared enum type.  Code generated by the protocol compiler
 // proto-declared enum type.  Code generated by the protocol compiler
 // will include specializations of this template for each enum type declared.
 // will include specializations of this template for each enum type declared.

+ 46 - 0
src/google/protobuf/generated_enum_util.h

@@ -0,0 +1,46 @@
+// 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_GENERATED_ENUM_UTIL_H__
+#define GOOGLE_PROTOBUF_GENERATED_ENUM_UTIL_H__
+
+#include <google/protobuf/stubs/template_util.h>
+
+namespace google {
+namespace protobuf {
+
+// This type trait can be used to cause templates to only match proto2 enum
+// types.
+template <typename T> struct is_proto_enum : ::google::protobuf::internal::false_type {};
+
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_GENERATED_ENUM_UTIL_H__

+ 23 - 18
src/google/protobuf/generated_message_reflection.cc

@@ -995,6 +995,7 @@ void GeneratedMessageReflection::ListFields(
   // Optimization:  The default instance never has any fields set.
   // Optimization:  The default instance never has any fields set.
   if (&message == default_instance_) return;
   if (&message == default_instance_) return;
 
 
+  output->reserve(descriptor_->field_count());
   for (int i = 0; i < descriptor_->field_count(); i++) {
   for (int i = 0; i < descriptor_->field_count(); i++) {
     const FieldDescriptor* field = descriptor_->field(i);
     const FieldDescriptor* field = descriptor_->field(i);
     if (field->is_repeated()) {
     if (field->is_repeated()) {
@@ -1018,7 +1019,7 @@ void GeneratedMessageReflection::ListFields(
   }
   }
 
 
   // ListFields() must sort output by field number.
   // ListFields() must sort output by field number.
-  sort(output->begin(), output->end(), FieldNumberSorter());
+  std::sort(output->begin(), output->end(), FieldNumberSorter());
 }
 }
 
 
 // -------------------------------------------------------------------
 // -------------------------------------------------------------------
@@ -1434,6 +1435,8 @@ const Message& GeneratedMessageReflection::GetMessage(
 Message* GeneratedMessageReflection::MutableMessage(
 Message* GeneratedMessageReflection::MutableMessage(
     Message* message, const FieldDescriptor* field,
     Message* message, const FieldDescriptor* field,
     MessageFactory* factory) const {
     MessageFactory* factory) const {
+  USAGE_CHECK_ALL(MutableMessage, SINGULAR, MESSAGE);
+
   if (factory == NULL) factory = message_factory_;
   if (factory == NULL) factory = message_factory_;
 
 
   if (field->is_extension()) {
   if (field->is_extension()) {
@@ -1972,26 +1975,28 @@ inline void GeneratedMessageReflection::ClearOneof(
   uint32 oneof_case = GetOneofCase(*message, oneof_descriptor);
   uint32 oneof_case = GetOneofCase(*message, oneof_descriptor);
   if (oneof_case > 0) {
   if (oneof_case > 0) {
     const FieldDescriptor* field = descriptor_->FindFieldByNumber(oneof_case);
     const FieldDescriptor* field = descriptor_->FindFieldByNumber(oneof_case);
-    switch (field->cpp_type()) {
-      case FieldDescriptor::CPPTYPE_STRING: {
-        switch (field->options().ctype()) {
-          default:  // TODO(kenton):  Support other string reps.
-          case FieldOptions::STRING: {
-            const string* default_ptr =
-                &DefaultRaw<ArenaStringPtr>(field).Get(NULL);
-            MutableField<ArenaStringPtr>(message, field)->
-                Destroy(default_ptr, GetArena(message));
-            break;
+    if (GetArena(message) == NULL) {
+      switch (field->cpp_type()) {
+        case FieldDescriptor::CPPTYPE_STRING: {
+          switch (field->options().ctype()) {
+            default:  // TODO(kenton):  Support other string reps.
+            case FieldOptions::STRING: {
+              const string* default_ptr =
+                  &DefaultRaw<ArenaStringPtr>(field).Get(NULL);
+              MutableField<ArenaStringPtr>(message, field)->
+                  Destroy(default_ptr, GetArena(message));
+              break;
+            }
           }
           }
+          break;
         }
         }
-        break;
-      }
 
 
-      case FieldDescriptor::CPPTYPE_MESSAGE:
-        delete *MutableRaw<Message*>(message, field);
-        break;
-      default:
-        break;
+        case FieldDescriptor::CPPTYPE_MESSAGE:
+          delete *MutableRaw<Message*>(message, field);
+          break;
+        default:
+          break;
+      }
     }
     }
 
 
     *MutableOneofCase(message, oneof_descriptor) = 0;
     *MutableOneofCase(message, oneof_descriptor) = 0;

+ 15 - 62
src/google/protobuf/io/coded_stream.cc

@@ -153,7 +153,7 @@ void CodedInputStream::PopLimit(Limit limit) {
 
 
 std::pair<CodedInputStream::Limit, int>
 std::pair<CodedInputStream::Limit, int>
 CodedInputStream::IncrementRecursionDepthAndPushLimit(int byte_limit) {
 CodedInputStream::IncrementRecursionDepthAndPushLimit(int byte_limit) {
-  return make_pair(PushLimit(byte_limit), --recursion_budget_);
+  return std::make_pair(PushLimit(byte_limit), --recursion_budget_);
 }
 }
 
 
 bool CodedInputStream::DecrementRecursionDepthAndPopLimit(Limit limit) {
 bool CodedInputStream::DecrementRecursionDepthAndPopLimit(Limit limit) {
@@ -613,8 +613,15 @@ CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output)
 }
 }
 
 
 CodedOutputStream::~CodedOutputStream() {
 CodedOutputStream::~CodedOutputStream() {
+  Trim();
+}
+
+void CodedOutputStream::Trim() {
   if (buffer_size_ > 0) {
   if (buffer_size_ > 0) {
     output_->BackUp(buffer_size_);
     output_->BackUp(buffer_size_);
+    total_bytes_ -= buffer_size_;
+    buffer_size_ = 0;
+    buffer_ = NULL;
   }
   }
 }
 }
 
 
@@ -662,12 +669,7 @@ void CodedOutputStream::WriteAliasedRaw(const void* data, int size) {
       ) {
       ) {
     WriteRaw(data, size);
     WriteRaw(data, size);
   } else {
   } else {
-    if (buffer_size_ > 0) {
-      output_->BackUp(buffer_size_);
-      total_bytes_ -= buffer_size_;
-      buffer_ = NULL;
-      buffer_size_ = 0;
-    }
+    Trim();
 
 
     total_bytes_ += size;
     total_bytes_ += size;
     had_error_ |= !output_->WriteAliasedRaw(data, size);
     had_error_ |= !output_->WriteAliasedRaw(data, size);
@@ -704,61 +706,12 @@ void CodedOutputStream::WriteLittleEndian64(uint64 value) {
   }
   }
 }
 }
 
 
-inline uint8* CodedOutputStream::WriteVarint32FallbackToArrayInline(
-    uint32 value, uint8* target) {
-  target[0] = static_cast<uint8>(value | 0x80);
-  if (value >= (1 << 7)) {
-    target[1] = static_cast<uint8>((value >>  7) | 0x80);
-    if (value >= (1 << 14)) {
-      target[2] = static_cast<uint8>((value >> 14) | 0x80);
-      if (value >= (1 << 21)) {
-        target[3] = static_cast<uint8>((value >> 21) | 0x80);
-        if (value >= (1 << 28)) {
-          target[4] = static_cast<uint8>(value >> 28);
-          return target + 5;
-        } else {
-          target[3] &= 0x7F;
-          return target + 4;
-        }
-      } else {
-        target[2] &= 0x7F;
-        return target + 3;
-      }
-    } else {
-      target[1] &= 0x7F;
-      return target + 2;
-    }
-  } else {
-    target[0] &= 0x7F;
-    return target + 1;
-  }
-}
-
-void CodedOutputStream::WriteVarint32(uint32 value) {
-  if (buffer_size_ >= kMaxVarint32Bytes) {
-    // Fast path:  We have enough bytes left in the buffer to guarantee that
-    // this write won't cross the end, so we can skip the checks.
-    uint8* target = buffer_;
-    uint8* end = WriteVarint32FallbackToArrayInline(value, target);
-    int size = end - target;
-    Advance(size);
-  } else {
-    // Slow path:  This write might cross the end of the buffer, so we
-    // compose the bytes first then use WriteRaw().
-    uint8 bytes[kMaxVarint32Bytes];
-    int size = 0;
-    while (value > 0x7F) {
-      bytes[size++] = (static_cast<uint8>(value) & 0x7F) | 0x80;
-      value >>= 7;
-    }
-    bytes[size++] = static_cast<uint8>(value) & 0x7F;
-    WriteRaw(bytes, size);
-  }
-}
-
-uint8* CodedOutputStream::WriteVarint32FallbackToArray(
-    uint32 value, uint8* target) {
-  return WriteVarint32FallbackToArrayInline(value, target);
+void CodedOutputStream::WriteVarint32SlowPath(uint32 value) {
+  uint8 bytes[kMaxVarint32Bytes];
+  uint8* target = &bytes[0];
+  uint8* end = WriteVarint32ToArray(value, target);
+  int size = end - target;
+  WriteRaw(bytes, size);
 }
 }
 
 
 inline uint8* CodedOutputStream::WriteVarint64ToArrayInline(
 inline uint8* CodedOutputStream::WriteVarint64ToArrayInline(

+ 34 - 22
src/google/protobuf/io/coded_stream.h

@@ -647,6 +647,13 @@ class LIBPROTOBUF_EXPORT CodedOutputStream {
   // ZeroCopyOutputStream immediately after the last byte written.
   // ZeroCopyOutputStream immediately after the last byte written.
   ~CodedOutputStream();
   ~CodedOutputStream();
 
 
+  // Trims any unused space in the underlying buffer so that its size matches
+  // the number of bytes written by this stream. The underlying buffer will
+  // automatically be trimmed when this stream is destroyed; this call is only
+  // necessary if the underlying buffer is accessed *before* the stream is
+  // destroyed.
+  void Trim();
+
   // Skips a number of bytes, leaving the bytes unmodified in the underlying
   // Skips a number of bytes, leaving the bytes unmodified in the underlying
   // buffer.  Returns false if an underlying write error occurs.  This is
   // buffer.  Returns false if an underlying write error occurs.  This is
   // mainly useful with GetDirectBufferPointer().
   // mainly useful with GetDirectBufferPointer().
@@ -789,7 +796,9 @@ class LIBPROTOBUF_EXPORT CodedOutputStream {
   // ZeroCopyOutputStream supports it.
   // ZeroCopyOutputStream supports it.
   void WriteAliasedRaw(const void* buffer, int size);
   void WriteAliasedRaw(const void* buffer, int size);
 
 
-  static uint8* WriteVarint32FallbackToArray(uint32 value, uint8* target);
+  // If this write might cross the end of the buffer, we compose the bytes first
+  // then use WriteRaw().
+  void WriteVarint32SlowPath(uint32 value);
 
 
   // Always-inlined versions of WriteVarint* functions so that code can be
   // Always-inlined versions of WriteVarint* functions so that code can be
   // reused, while still controlling size. For instance, WriteVarint32ToArray()
   // reused, while still controlling size. For instance, WriteVarint32ToArray()
@@ -798,8 +807,6 @@ class LIBPROTOBUF_EXPORT CodedOutputStream {
   // WriteVarint32FallbackToArray.  Meanwhile, WriteVarint32() is already
   // WriteVarint32FallbackToArray.  Meanwhile, WriteVarint32() is already
   // out-of-line, so it should just invoke this directly to avoid any extra
   // out-of-line, so it should just invoke this directly to avoid any extra
   // function call overhead.
   // function call overhead.
-  static uint8* WriteVarint32FallbackToArrayInline(
-      uint32 value, uint8* target) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
   static uint8* WriteVarint64ToArrayInline(
   static uint8* WriteVarint64ToArrayInline(
       uint64 value, uint8* target) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
       uint64 value, uint8* target) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
 
 
@@ -919,7 +926,7 @@ inline std::pair<uint32, bool> CodedInputStream::ReadTagWithCutoff(
       const uint32 kMax1ByteVarint = 0x7f;
       const uint32 kMax1ByteVarint = 0x7f;
       uint32 tag = last_tag_ = buffer_[0];
       uint32 tag = last_tag_ = buffer_[0];
       Advance(1);
       Advance(1);
-      return make_pair(tag, cutoff >= kMax1ByteVarint || tag <= cutoff);
+      return std::make_pair(tag, cutoff >= kMax1ByteVarint || tag <= cutoff);
     }
     }
     // Other hot case: cutoff >= 0x80, buffer_ has at least two bytes available,
     // Other hot case: cutoff >= 0x80, buffer_ has at least two bytes available,
     // and tag is two bytes.  The latter is tested by bitwise-and-not of the
     // and tag is two bytes.  The latter is tested by bitwise-and-not of the
@@ -937,12 +944,12 @@ inline std::pair<uint32, bool> CodedInputStream::ReadTagWithCutoff(
       // so we don't have to check for tag == 0.  We may need to check whether
       // so we don't have to check for tag == 0.  We may need to check whether
       // it exceeds cutoff.
       // it exceeds cutoff.
       bool at_or_below_cutoff = cutoff >= kMax2ByteVarint || tag <= cutoff;
       bool at_or_below_cutoff = cutoff >= kMax2ByteVarint || tag <= cutoff;
-      return make_pair(tag, at_or_below_cutoff);
+      return std::make_pair(tag, at_or_below_cutoff);
     }
     }
   }
   }
   // Slow path
   // Slow path
   last_tag_ = ReadTagFallback();
   last_tag_ = ReadTagFallback();
-  return make_pair(last_tag_, static_cast<uint32>(last_tag_ - 1) < cutoff);
+  return std::make_pair(last_tag_, static_cast<uint32>(last_tag_ - 1) < cutoff);
 }
 }
 
 
 inline bool CodedInputStream::LastTagWas(uint32 expected) {
 inline bool CodedInputStream::LastTagWas(uint32 expected) {
@@ -1027,13 +1034,14 @@ inline uint8* CodedOutputStream::GetDirectBufferForNBytesAndAdvance(int size) {
 }
 }
 
 
 inline uint8* CodedOutputStream::WriteVarint32ToArray(uint32 value,
 inline uint8* CodedOutputStream::WriteVarint32ToArray(uint32 value,
-                                                        uint8* target) {
-  if (value < 0x80) {
-    *target = value;
-    return target + 1;
-  } else {
-    return WriteVarint32FallbackToArray(value, target);
+                                                      uint8* target) {
+  while (value >= 0x80) {
+    *target = static_cast<uint8>(value | 0x80);
+    value >>= 7;
+    ++target;
   }
   }
+  *target = static_cast<uint8>(value);
+  return target + 1;
 }
 }
 
 
 inline void CodedOutputStream::WriteVarint32SignExtended(int32 value) {
 inline void CodedOutputStream::WriteVarint32SignExtended(int32 value) {
@@ -1086,22 +1094,26 @@ inline uint8* CodedOutputStream::WriteLittleEndian64ToArray(uint64 value,
   return target + sizeof(value);
   return target + sizeof(value);
 }
 }
 
 
+inline void CodedOutputStream::WriteVarint32(uint32 value) {
+  if (buffer_size_ >= 5) {
+    // Fast path:  We have enough bytes left in the buffer to guarantee that
+    // this write won't cross the end, so we can skip the checks.
+    uint8* target = buffer_;
+    uint8* end = WriteVarint32ToArray(value, target);
+    int size = end - target;
+    Advance(size);
+  } else {
+    WriteVarint32SlowPath(value);
+  }
+}
+
 inline void CodedOutputStream::WriteTag(uint32 value) {
 inline void CodedOutputStream::WriteTag(uint32 value) {
   WriteVarint32(value);
   WriteVarint32(value);
 }
 }
 
 
 inline uint8* CodedOutputStream::WriteTagToArray(
 inline uint8* CodedOutputStream::WriteTagToArray(
     uint32 value, uint8* target) {
     uint32 value, uint8* target) {
-  if (value < (1 << 7)) {
-    target[0] = value;
-    return target + 1;
-  } else if (value < (1 << 14)) {
-    target[0] = static_cast<uint8>(value | 0x80);
-    target[1] = static_cast<uint8>(value >> 7);
-    return target + 2;
-  } else {
-    return WriteVarint32FallbackToArray(value, target);
-  }
+  return WriteVarint32ToArray(value, target);
 }
 }
 
 
 inline int CodedOutputStream::VarintSize32(uint32 value) {
 inline int CodedOutputStream::VarintSize32(uint32 value) {

+ 2 - 2
src/google/protobuf/io/coded_stream_unittest.cc

@@ -502,11 +502,11 @@ struct Fixed64Case {
 };
 };
 
 
 inline std::ostream& operator<<(std::ostream& os, const Fixed32Case& c) {
 inline std::ostream& operator<<(std::ostream& os, const Fixed32Case& c) {
-  return os << "0x" << hex << c.value << dec;
+  return os << "0x" << std::hex << c.value << std::dec;
 }
 }
 
 
 inline std::ostream& operator<<(std::ostream& os, const Fixed64Case& c) {
 inline std::ostream& operator<<(std::ostream& os, const Fixed64Case& c) {
-  return os << "0x" << hex << c.value << dec;
+  return os << "0x" << std::hex << c.value << std::dec;
 }
 }
 
 
 Fixed32Case kFixed32Cases[] = {
 Fixed32Case kFixed32Cases[] = {

+ 1 - 0
src/google/protobuf/io/gzip_stream.cc

@@ -49,6 +49,7 @@ static const int kDefaultBufferSize = 65536;
 GzipInputStream::GzipInputStream(
 GzipInputStream::GzipInputStream(
     ZeroCopyInputStream* sub_stream, Format format, int buffer_size)
     ZeroCopyInputStream* sub_stream, Format format, int buffer_size)
     : format_(format), sub_stream_(sub_stream), zerror_(Z_OK), byte_count_(0) {
     : format_(format), sub_stream_(sub_stream), zerror_(Z_OK), byte_count_(0) {
+  zcontext_.state = Z_NULL;
   zcontext_.zalloc = Z_NULL;
   zcontext_.zalloc = Z_NULL;
   zcontext_.zfree = Z_NULL;
   zcontext_.zfree = Z_NULL;
   zcontext_.opaque = Z_NULL;
   zcontext_.opaque = Z_NULL;

+ 1 - 1
src/google/protobuf/io/zero_copy_stream_impl_lite.h

@@ -368,7 +368,7 @@ inline char* mutable_string_data(string* s) {
 inline std::pair<char*, bool> as_string_data(string* s) {
 inline std::pair<char*, bool> as_string_data(string* s) {
   char *p = mutable_string_data(s);
   char *p = mutable_string_data(s);
 #ifdef LANG_CXX11
 #ifdef LANG_CXX11
-  return make_pair(p, true);
+  return std::make_pair(p, true);
 #else
 #else
   return make_pair(p, p != NULL);
   return make_pair(p, p != NULL);
 #endif
 #endif

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

@@ -345,6 +345,6 @@ int main(int argc, char* argv[]) {
     GOOGLE_CHECK_EQ(0, empty_message.unknown_fields().size());
     GOOGLE_CHECK_EQ(0, empty_message.unknown_fields().size());
   }
   }
 
 
-  cout << "PASS" << endl;
+  std::cout << "PASS" << std::endl;
   return 0;
   return 0;
 }
 }

+ 153 - 28
src/google/protobuf/map.h

@@ -34,6 +34,8 @@
 #include <iterator>
 #include <iterator>
 #include <google/protobuf/stubs/hash.h>
 #include <google/protobuf/stubs/hash.h>
 
 
+#include <google/protobuf/arena.h>
+#include <google/protobuf/generated_enum_util.h>
 #include <google/protobuf/map_type_handler.h>
 #include <google/protobuf/map_type_handler.h>
 
 
 namespace google {
 namespace google {
@@ -45,10 +47,12 @@ class Map;
 template <typename Enum> struct is_proto_enum;
 template <typename Enum> struct is_proto_enum;
 
 
 namespace internal {
 namespace internal {
-template <typename K, typename V, FieldDescriptor::Type KeyProto,
-          FieldDescriptor::Type ValueProto, int default_enum_value>
-class MapField;
-}  // namespace internal
+template <typename Key, typename T,
+          WireFormatLite::FieldType key_wire_type,
+          WireFormatLite::FieldType value_wire_type,
+          int default_enum_value>
+class MapFieldLite;
+}
 
 
 // This is the class for google::protobuf::Map's internal value_type. Instead of using
 // This is the class for google::protobuf::Map's internal value_type. Instead of using
 // std::pair as value_type, we use this class which provides us more control of
 // std::pair as value_type, we use this class which provides us more control of
@@ -61,23 +65,24 @@ class MapPair {
 
 
   MapPair(const Key& other_first, const T& other_second)
   MapPair(const Key& other_first, const T& other_second)
       : first(other_first), second(other_second) {}
       : first(other_first), second(other_second) {}
-
   explicit MapPair(const Key& other_first) : first(other_first), second() {}
   explicit MapPair(const Key& other_first) : first(other_first), second() {}
-
   MapPair(const MapPair& other)
   MapPair(const MapPair& other)
       : first(other.first), second(other.second) {}
       : first(other.first), second(other.second) {}
 
 
   ~MapPair() {}
   ~MapPair() {}
 
 
-  // Implicitly convertible to std::pair.
-  operator std::pair<const Key, T>() const {
-    return std::pair<const Key, T>(first, second);
+  // Implicitly convertible to std::pair of compatible types.
+  template <typename T1, typename T2>
+  operator std::pair<T1, T2>() const {
+    return std::pair<T1, T2>(first, second);
   }
   }
 
 
   const Key first;
   const Key first;
   T second;
   T second;
 
 
  private:
  private:
+  typedef void DestructorSkippable_;
+  friend class ::google::protobuf::Arena;
   friend class Map<Key, T>;
   friend class Map<Key, T>;
 };
 };
 
 
@@ -86,6 +91,7 @@ class MapPair {
 // interface directly to visit or change map fields.
 // interface directly to visit or change map fields.
 template <typename Key, typename T>
 template <typename Key, typename T>
 class Map {
 class Map {
+  typedef internal::MapCppTypeHandler<Key> KeyTypeHandler;
   typedef internal::MapCppTypeHandler<T> ValueTypeHandler;
   typedef internal::MapCppTypeHandler<T> ValueTypeHandler;
 
 
  public:
  public:
@@ -100,20 +106,104 @@ class Map {
 
 
   typedef size_t size_type;
   typedef size_t size_type;
   typedef hash<Key> hasher;
   typedef hash<Key> hasher;
-
-  Map() : default_enum_value_(0) {}
-
-  Map(const Map& other) {
+  typedef equal_to<Key> key_equal;
+
+  Map()
+      : arena_(NULL),
+        allocator_(arena_),
+        elements_(0, hasher(), key_equal(), allocator_),
+        default_enum_value_(0) {}
+  explicit Map(Arena* arena)
+      : arena_(arena),
+        allocator_(arena_),
+        elements_(0, hasher(), key_equal(), allocator_),
+        default_enum_value_(0) {}
+
+  Map(const Map& other)
+      : arena_(NULL),
+        allocator_(arena_),
+        elements_(0, hasher(), key_equal(), allocator_),
+        default_enum_value_(other.default_enum_value_) {
     insert(other.begin(), other.end());
     insert(other.begin(), other.end());
   }
   }
 
 
   ~Map() { clear(); }
   ~Map() { clear(); }
 
 
+ private:
+  // re-implement std::allocator to use arena allocator for memory allocation.
+  // Used for google::protobuf::Map implementation. Users should not use this class
+  // directly.
+  template <typename U>
+  class MapAllocator {
+   public:
+    typedef U value_type;
+    typedef value_type* pointer;
+    typedef const value_type* const_pointer;
+    typedef value_type& reference;
+    typedef const value_type& const_reference;
+    typedef size_t size_type;
+    typedef ptrdiff_t difference_type;
+
+    MapAllocator() : arena_(NULL) {}
+    explicit MapAllocator(Arena* arena) : arena_(arena) {}
+    template <typename X>
+    MapAllocator(const MapAllocator<X>& allocator)
+        : arena_(allocator.arena_) {}
+
+    pointer allocate(size_type n, const_pointer hint = 0) {
+      // If arena is not given, malloc needs to be called which doesn't
+      // construct element object.
+      if (arena_ == NULL) {
+        return reinterpret_cast<pointer>(malloc(n * sizeof(value_type)));
+      } else {
+        return reinterpret_cast<pointer>(
+            Arena::CreateArray<uint8>(arena_, n * sizeof(value_type)));
+      }
+    }
+
+    void deallocate(pointer p, size_type n) {
+      if (arena_ == NULL) {
+        free(p);
+      }
+    }
+
+    void construct(pointer p, const_reference t) { new (p) value_type(t); }
+
+    void destroy(pointer p) {
+      if (arena_ == NULL) p->~value_type();
+    }
+
+    template <typename X>
+    struct rebind {
+      typedef MapAllocator<X> other;
+    };
+
+    template <typename X>
+    bool operator==(const MapAllocator<X>& other) const {
+      return arena_ == other.arena_;
+    }
+
+    template <typename X>
+    bool operator!=(const MapAllocator<X>& other) const {
+      return arena_ != other.arena_;
+    }
+
+   private:
+    Arena* arena_;
+
+    template <typename X>
+    friend class MapAllocator;
+  };
+
+ public:
+  typedef MapAllocator<std::pair<const Key, MapPair<Key, T>*> > Allocator;
+
   // Iterators
   // Iterators
-  class const_iterator
+  class LIBPROTOBUF_EXPORT const_iterator
       : public std::iterator<std::forward_iterator_tag, value_type, ptrdiff_t,
       : public std::iterator<std::forward_iterator_tag, value_type, ptrdiff_t,
                              const value_type*, const value_type&> {
                              const value_type*, const value_type&> {
-    typedef typename hash_map<Key, value_type*>::const_iterator InnerIt;
+    typedef typename hash_map<Key, value_type*, hash<Key>, equal_to<Key>,
+                              Allocator>::const_iterator InnerIt;
 
 
    public:
    public:
     const_iterator() {}
     const_iterator() {}
@@ -139,8 +229,9 @@ class Map {
     InnerIt it_;
     InnerIt it_;
   };
   };
 
 
-  class iterator : public std::iterator<std::forward_iterator_tag, value_type> {
-    typedef typename hash_map<Key, value_type*>::iterator InnerIt;
+  class LIBPROTOBUF_EXPORT iterator : public std::iterator<std::forward_iterator_tag, value_type> {
+    typedef typename hash_map<Key, value_type*, hasher, equal_to<Key>,
+                              Allocator>::iterator InnerIt;
 
 
    public:
    public:
     iterator() {}
     iterator() {}
@@ -185,7 +276,7 @@ class Map {
   T& operator[](const key_type& key) {
   T& operator[](const key_type& key) {
     value_type** value = &elements_[key];
     value_type** value = &elements_[key];
     if (*value == NULL) {
     if (*value == NULL) {
-      *value = new value_type(key);
+      *value = CreateValueTypeInternal(key);
       internal::MapValueInitializer<google::protobuf::is_proto_enum<T>::value,
       internal::MapValueInitializer<google::protobuf::is_proto_enum<T>::value,
                                     T>::Initialize((*value)->second,
                                     T>::Initialize((*value)->second,
                                                    default_enum_value_);
                                                    default_enum_value_);
@@ -241,7 +332,7 @@ class Map {
     } else {
     } else {
       return std::pair<iterator, bool>(
       return std::pair<iterator, bool>(
           iterator(elements_.insert(std::pair<Key, value_type*>(
           iterator(elements_.insert(std::pair<Key, value_type*>(
-              value.first, new value_type(value))).first), true);
+              value.first, CreateValueTypeInternal(value))).first), true);
     }
     }
   }
   }
   template <class InputIt>
   template <class InputIt>
@@ -256,28 +347,29 @@ class Map {
 
 
   // Erase
   // Erase
   size_type erase(const key_type& key) {
   size_type erase(const key_type& key) {
-    typename hash_map<Key, value_type*>::iterator it = elements_.find(key);
+    typename hash_map<Key, value_type*, hash<Key>, equal_to<Key>,
+                      Allocator>::iterator it = elements_.find(key);
     if (it == elements_.end()) {
     if (it == elements_.end()) {
       return 0;
       return 0;
     } else {
     } else {
-      delete it->second;
+      if (arena_ == NULL) delete it->second;
       elements_.erase(it);
       elements_.erase(it);
       return 1;
       return 1;
     }
     }
   }
   }
   void erase(iterator pos) {
   void erase(iterator pos) {
-    delete pos.it_->second;
+    if (arena_ == NULL) delete pos.it_->second;
     elements_.erase(pos.it_);
     elements_.erase(pos.it_);
   }
   }
   void erase(iterator first, iterator last) {
   void erase(iterator first, iterator last) {
     for (iterator it = first; it != last;) {
     for (iterator it = first; it != last;) {
-      delete it.it_->second;
+      if (arena_ == NULL) delete it.it_->second;
       elements_.erase((it++).it_);
       elements_.erase((it++).it_);
     }
     }
   }
   }
   void clear() {
   void clear() {
     for (iterator it = begin(); it != end(); ++it) {
     for (iterator it = begin(); it != end(); ++it) {
-      delete it.it_->second;
+      if (arena_ == NULL) delete it.it_->second;
     }
     }
     elements_.clear();
     elements_.clear();
   }
   }
@@ -297,12 +389,45 @@ class Map {
     default_enum_value_ = default_enum_value;
     default_enum_value_ = default_enum_value;
   }
   }
 
 
-  hash_map<Key, value_type*> elements_;
+  value_type* CreateValueTypeInternal(const Key& key) {
+    if (arena_ == NULL) {
+      return new value_type(key);
+    } else {
+      value_type* value = reinterpret_cast<value_type*>(
+          Arena::CreateArray<uint8>(arena_, sizeof(value_type)));
+      Arena::CreateInArenaStorage(const_cast<Key*>(&value->first), arena_);
+      Arena::CreateInArenaStorage(&value->second, arena_);
+      const_cast<Key&>(value->first) = key;
+      return value;
+    }
+  }
+
+  value_type* CreateValueTypeInternal(const value_type& value) {
+    if (arena_ == NULL) {
+      return new value_type(value);
+    } else {
+      value_type* p = reinterpret_cast<value_type*>(
+          Arena::CreateArray<uint8>(arena_, sizeof(value_type)));
+      Arena::CreateInArenaStorage(const_cast<Key*>(&p->first), arena_);
+      Arena::CreateInArenaStorage(&p->second, arena_);
+      const_cast<Key&>(p->first) = value.first;
+      p->second = value.second;
+      return p;
+    }
+  }
+
+  Arena* arena_;
+  Allocator allocator_;
+  hash_map<Key, value_type*, hash<Key>, equal_to<Key>, Allocator> elements_;
   int default_enum_value_;
   int default_enum_value_;
 
 
-  template <typename K, typename V, FieldDescriptor::Type KeyProto,
-            FieldDescriptor::Type ValueProto, int default_enum>
-  friend class internal::MapField;
+  friend class ::google::protobuf::Arena;
+  typedef void DestructorSkippable_;
+  template <typename K, typename V,
+            internal::WireFormatLite::FieldType key_wire_type,
+            internal::WireFormatLite::FieldType value_wire_type,
+            int default_enum_value>
+  friend class LIBPROTOBUF_EXPORT internal::MapFieldLite;
 };
 };
 
 
 }  // namespace protobuf
 }  // namespace protobuf

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است