浏览代码

Merge branch master into v3.0.0-beta-2

Feng Xiao 9 年之前
父节点
当前提交
d217808417
共有 42 个文件被更改,包括 404 次插入1055 次删除
  1. 0 1
      Makefile.am
  2. 2 0
      cmake/CMakeLists.txt
  3. 6 3
      csharp/src/AddressBook/Addressbook.cs
  4. 5 5
      csharp/src/Google.Protobuf.Conformance/Conformance.cs
  5. 24 19
      csharp/src/Google.Protobuf.Conformance/Program.cs
  6. 7 7
      csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs
  7. 1 1
      csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportProto3.cs
  8. 1 1
      csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportPublicProto3.cs
  9. 10 10
      csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs
  10. 35 35
      csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs
  11. 4 4
      csharp/src/Google.Protobuf.Test/TestProtos/UnittestWellKnownTypes.cs
  12. 23 0
      csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs
  13. 10 0
      csharp/src/Google.Protobuf/Google.Protobuf.csproj
  14. 38 19
      csharp/src/Google.Protobuf/Google.Protobuf.nuspec
  15. 51 3
      csharp/src/Google.Protobuf/JsonFormatter.cs
  16. 22 22
      csharp/src/Google.Protobuf/Reflection/Descriptor.cs
  17. 1 1
      csharp/src/Google.Protobuf/WellKnownTypes/Any.cs
  18. 3 3
      csharp/src/Google.Protobuf/WellKnownTypes/Api.cs
  19. 1 1
      csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs
  20. 1 1
      csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs
  21. 1 1
      csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs
  22. 1 1
      csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs
  23. 3 3
      csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs
  24. 1 1
      csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs
  25. 5 5
      csharp/src/Google.Protobuf/WellKnownTypes/Type.cs
  26. 9 9
      csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs
  27. 4 0
      csharp/src/Google.Protobuf/packages.config
  28. 5 0
      examples/add_person.go
  29. 24 22
      examples/list_people.go
  30. 24 0
      examples/list_people_test.go
  31. 11 318
      objectivec/GPBCodedInputStream.m
  32. 0 17
      objectivec/GPBCodedInputStream_PackagePrivate.h
  33. 7 7
      objectivec/GPBMessage.m
  34. 6 1
      objectivec/GPBMessage_PackagePrivate.h
  35. 22 6
      objectivec/GPBRootObject.m
  36. 2 2
      objectivec/GPBUtilities.m
  37. 0 4
      objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj
  38. 0 4
      objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj
  39. 5 1
      objectivec/Tests/GPBCodedInputStreamTests.m
  40. 0 513
      objectivec/Tests/GPBStringTests.m
  41. 1 1
      src/google/protobuf/compiler/csharp/csharp_message.cc
  42. 28 3
      src/google/protobuf/descriptor.cc

+ 0 - 1
Makefile.am

@@ -475,7 +475,6 @@ objectivec_EXTRA_DIST=                                                       \
   objectivec/Tests/GPBMessageTests.m                                         \
   objectivec/Tests/GPBObjectiveCPlusPlusTest.mm                              \
   objectivec/Tests/GPBPerfTests.m                                            \
-  objectivec/Tests/GPBStringTests.m                                          \
   objectivec/Tests/GPBSwiftTests.swift                                       \
   objectivec/Tests/GPBTestUtilities.h                                        \
   objectivec/Tests/GPBTestUtilities.m                                        \

+ 2 - 0
cmake/CMakeLists.txt

@@ -115,6 +115,8 @@ else (protobuf_BUILD_SHARED_LIBS)
 endif (protobuf_BUILD_SHARED_LIBS)
 
 if (MSVC)
+  # Build with multiple processes
+  add_definitions(/MP)
   add_definitions(/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305)
   string(REPLACE "/" "\\" PROTOBUF_SOURCE_WIN32_PATH ${protobuf_SOURCE_DIR})
   string(REPLACE "/" "\\" PROTOBUF_BINARY_WIN32_PATH ${protobuf_BINARY_DIR})

+ 6 - 3
csharp/src/AddressBook/Addressbook.cs

@@ -43,6 +43,9 @@ namespace Google.Protobuf.Examples.AddressBook {
 
   }
   #region Messages
+  /// <summary>
+  ///  [START messages]
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class Person : pb::IMessage<Person> {
     private static readonly pb::MessageParser<Person> _parser = new pb::MessageParser<Person>(() => new Person());
@@ -143,7 +146,7 @@ namespace Google.Protobuf.Examples.AddressBook {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -302,7 +305,7 @@ namespace Google.Protobuf.Examples.AddressBook {
         }
 
         public override string ToString() {
-          return pb::JsonFormatter.Default.Format(this);
+          return pb::JsonFormatter.ToDiagnosticString(this);
         }
 
         public void WriteTo(pb::CodedOutputStream output) {
@@ -426,7 +429,7 @@ namespace Google.Protobuf.Examples.AddressBook {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {

+ 5 - 5
csharp/src/Google.Protobuf.Conformance/Conformance.cs

@@ -284,7 +284,7 @@ namespace Conformance {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -532,7 +532,7 @@ namespace Conformance {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1544,7 +1544,7 @@ namespace Conformance {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -2343,7 +2343,7 @@ namespace Conformance {
         }
 
         public override string ToString() {
-          return pb::JsonFormatter.Default.Format(this);
+          return pb::JsonFormatter.ToDiagnosticString(this);
         }
 
         public void WriteTo(pb::CodedOutputStream output) {
@@ -2471,7 +2471,7 @@ namespace Conformance {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {

+ 24 - 19
csharp/src/Google.Protobuf.Conformance/Program.cs

@@ -31,6 +31,7 @@
 #endregion
 
 using Conformance;
+using Google.Protobuf.Reflection;
 using System;
 using System.IO;
 
@@ -47,16 +48,17 @@ namespace Google.Protobuf.Conformance
             // This way we get the binary streams instead of readers/writers.
             var input = new BinaryReader(Console.OpenStandardInput());
             var output = new BinaryWriter(Console.OpenStandardOutput());
+            var typeRegistry = TypeRegistry.FromMessages(TestAllTypes.Descriptor);
 
             int count = 0;
-            while (RunTest(input, output))
+            while (RunTest(input, output, typeRegistry))
             {
                 count++;
             }
             Console.Error.WriteLine("Received EOF after {0} tests", count);
         }
 
-        private static bool RunTest(BinaryReader input, BinaryWriter output)
+        private static bool RunTest(BinaryReader input, BinaryWriter output, TypeRegistry typeRegistry)
         {
             int? size = ReadInt32(input);
             if (size == null)
@@ -69,7 +71,7 @@ namespace Google.Protobuf.Conformance
                 throw new EndOfStreamException("Read " + inputData.Length + " bytes of data when expecting " + size);
             }
             ConformanceRequest request = ConformanceRequest.Parser.ParseFrom(inputData);
-            ConformanceResponse response = PerformRequest(request);
+            ConformanceResponse response = PerformRequest(request, typeRegistry);
             byte[] outputData = response.ToByteArray();
             output.Write(outputData.Length);
             output.Write(outputData);
@@ -77,30 +79,33 @@ namespace Google.Protobuf.Conformance
             return true;
         }
 
-        private static ConformanceResponse PerformRequest(ConformanceRequest request)
+        private static ConformanceResponse PerformRequest(ConformanceRequest request, TypeRegistry typeRegistry)
         {
             TestAllTypes message;
-            switch (request.PayloadCase)
+            try
             {
-                case ConformanceRequest.PayloadOneofCase.JsonPayload:
-                    return new ConformanceResponse { Skipped = "JSON parsing not implemented in C# yet" };
-                case ConformanceRequest.PayloadOneofCase.ProtobufPayload:
-                    try
-                    {
+                switch (request.PayloadCase)
+                {
+                    case ConformanceRequest.PayloadOneofCase.JsonPayload:
+                        var parser = new JsonParser(new JsonParser.Settings(20, typeRegistry));
+                        message = parser.Parse<TestAllTypes>(request.JsonPayload);
+                        break;
+                    case ConformanceRequest.PayloadOneofCase.ProtobufPayload:
                         message = TestAllTypes.Parser.ParseFrom(request.ProtobufPayload);
-                    }
-                    catch (InvalidProtocolBufferException e)
-                    {
-                        return new ConformanceResponse { ParseError = e.Message };
-                    }
-                    break;
-                default:
-                    throw new Exception("Unsupported request payload: " + request.PayloadCase);
+                        break;
+                    default:
+                        throw new Exception("Unsupported request payload: " + request.PayloadCase);
+                }
+            }
+            catch (InvalidProtocolBufferException e)
+            {
+                return new ConformanceResponse { ParseError = e.Message };
             }
             switch (request.RequestedOutputFormat)
             {
                 case global::Conformance.WireFormat.JSON:
-                    return new ConformanceResponse { JsonPayload = JsonFormatter.Default.Format(message) };
+                    var formatter = new JsonFormatter(new JsonFormatter.Settings(false, typeRegistry));
+                    return new ConformanceResponse { JsonPayload = formatter.Format(message) };
                 case global::Conformance.WireFormat.PROTOBUF:
                     return new ConformanceResponse { ProtobufPayload = message.ToByteString() };
                 default:

+ 7 - 7
csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs

@@ -425,7 +425,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -633,7 +633,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -741,7 +741,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -851,7 +851,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1121,7 +1121,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1318,7 +1318,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1427,7 +1427,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {

+ 1 - 1
csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportProto3.cs

@@ -110,7 +110,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {

+ 1 - 1
csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportPublicProto3.cs

@@ -96,7 +96,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {

+ 10 - 10
csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs

@@ -126,7 +126,7 @@ namespace UnitTest.Issues.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -204,7 +204,7 @@ namespace UnitTest.Issues.TestProtos {
         }
 
         public override string ToString() {
-          return pb::JsonFormatter.Default.Format(this);
+          return pb::JsonFormatter.ToDiagnosticString(this);
         }
 
         public void WriteTo(pb::CodedOutputStream output) {
@@ -282,7 +282,7 @@ namespace UnitTest.Issues.TestProtos {
             }
 
             public override string ToString() {
-              return pb::JsonFormatter.Default.Format(this);
+              return pb::JsonFormatter.ToDiagnosticString(this);
             }
 
             public void WriteTo(pb::CodedOutputStream output) {
@@ -405,7 +405,7 @@ namespace UnitTest.Issues.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -511,7 +511,7 @@ namespace UnitTest.Issues.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -668,7 +668,7 @@ namespace UnitTest.Issues.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -831,7 +831,7 @@ namespace UnitTest.Issues.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -947,7 +947,7 @@ namespace UnitTest.Issues.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1056,7 +1056,7 @@ namespace UnitTest.Issues.TestProtos {
         }
 
         public override string ToString() {
-          return pb::JsonFormatter.Default.Format(this);
+          return pb::JsonFormatter.ToDiagnosticString(this);
         }
 
         public void WriteTo(pb::CodedOutputStream output) {
@@ -1279,7 +1279,7 @@ namespace UnitTest.Issues.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {

+ 35 - 35
csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs

@@ -927,7 +927,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1600,7 +1600,7 @@ namespace Google.Protobuf.TestProtos {
         }
 
         public override string ToString() {
-          return pb::JsonFormatter.Default.Format(this);
+          return pb::JsonFormatter.ToDiagnosticString(this);
         }
 
         public void WriteTo(pb::CodedOutputStream output) {
@@ -1736,7 +1736,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1873,7 +1873,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1980,7 +1980,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -2070,7 +2070,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -2162,7 +2162,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -2291,7 +2291,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -2421,7 +2421,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -2547,7 +2547,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -2669,7 +2669,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -2883,7 +2883,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -3107,7 +3107,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -3278,7 +3278,7 @@ namespace Google.Protobuf.TestProtos {
         }
 
         public override string ToString() {
-          return pb::JsonFormatter.Default.Format(this);
+          return pb::JsonFormatter.ToDiagnosticString(this);
         }
 
         public void WriteTo(pb::CodedOutputStream output) {
@@ -3400,7 +3400,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -3506,7 +3506,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -3608,7 +3608,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -3704,7 +3704,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -3807,7 +3807,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -3913,7 +3913,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -4016,7 +4016,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -4119,7 +4119,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -4222,7 +4222,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -4325,7 +4325,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -4486,7 +4486,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -4780,7 +4780,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -5140,7 +5140,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -5414,7 +5414,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -5554,7 +5554,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -5647,7 +5647,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -5723,7 +5723,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -5799,7 +5799,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -5875,7 +5875,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -5951,7 +5951,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -6027,7 +6027,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {

+ 4 - 4
csharp/src/Google.Protobuf.Test/TestProtos/UnittestWellKnownTypes.cs

@@ -466,7 +466,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1106,7 +1106,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1625,7 +1625,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -2213,7 +2213,7 @@ namespace Google.Protobuf.TestProtos {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {

+ 23 - 0
csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs

@@ -62,5 +62,28 @@ namespace Google.Protobuf.WellKnownTypes
             var unpacked = any.Unpack<TestAllTypes>();
             Assert.AreEqual(message, unpacked);
         }
+
+        [Test]
+        public void ToString_WithValues()
+        {
+            var message = SampleMessages.CreateFullTestAllTypes();
+            var any = Any.Pack(message);
+            var text = any.ToString();
+            Assert.That(text, Is.StringContaining("\"@value\": \"" + message.ToByteString().ToBase64() + "\""));
+        }
+
+        [Test]
+        public void ToString_Empty()
+        {
+            var any = new Any();
+            Assert.AreEqual("{ \"@type\": \"\", \"@value\": \"\" }", any.ToString());
+        }
+
+        [Test]
+        public void ToString_MessageContainingAny()
+        {
+            var message = new TestWellKnownTypes { AnyField = new Any() };
+            Assert.AreEqual("{ \"anyField\": { \"@type\": \"\", \"@value\": \"\" } }", message.ToString());
+        }
     }
 }

+ 10 - 0
csharp/src/Google.Protobuf/Google.Protobuf.csproj

@@ -16,6 +16,8 @@
     <FileAlignment>512</FileAlignment>
     <OldToolsVersion>3.5</OldToolsVersion>
     <MinimumVisualStudioVersion>10.0</MinimumVisualStudioVersion>
+    <NuGetPackageImportStamp>
+    </NuGetPackageImportStamp>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
@@ -142,9 +144,17 @@
   </ItemGroup>
   <ItemGroup>
     <None Include="Google.Protobuf.nuspec" />
+    <None Include="packages.config" />
   </ItemGroup>
   <ItemGroup />
   <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
+  <Import Project="..\packages\NuSpec.ReferenceGenerator.1.4.1\build\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\NuSpec.ReferenceGenerator.targets" Condition="Exists('..\packages\NuSpec.ReferenceGenerator.1.4.1\build\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\NuSpec.ReferenceGenerator.targets')" />
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('..\packages\NuSpec.ReferenceGenerator.1.4.1\build\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\NuSpec.ReferenceGenerator.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NuSpec.ReferenceGenerator.1.4.1\build\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\NuSpec.ReferenceGenerator.targets'))" />
+  </Target>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.
   <Target Name="BeforeBuild">

+ 38 - 19
csharp/src/Google.Protobuf/Google.Protobuf.nuspec

@@ -1,11 +1,11 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <package>
   <metadata>
     <id>Google.Protobuf</id>
     <title>Google Protocol Buffers C#</title>
     <summary>C# runtime library for Protocol Buffers - Google's data interchange format.</summary>
     <description>See project site for more info.</description>
-    <version>3.0.0-alpha4</version>
+    <version>3.0.0-beta2</version>
     <authors>Google Inc.</authors>
     <owners>protobuf-packages</owners>
     <licenseUrl>https://github.com/google/protobuf/blob/master/LICENSE</licenseUrl>
@@ -14,24 +14,43 @@
     <releaseNotes>C# proto3 support</releaseNotes>
     <copyright>Copyright 2015, Google Inc.</copyright>
     <tags>Protocol Buffers Binary Serialization Format Google proto proto3</tags>
+    <dependencies>
+      <group targetFramework="dotnet">
+        <dependency id="System.Collections" version="4.0.0" />
+        <dependency id="System.Diagnostics.Debug" version="4.0.0" />
+        <dependency id="System.Globalization" version="4.0.0" />
+        <dependency id="System.IO" version="4.0.0" />
+        <dependency id="System.Linq" version="4.0.0" />
+        <dependency id="System.Linq.Expressions" version="4.0.0" />
+        <dependency id="System.ObjectModel" version="4.0.0" />
+        <dependency id="System.Reflection" version="4.0.0" />
+        <dependency id="System.Runtime" version="4.0.0" />
+        <dependency id="System.Runtime.Extensions" version="4.0.0" />
+        <dependency id="System.Text.Encoding" version="4.0.0" />
+        <dependency id="System.Text.RegularExpressions" version="4.0.0" />
+      </group>
+    </dependencies>
   </metadata>
   <files>
     <file src="bin/ReleaseSigned/Google.Protobuf.dll" target="lib/portable-net45+netcore45+wpa81+wp8" />
-	<file src="bin/ReleaseSigned/Google.Protobuf.pdb" target="lib/portable-net45+netcore45+wpa81+wp8" />
-	<file src="bin/ReleaseSigned/Google.Protobuf.xml" target="lib/portable-net45+netcore45+wpa81+wp8" />
-	<file src="**\*.cs" target="src" />
-	<file src="..\..\..\cmake\Release\protoc.exe" target="tools" />
-	<file src="..\..\..\src\google\protobuf\any.proto" target="tools\google\protobuf" />
-	<file src="..\..\..\src\google\protobuf\api.proto" target="tools\google\protobuf" />
-	<file src="..\..\..\src\google\protobuf\descriptor.proto" target="tools\google\protobuf" />
-	<file src="..\..\..\src\google\protobuf\duration.proto" target="tools\google\protobuf" />
-	<file src="..\..\..\src\google\protobuf\empty.proto" target="tools\google\protobuf" />
-	<file src="..\..\..\src\google\protobuf\field_mask.proto" target="tools\google\protobuf" />
-	<file src="..\..\..\src\google\protobuf\source_context.proto" target="tools\google\protobuf" />
-	<file src="..\..\..\src\google\protobuf\struct.proto" target="tools\google\protobuf" />
-	<file src="..\..\..\src\google\protobuf\timestamp.proto" target="tools\google\protobuf" />
-	<file src="..\..\..\src\google\protobuf\any.proto" target="tools\google\protobuf" />
-	<file src="..\..\..\src\google\protobuf\type.proto" target="tools\google\protobuf" />
-	<file src="..\..\..\src\google\protobuf\wrappers.proto" target="tools\google\protobuf" />
+    <file src="bin/ReleaseSigned/Google.Protobuf.pdb" target="lib/portable-net45+netcore45+wpa81+wp8" />
+    <file src="bin/ReleaseSigned/Google.Protobuf.xml" target="lib/portable-net45+netcore45+wpa81+wp8" />
+    <file src="bin/ReleaseSigned/Google.Protobuf.dll" target="lib/dotnet" />
+    <file src="bin/ReleaseSigned/Google.Protobuf.pdb" target="lib/dotnet" />
+    <file src="bin/ReleaseSigned/Google.Protobuf.xml" target="lib/dotnet" />
+    <file src="**\*.cs" target="src" />
+    <file src="..\..\..\cmake\Release\protoc.exe" target="tools" />
+    <file src="..\..\..\src\google\protobuf\any.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\api.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\descriptor.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\duration.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\empty.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\field_mask.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\source_context.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\struct.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\timestamp.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\any.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\type.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\wrappers.proto" target="tools\google\protobuf" />
   </files>
-</package>
+</package>

+ 51 - 3
csharp/src/Google.Protobuf/JsonFormatter.cs

@@ -56,17 +56,19 @@ namespace Google.Protobuf
     public sealed class JsonFormatter
     {
         internal const string AnyTypeUrlField = "@type";
+        internal const string AnyDiagnosticValueField = "@value";
         internal const string AnyWellKnownTypeValueField = "value";
         private const string TypeUrlPrefix = "type.googleapis.com";
         private const string NameValueSeparator = ": ";
         private const string PropertySeparator = ", ";
 
-        private static JsonFormatter defaultInstance = new JsonFormatter(Settings.Default);
-
         /// <summary>
         /// Returns a formatter using the default settings.
         /// </summary>
-        public static JsonFormatter Default { get { return defaultInstance; } }
+        public static JsonFormatter Default { get; } = new JsonFormatter(Settings.Default);
+
+        // A JSON formatter which *only* exists 
+        private static readonly JsonFormatter diagnosticFormatter = new JsonFormatter(Settings.Default);
 
         /// <summary>
         /// The JSON representation of the first 160 characters of Unicode.
@@ -149,6 +151,29 @@ namespace Google.Protobuf
             return builder.ToString();
         }
 
+        /// <summary>
+        /// Converts a message to JSON for diagnostic purposes with no extra context.
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// This differs from calling <see cref="Format(IMessage)"/> on the default JSON
+        /// formatter in its handling of <see cref="Any"/>. As no type registry is available
+        /// in <see cref="object.ToString"/> calls, the normal way of resolving the type of
+        /// an <c>Any</c> message cannot be applied. Instead, a JSON property named <c>@value</c>
+        /// is included with the base64 data from the <see cref="Any.Value"/> property of the message.
+        /// </para>
+        /// <para>The value returned by this method is only designed to be used for diagnostic
+        /// purposes. It may not be parsable by <see cref="JsonParser"/>, and may not be parsable
+        /// by other Protocol Buffer implementations.</para>
+        /// </remarks>
+        /// <param name="message">The message to format for diagnostic purposes.</param>
+        /// <returns>The diagnostic-only JSON representation of the message</returns>
+        public static string ToDiagnosticString(IMessage message)
+        {
+            Preconditions.CheckNotNull(message, nameof(message));
+            return diagnosticFormatter.Format(message);
+        }
+
         private void WriteMessage(StringBuilder builder, IMessage message)
         {
             if (message == null)
@@ -516,6 +541,12 @@ namespace Google.Protobuf
 
         private void WriteAny(StringBuilder builder, IMessage value)
         {
+            if (ReferenceEquals(this, diagnosticFormatter))
+            {
+                WriteDiagnosticOnlyAny(builder, value);
+                return;
+            }
+
             string typeUrl = (string) value.Descriptor.Fields[Any.TypeUrlFieldNumber].Accessor.GetValue(value);
             ByteString data = (ByteString) value.Descriptor.Fields[Any.ValueFieldNumber].Accessor.GetValue(value);
             string typeName = GetTypeName(typeUrl);
@@ -544,6 +575,23 @@ namespace Google.Protobuf
             builder.Append(" }");
         }
 
+        private void WriteDiagnosticOnlyAny(StringBuilder builder, IMessage value)
+        {
+            string typeUrl = (string) value.Descriptor.Fields[Any.TypeUrlFieldNumber].Accessor.GetValue(value);
+            ByteString data = (ByteString) value.Descriptor.Fields[Any.ValueFieldNumber].Accessor.GetValue(value);
+            builder.Append("{ ");
+            WriteString(builder, AnyTypeUrlField);
+            builder.Append(NameValueSeparator);
+            WriteString(builder, typeUrl);
+            builder.Append(PropertySeparator);
+            WriteString(builder, AnyDiagnosticValueField);
+            builder.Append(NameValueSeparator);
+            builder.Append('"');
+            builder.Append(data.ToBase64());
+            builder.Append('"');
+            builder.Append(" }");
+        }
+
         internal static string GetTypeName(String typeUrl)
         {
             string[] parts = typeUrl.Split('/');

+ 22 - 22
csharp/src/Google.Protobuf/Reflection/Descriptor.cs

@@ -225,7 +225,7 @@ namespace Google.Protobuf.Reflection {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -489,7 +489,7 @@ namespace Google.Protobuf.Reflection {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -827,7 +827,7 @@ namespace Google.Protobuf.Reflection {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1021,7 +1021,7 @@ namespace Google.Protobuf.Reflection {
         }
 
         public override string ToString() {
-          return pb::JsonFormatter.Default.Format(this);
+          return pb::JsonFormatter.ToDiagnosticString(this);
         }
 
         public void WriteTo(pb::CodedOutputStream output) {
@@ -1162,7 +1162,7 @@ namespace Google.Protobuf.Reflection {
         }
 
         public override string ToString() {
-          return pb::JsonFormatter.Default.Format(this);
+          return pb::JsonFormatter.ToDiagnosticString(this);
         }
 
         public void WriteTo(pb::CodedOutputStream output) {
@@ -1436,7 +1436,7 @@ namespace Google.Protobuf.Reflection {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1741,7 +1741,7 @@ namespace Google.Protobuf.Reflection {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1872,7 +1872,7 @@ namespace Google.Protobuf.Reflection {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -2031,7 +2031,7 @@ namespace Google.Protobuf.Reflection {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -2196,7 +2196,7 @@ namespace Google.Protobuf.Reflection {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -2404,7 +2404,7 @@ namespace Google.Protobuf.Reflection {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -2863,7 +2863,7 @@ namespace Google.Protobuf.Reflection {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -3302,7 +3302,7 @@ namespace Google.Protobuf.Reflection {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -3596,7 +3596,7 @@ namespace Google.Protobuf.Reflection {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -3845,7 +3845,7 @@ namespace Google.Protobuf.Reflection {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -3990,7 +3990,7 @@ namespace Google.Protobuf.Reflection {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -4121,7 +4121,7 @@ namespace Google.Protobuf.Reflection {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -4252,7 +4252,7 @@ namespace Google.Protobuf.Reflection {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -4451,7 +4451,7 @@ namespace Google.Protobuf.Reflection {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -4653,7 +4653,7 @@ namespace Google.Protobuf.Reflection {
         }
 
         public override string ToString() {
-          return pb::JsonFormatter.Default.Format(this);
+          return pb::JsonFormatter.ToDiagnosticString(this);
         }
 
         public void WriteTo(pb::CodedOutputStream output) {
@@ -4823,7 +4823,7 @@ namespace Google.Protobuf.Reflection {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -5051,7 +5051,7 @@ namespace Google.Protobuf.Reflection {
         }
 
         public override string ToString() {
-          return pb::JsonFormatter.Default.Format(this);
+          return pb::JsonFormatter.ToDiagnosticString(this);
         }
 
         public void WriteTo(pb::CodedOutputStream output) {

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

@@ -165,7 +165,7 @@ namespace Google.Protobuf.WellKnownTypes {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {

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

@@ -230,7 +230,7 @@ namespace Google.Protobuf.WellKnownTypes {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -503,7 +503,7 @@ namespace Google.Protobuf.WellKnownTypes {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -783,7 +783,7 @@ namespace Google.Protobuf.WellKnownTypes {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {

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

@@ -164,7 +164,7 @@ namespace Google.Protobuf.WellKnownTypes {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {

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

@@ -94,7 +94,7 @@ namespace Google.Protobuf.WellKnownTypes {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {

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

@@ -221,7 +221,7 @@ namespace Google.Protobuf.WellKnownTypes {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {

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

@@ -105,7 +105,7 @@ namespace Google.Protobuf.WellKnownTypes {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {

+ 3 - 3
csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs

@@ -136,7 +136,7 @@ namespace Google.Protobuf.WellKnownTypes {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -361,7 +361,7 @@ namespace Google.Protobuf.WellKnownTypes {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -555,7 +555,7 @@ namespace Google.Protobuf.WellKnownTypes {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {

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

@@ -175,7 +175,7 @@ namespace Google.Protobuf.WellKnownTypes {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {

+ 5 - 5
csharp/src/Google.Protobuf/WellKnownTypes/Type.cs

@@ -230,7 +230,7 @@ namespace Google.Protobuf.WellKnownTypes {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -522,7 +522,7 @@ namespace Google.Protobuf.WellKnownTypes {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -910,7 +910,7 @@ namespace Google.Protobuf.WellKnownTypes {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1098,7 +1098,7 @@ namespace Google.Protobuf.WellKnownTypes {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1244,7 +1244,7 @@ namespace Google.Protobuf.WellKnownTypes {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {

+ 9 - 9
csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs

@@ -117,7 +117,7 @@ namespace Google.Protobuf.WellKnownTypes {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -228,7 +228,7 @@ namespace Google.Protobuf.WellKnownTypes {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -339,7 +339,7 @@ namespace Google.Protobuf.WellKnownTypes {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -450,7 +450,7 @@ namespace Google.Protobuf.WellKnownTypes {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -561,7 +561,7 @@ namespace Google.Protobuf.WellKnownTypes {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -672,7 +672,7 @@ namespace Google.Protobuf.WellKnownTypes {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -783,7 +783,7 @@ namespace Google.Protobuf.WellKnownTypes {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -894,7 +894,7 @@ namespace Google.Protobuf.WellKnownTypes {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1005,7 +1005,7 @@ namespace Google.Protobuf.WellKnownTypes {
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {

+ 4 - 0
csharp/src/Google.Protobuf/packages.config

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="NuSpec.ReferenceGenerator" version="1.4.1" targetFramework="portable45-net45+win8+wp8+wpa81" developmentDependency="true" />
+</packages>

+ 5 - 0
examples/add_person.go

@@ -105,7 +105,10 @@ func main() {
 			log.Fatalln("Error reading file:", err)
 		}
 	}
+
+	// [START marshal_proto]
 	book := &pb.AddressBook{}
+	// [START_EXCLUDE]
 	if err := proto.Unmarshal(in, book); err != nil {
 		log.Fatalln("Failed to parse address book:", err)
 	}
@@ -116,6 +119,7 @@ func main() {
 		log.Fatalln("Error with address:", err)
 	}
 	book.People = append(book.People, addr)
+	// [END_EXCLUDE]
 
 	// Write the new address book back to disk.
 	out, err := proto.Marshal(book)
@@ -125,4 +129,5 @@ func main() {
 	if err := ioutil.WriteFile(fname, out, 0644); err != nil {
 		log.Fatalln("Failed to write address book:", err)
 	}
+	// [END marshal_proto]
 }

+ 24 - 22
examples/list_people.go

@@ -11,25 +11,29 @@ import (
 	pb "github.com/google/protobuf/examples/tutorial"
 )
 
-func listPeople(w io.Writer, book *pb.AddressBook) {
-	for _, p := range book.People {
-		fmt.Fprintln(w, "Person ID:", p.Id)
-		fmt.Fprintln(w, "  Name:", p.Name)
-		if p.Email != "" {
-			fmt.Fprintln(w, "  E-mail address:", p.Email)
-		}
+func writePerson(w io.Writer, p *pb.Person) {
+	fmt.Fprintln(w, "Person ID:", p.Id)
+	fmt.Fprintln(w, "  Name:", p.Name)
+	if p.Email != "" {
+		fmt.Fprintln(w, "  E-mail address:", p.Email)
+	}
 
-		for _, pn := range p.Phones {
-			switch pn.Type {
-			case pb.Person_MOBILE:
-				fmt.Fprint(w, "  Mobile phone #: ")
-			case pb.Person_HOME:
-				fmt.Fprint(w, "  Home phone #: ")
-			case pb.Person_WORK:
-				fmt.Fprint(w, "  Work phone #: ")
-			}
-			fmt.Fprintln(w, pn.Number)
+	for _, pn := range p.Phones {
+		switch pn.Type {
+		case pb.Person_MOBILE:
+			fmt.Fprint(w, "  Mobile phone #: ")
+		case pb.Person_HOME:
+			fmt.Fprint(w, "  Home phone #: ")
+		case pb.Person_WORK:
+			fmt.Fprint(w, "  Work phone #: ")
 		}
+		fmt.Fprintln(w, pn.Number)
+	}
+}
+
+func listPeople(w io.Writer, book *pb.AddressBook) {
+	for _, p := range book.People {
+		writePerson(w, p)
 	}
 }
 
@@ -41,19 +45,17 @@ func main() {
 	}
 	fname := os.Args[1]
 
+	// [START unmarshal_proto]
 	// Read the existing address book.
 	in, err := ioutil.ReadFile(fname)
 	if err != nil {
-		if os.IsNotExist(err) {
-			fmt.Printf("%s: File not found.  Creating new file.\n", fname)
-		} else {
-			log.Fatalln("Error reading file:", err)
-		}
+		log.Fatalln("Error reading file:", err)
 	}
 	book := &pb.AddressBook{}
 	if err := proto.Unmarshal(in, book); err != nil {
 		log.Fatalln("Failed to parse address book:", err)
 	}
+	// [END unmarshal_proto]
 
 	listPeople(os.Stdout, book)
 }

+ 24 - 0
examples/list_people_test.go

@@ -8,6 +8,30 @@ import (
 	pb "github.com/google/protobuf/examples/tutorial"
 )
 
+func TestWritePersonWritesPerson(t *testing.T) {
+	buf := new(bytes.Buffer)
+	// [START populate_proto]
+	p := pb.Person{
+		Id:    1234,
+		Name:  "John Doe",
+		Email: "jdoe@example.com",
+		Phones: []*pb.Person_PhoneNumber{
+			{Number: "555-4321", Type: pb.Person_HOME},
+		},
+	}
+	// [END populate_proto]
+	writePerson(buf, &p)
+	got := buf.String()
+	want := `Person ID: 1234
+  Name: John Doe
+  E-mail address: jdoe@example.com
+  Home phone #: 555-4321
+`
+	if got != want {
+		t.Errorf("writePerson(%s) =>\n\t%q, want %q", p.String(), got, want)
+	}
+}
+
 func TestListPeopleWritesList(t *testing.T) {
 	buf := new(bytes.Buffer)
 	in := pb.AddressBook{[]*pb.Person{

+ 11 - 318
objectivec/GPBCodedInputStream.m

@@ -216,7 +216,17 @@ NSString *GPBCodedInputStreamReadRetainedString(
     result = @"";
   } else {
     CheckSize(state, size);
-    result = GPBCreateGPBStringWithUTF8(&state->bytes[state->bufferPos], size);
+    result = [[NSString alloc] initWithBytes:&state->bytes[state->bufferPos]
+                                      length:size
+                                    encoding:NSUTF8StringEncoding];
+    if (!result) {
+      result = @"";
+#ifdef DEBUG
+      // https://developers.google.com/protocol-buffers/docs/proto#scalar
+      NSLog(@"UTF8 failure, is some field type 'string' when it should be "
+            @"'bytes'?");
+#endif
+    }
     state->bufferPos += size;
   }
   return result;
@@ -478,320 +488,3 @@ void GPBCodedInputStreamCheckLastTagWas(GPBCodedInputStreamState *state,
 }
 
 @end
-
-@implementation GPBString {
- @package
-  CFStringRef string_;
-  unsigned char *utf8_;
-  NSUInteger utf8Len_;
-
-  // This lock is used to gate access to utf8_.  Once GPBStringInitStringValue()
-  // has been called, string_ will be filled in, and utf8_ will be NULL.
-  OSSpinLock lock_;
-
-  BOOL hasBOM_;
-  BOOL is7BitAscii_;
-}
-
-// Returns true if the passed in bytes are 7 bit ascii.
-// This routine needs to be fast.
-static bool AreBytesIn7BitASCII(const uint8_t *bytes, NSUInteger len) {
-// In the loops below, it's more efficient to collect rather than do
-// conditional at every step.
-#if __LP64__
-  // Align bytes. This is especially important in case of 3 byte BOM.
-  while (len > 0 && ((size_t)bytes & 0x07)) {
-    if (*bytes++ & 0x80) return false;
-    len--;
-  }
-  while (len >= 32) {
-    uint64_t val = *(const uint64_t *)bytes;
-    uint64_t hiBits = (val & 0x8080808080808080ULL);
-    bytes += 8;
-    val = *(const uint64_t *)bytes;
-    hiBits |= (val & 0x8080808080808080ULL);
-    bytes += 8;
-    val = *(const uint64_t *)bytes;
-    hiBits |= (val & 0x8080808080808080ULL);
-    bytes += 8;
-    val = *(const uint64_t *)bytes;
-    if (hiBits | (val & 0x8080808080808080ULL)) return false;
-    bytes += 8;
-    len -= 32;
-  }
-
-  while (len >= 16) {
-    uint64_t val = *(const uint64_t *)bytes;
-    uint64_t hiBits = (val & 0x8080808080808080ULL);
-    bytes += 8;
-    val = *(const uint64_t *)bytes;
-    if (hiBits | (val & 0x8080808080808080ULL)) return false;
-    bytes += 8;
-    len -= 16;
-  }
-
-  while (len >= 8) {
-    uint64_t val = *(const uint64_t *)bytes;
-    if (val & 0x8080808080808080ULL) return false;
-    bytes += 8;
-    len -= 8;
-  }
-#else   // __LP64__
-  // Align bytes. This is especially important in case of 3 byte BOM.
-  while (len > 0 && ((size_t)bytes & 0x03)) {
-    if (*bytes++ & 0x80) return false;
-    len--;
-  }
-  while (len >= 16) {
-    uint32_t val = *(const uint32_t *)bytes;
-    uint32_t hiBits = (val & 0x80808080U);
-    bytes += 4;
-    val = *(const uint32_t *)bytes;
-    hiBits |= (val & 0x80808080U);
-    bytes += 4;
-    val = *(const uint32_t *)bytes;
-    hiBits |= (val & 0x80808080U);
-    bytes += 4;
-    val = *(const uint32_t *)bytes;
-    if (hiBits | (val & 0x80808080U)) return false;
-    bytes += 4;
-    len -= 16;
-  }
-
-  while (len >= 8) {
-    uint32_t val = *(const uint32_t *)bytes;
-    uint32_t hiBits = (val & 0x80808080U);
-    bytes += 4;
-    val = *(const uint32_t *)bytes;
-    if (hiBits | (val & 0x80808080U)) return false;
-    bytes += 4;
-    len -= 8;
-  }
-#endif  // __LP64__
-
-  while (len >= 4) {
-    uint32_t val = *(const uint32_t *)bytes;
-    if (val & 0x80808080U) return false;
-    bytes += 4;
-    len -= 4;
-  }
-
-  while (len--) {
-    if (*bytes++ & 0x80) return false;
-  }
-
-  return true;
-}
-
-static void GPBStringInitStringValue(GPBString *string) {
-  OSSpinLockLock(&string->lock_);
-  GPBStringInitStringValueAlreadyLocked(string);
-  OSSpinLockUnlock(&string->lock_);
-}
-
-static void GPBStringInitStringValueAlreadyLocked(GPBString *string) {
-  if (string->string_ == NULL && string->utf8_ != NULL) {
-    // Using kCFAllocatorMalloc for contentsDeallocator, as buffer in
-    // string->utf8_ is being handed off.
-    string->string_ = CFStringCreateWithBytesNoCopy(
-        NULL, string->utf8_, string->utf8Len_, kCFStringEncodingUTF8, false,
-        kCFAllocatorMalloc);
-    if (!string->string_) {
-#ifdef DEBUG
-      // https://developers.google.com/protocol-buffers/docs/proto#scalar
-      NSLog(@"UTF8 failure, is some field type 'string' when it should be "
-            @"'bytes'?");
-#endif
-      string->string_ = CFSTR("");
-      string->utf8Len_ = 0;
-      // On failure, we have to clean up the buffer.
-      free(string->utf8_);
-    }
-    string->utf8_ = NULL;
-  }
-}
-
-GPBString *GPBCreateGPBStringWithUTF8(const void *bytes, NSUInteger length) {
-  GPBString *result = [[GPBString alloc] initWithBytes:bytes length:length];
-  return result;
-}
-
-- (instancetype)initWithBytes:(const void *)bytes length:(NSUInteger)length {
-  self = [super init];
-  if (self) {
-    utf8_ = malloc(length);
-    memcpy(utf8_, bytes, length);
-    utf8Len_ = length;
-    lock_ = OS_SPINLOCK_INIT;
-    is7BitAscii_ = AreBytesIn7BitASCII(bytes, length);
-    if (length >= 3 && memcmp(utf8_, "\xef\xbb\xbf", 3) == 0) {
-      // We can't just remove the BOM from the string here, because in the case
-      // where we have > 1 BOM at the beginning of the string, we will remove one,
-      // and the internal NSString we create will remove the next one, and we will
-      // end up with a GPBString != NSString issue.
-      // We also just can't remove all the BOMs because then we would end up with
-      // potential cases where a GPBString and an NSString made with the same
-      // UTF8 buffer would in fact be different.
-      // We record the fact we have a BOM, and use it as necessary to simulate
-      // what NSString would return for various calls.
-      hasBOM_ = YES;
-#if DEBUG
-      // Sending BOMs across the line is just wasting bits.
-      NSLog(@"Bad data? String should not have BOM!");
-#endif  // DEBUG
-    }
-  }
-  return self;
-}
-
-- (void)dealloc {
-  if (string_ != NULL) {
-    CFRelease(string_);
-  }
-  if (utf8_ != NULL) {
-    free(utf8_);
-  }
-  [super dealloc];
-}
-
-// Required NSString overrides.
-- (NSUInteger)length {
-  if (is7BitAscii_) {
-    return utf8Len_;
-  } else {
-    GPBStringInitStringValue(self);
-    return CFStringGetLength(string_);
-  }
-}
-
-- (unichar)characterAtIndex:(NSUInteger)anIndex {
-  OSSpinLockLock(&lock_);
-  if (is7BitAscii_ && utf8_) {
-    unichar result = utf8_[anIndex];
-    OSSpinLockUnlock(&lock_);
-    return result;
-  } else {
-    GPBStringInitStringValueAlreadyLocked(self);
-    OSSpinLockUnlock(&lock_);
-    return CFStringGetCharacterAtIndex(string_, anIndex);
-  }
-}
-
-// Override a couple of methods that typically want high performance.
-
-- (id)copyWithZone:(NSZone *)zone {
-  GPBStringInitStringValue(self);
-  return [(NSString *)string_ copyWithZone:zone];
-}
-
-- (id)mutableCopyWithZone:(NSZone *)zone {
-  GPBStringInitStringValue(self);
-  return [(NSString *)string_ mutableCopyWithZone:zone];
-}
-
-- (NSUInteger)hash {
-  // Must convert to string here to make sure that the hash is always
-  // consistent no matter what state the GPBString is in.
-  GPBStringInitStringValue(self);
-  return CFHash(string_);
-}
-
-- (BOOL)isEqual:(id)object {
-  if (self == object) {
-    return YES;
-  }
-  if ([object isKindOfClass:[NSString class]]) {
-    GPBStringInitStringValue(self);
-    return CFStringCompare(string_, (CFStringRef)object, 0) ==
-           kCFCompareEqualTo;
-  }
-  return NO;
-}
-
-- (void)getCharacters:(unichar *)buffer range:(NSRange)aRange {
-  OSSpinLockLock(&lock_);
-  if (is7BitAscii_ && utf8_) {
-    unsigned char *bytes = &(utf8_[aRange.location]);
-    for (NSUInteger i = 0; i < aRange.length; ++i) {
-      buffer[i] = bytes[i];
-    }
-    OSSpinLockUnlock(&lock_);
-  } else {
-    GPBStringInitStringValueAlreadyLocked(self);
-    OSSpinLockUnlock(&lock_);
-    CFStringGetCharacters(string_, CFRangeMake(aRange.location, aRange.length),
-                          buffer);
-  }
-}
-
-- (NSUInteger)lengthOfBytesUsingEncoding:(NSStringEncoding)encoding {
-  if ((encoding == NSUTF8StringEncoding) ||
-      (encoding == NSASCIIStringEncoding && is7BitAscii_)) {
-    return utf8Len_ - (hasBOM_ ? 3 : 0);
-  } else {
-    GPBStringInitStringValue(self);
-    return [(NSString *)string_ lengthOfBytesUsingEncoding:encoding];
-  }
-}
-
-- (BOOL)getBytes:(void *)buffer
-         maxLength:(NSUInteger)maxLength
-        usedLength:(NSUInteger *)usedLength
-          encoding:(NSStringEncoding)encoding
-           options:(NSStringEncodingConversionOptions)options
-             range:(NSRange)range
-    remainingRange:(NSRangePointer)remainingRange {
-  // [NSString getBytes:maxLength:usedLength:encoding:options:range:remainingRange]
-  // does not return reliable results if the maxLength argument is 0
-  // (Radar 16385183). Therefore we have special cased it as a slow case so
-  // that it behaves however Apple intends it to behave. It should be a rare
-  // case.
-  //
-  // [NSString getBytes:maxLength:usedLength:encoding:options:range:remainingRange]
-  // does not return reliable results if the range is outside of the strings
-  // length (Radar 16396177). Therefore we have special cased it as a slow
-  // case so that it behaves however Apple intends it to behave.  It should
-  // be a rare case.
-  //
-  // We can optimize the UTF8StringEncoding and NSASCIIStringEncoding with no
-  // options cases.
-  if ((options == 0) &&
-      (encoding == NSUTF8StringEncoding || encoding == NSASCIIStringEncoding) &&
-      (maxLength != 0) &&
-      (NSMaxRange(range) <= utf8Len_)) {
-    // Might be able to optimize it.
-    OSSpinLockLock(&lock_);
-    if (is7BitAscii_ && utf8_) {
-      NSUInteger length = range.length;
-      length = (length < maxLength) ? length : maxLength;
-      memcpy(buffer, utf8_ + range.location, length);
-      if (usedLength) {
-        *usedLength = length;
-      }
-      if (remainingRange) {
-        remainingRange->location = range.location + length;
-        remainingRange->length = range.length - length;
-      }
-      OSSpinLockUnlock(&lock_);
-      if (length > 0) {
-        return YES;
-      } else {
-        return NO;
-      }
-    } else {
-      GPBStringInitStringValueAlreadyLocked(self);
-      OSSpinLockUnlock(&lock_);
-    }
-  } else {
-    GPBStringInitStringValue(self);
-  }
-  return [(NSString *)string_ getBytes:buffer
-                             maxLength:maxLength
-                            usedLength:usedLength
-                              encoding:encoding
-                               options:options
-                                 range:range
-                        remainingRange:remainingRange];
-}
-
-@end

+ 0 - 17
objectivec/GPBCodedInputStream_PackagePrivate.h

@@ -39,19 +39,6 @@
 @class GPBUnknownFieldSet;
 @class GPBFieldDescriptor;
 
-// GPBString is a string subclass that avoids the overhead of initializing
-// a full NSString until it is actually needed. Lots of protocol buffers contain
-// strings, and instantiating all of those strings and having them parsed to
-// verify correctness when the message was being read was expensive, when many
-// of the strings were never being used.
-//
-// Note for future-self. I tried implementing this using a NSProxy.
-// Turned out the performance was horrible in client apps because folks
-// like to use libraries like SBJSON that grab characters one at a time.
-// The proxy overhead was a killer.
-@interface GPBString : NSString
-@end
-
 typedef struct GPBCodedInputStreamState {
   const uint8_t *bytes;
   size_t bufferSize;
@@ -92,10 +79,6 @@ typedef struct GPBCodedInputStreamState {
 
 CF_EXTERN_C_BEGIN
 
-// Returns a GPBString with a +1 retain count.
-GPBString *GPBCreateGPBStringWithUTF8(const void *bytes, NSUInteger length)
-    __attribute__((ns_returns_retained));
-
 int32_t GPBCodedInputStreamReadTag(GPBCodedInputStreamState *state);
 
 double GPBCodedInputStreamReadDouble(GPBCodedInputStreamState *state);

+ 7 - 7
objectivec/GPBMessage.m

@@ -568,13 +568,13 @@ static id GetArrayIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) {
   id array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
   if (!array) {
     // Check again after getting the lock.
-    OSSpinLockLock(&self->readOnlyMutex_);
+    dispatch_semaphore_wait(self->readOnlySemaphore_, DISPATCH_TIME_FOREVER);
     array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
     if (!array) {
       array = CreateArrayForField(field, self);
       GPBSetAutocreatedRetainedObjectIvarWithField(self, field, array);
     }
-    OSSpinLockUnlock(&self->readOnlyMutex_);
+    dispatch_semaphore_signal(self->readOnlySemaphore_);
   }
   return array;
 }
@@ -598,13 +598,13 @@ static id GetMapIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) {
   id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
   if (!dict) {
     // Check again after getting the lock.
-    OSSpinLockLock(&self->readOnlyMutex_);
+    dispatch_semaphore_wait(self->readOnlySemaphore_, DISPATCH_TIME_FOREVER);
     dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
     if (!dict) {
       dict = CreateMapForField(field, self);
       GPBSetAutocreatedRetainedObjectIvarWithField(self, field, dict);
     }
-    OSSpinLockUnlock(&self->readOnlyMutex_);
+    dispatch_semaphore_signal(self->readOnlySemaphore_);
   }
   return dict;
 }
@@ -810,7 +810,7 @@ static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) {
     messageStorage_ = (GPBMessage_StoragePtr)(
         ((uint8_t *)self) + class_getInstanceSize([self class]));
 
-    readOnlyMutex_ = OS_SPINLOCK_INIT;
+    readOnlySemaphore_ = dispatch_semaphore_create(1);
   }
 
   return self;
@@ -1723,7 +1723,7 @@ static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) {
   }
 
   // Check for an autocreated value.
-  OSSpinLockLock(&readOnlyMutex_);
+  dispatch_semaphore_wait(readOnlySemaphore_, DISPATCH_TIME_FOREVER);
   value = [autocreatedExtensionMap_ objectForKey:extension];
   if (!value) {
     // Auto create the message extensions to match normal fields.
@@ -1740,7 +1740,7 @@ static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) {
     [value release];
   }
 
-  OSSpinLockUnlock(&readOnlyMutex_);
+  dispatch_semaphore_signal(readOnlySemaphore_);
   return value;
 }
 

+ 6 - 1
objectivec/GPBMessage_PackagePrivate.h

@@ -62,7 +62,12 @@ typedef struct GPBMessage_Storage *GPBMessage_StoragePtr;
   // by *read* operations such as getters (autocreation of message fields and
   // message extensions, not setting of values). Used to guarantee thread safety
   // for concurrent reads on the message.
-  OSSpinLock readOnlyMutex_;
+  // NOTE: OSSpinLock may seem like a good fit here but Apple engineers have
+  // pointed out that they are vulnerable to live locking on iOS in cases of
+  // priority inversion:
+  //   http://mjtsai.com/blog/2015/12/16/osspinlock-is-unsafe/
+  //   https://lists.swift.org/pipermail/swift-dev/Week-of-Mon-20151214/000372.html
+  dispatch_semaphore_t readOnlySemaphore_;
 }
 
 // Gets an extension value without autocreating the result if not found. (i.e.

+ 22 - 6
objectivec/GPBRootObject.m

@@ -31,7 +31,6 @@
 #import "GPBRootObject_PackagePrivate.h"
 
 #import <objc/runtime.h>
-#import <libkern/OSAtomic.h>
 
 #import <CoreFoundation/CoreFoundation.h>
 
@@ -96,13 +95,19 @@ static CFHashCode GPBRootExtensionKeyHash(const void *value) {
   return jenkins_one_at_a_time_hash(key);
 }
 
-static OSSpinLock gExtensionSingletonDictionaryLock_ = OS_SPINLOCK_INIT;
+// NOTE: OSSpinLock may seem like a good fit here but Apple engineers have
+// pointed out that they are vulnerable to live locking on iOS in cases of
+// priority inversion:
+//   http://mjtsai.com/blog/2015/12/16/osspinlock-is-unsafe/
+//   https://lists.swift.org/pipermail/swift-dev/Week-of-Mon-20151214/000372.html
+static dispatch_semaphore_t gExtensionSingletonDictionarySemaphore;
 static CFMutableDictionaryRef gExtensionSingletonDictionary = NULL;
 static GPBExtensionRegistry *gDefaultExtensionRegistry = NULL;
 
 + (void)initialize {
   // Ensure the global is started up.
   if (!gExtensionSingletonDictionary) {
+    gExtensionSingletonDictionarySemaphore = dispatch_semaphore_create(1);
     CFDictionaryKeyCallBacks keyCallBacks = {
       // See description above for reason for using custom dictionary.
       0,
@@ -134,9 +139,10 @@ static GPBExtensionRegistry *gDefaultExtensionRegistry = NULL;
 
 + (void)globallyRegisterExtension:(GPBExtensionDescriptor *)field {
   const char *key = [field singletonNameC];
-  OSSpinLockLock(&gExtensionSingletonDictionaryLock_);
+  dispatch_semaphore_wait(gExtensionSingletonDictionarySemaphore,
+                          DISPATCH_TIME_FOREVER);
   CFDictionarySetValue(gExtensionSingletonDictionary, key, field);
-  OSSpinLockUnlock(&gExtensionSingletonDictionaryLock_);
+  dispatch_semaphore_signal(gExtensionSingletonDictionarySemaphore);
 }
 
 static id ExtensionForName(id self, SEL _cmd) {
@@ -166,14 +172,24 @@ static id ExtensionForName(id self, SEL _cmd) {
   key[classNameLen] = '_';
   memcpy(&key[classNameLen + 1], selName, selNameLen);
   key[classNameLen + 1 + selNameLen] = '\0';
-  OSSpinLockLock(&gExtensionSingletonDictionaryLock_);
+
+  // NOTE: Even though this method is called from another C function,
+  // gExtensionSingletonDictionarySemaphore and gExtensionSingletonDictionary
+  // will always be initialized. This is because this call flow is just to
+  // lookup the Extension, meaning the code is calling an Extension class
+  // message on a Message or Root class. This guarantees that the class was
+  // initialized and Message classes ensure their Root was also initialized.
+  NSAssert(gExtensionSingletonDictionary, @"Startup order broken!");
+
+  dispatch_semaphore_wait(gExtensionSingletonDictionarySemaphore,
+                          DISPATCH_TIME_FOREVER);
   id extension = (id)CFDictionaryGetValue(gExtensionSingletonDictionary, key);
   if (extension) {
     // The method is getting wired in to the class, so no need to keep it in
     // the dictionary.
     CFDictionaryRemoveValue(gExtensionSingletonDictionary, key);
   }
-  OSSpinLockUnlock(&gExtensionSingletonDictionaryLock_);
+  dispatch_semaphore_signal(gExtensionSingletonDictionarySemaphore);
   return extension;
 }
 

+ 2 - 2
objectivec/GPBUtilities.m

@@ -411,7 +411,7 @@ id GPBGetObjectIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) {
     return field.defaultValue.valueMessage;
   }
 
-  OSSpinLockLock(&self->readOnlyMutex_);
+  dispatch_semaphore_wait(self->readOnlySemaphore_, DISPATCH_TIME_FOREVER);
   GPBMessage *result = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
   if (!result) {
     // For non repeated messages, create the object, set it and return it.
@@ -420,7 +420,7 @@ id GPBGetObjectIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) {
     result = GPBCreateMessageWithAutocreator(field.msgClass, self, field);
     GPBSetAutocreatedRetainedObjectIvarWithField(self, field, result);
   }
-  OSSpinLockUnlock(&self->readOnlyMutex_);
+  dispatch_semaphore_signal(self->readOnlySemaphore_);
   return result;
 }
 

+ 0 - 4
objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj

@@ -28,7 +28,6 @@
 		8B8B615D17DF7056002EE618 /* GPBARCUnittestProtos.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B8B615C17DF7056002EE618 /* GPBARCUnittestProtos.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; };
 		8B96157414C8C38C00A2AC0B /* GPBDescriptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B96157314C8C38C00A2AC0B /* GPBDescriptor.m */; };
 		8B96157514CA019D00A2AC0B /* Descriptor.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BD3982214BE5B0C0081D629 /* Descriptor.pbobjc.m */; };
-		8BA9364518DA5F4C0056FA2A /* GPBStringTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BA9364418DA5F4B0056FA2A /* GPBStringTests.m */; };
 		8BBEA4A9147C727D00C4ADB7 /* GPBCodedInputStreamTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B69B0F94FDF800A0C422 /* GPBCodedInputStreamTests.m */; };
 		8BBEA4AA147C727D00C4ADB7 /* GPBCodedOuputStreamTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B69D0F94FDF800A0C422 /* GPBCodedOuputStreamTests.m */; };
 		8BBEA4AC147C727D00C4ADB7 /* GPBMessageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B6A30F94FDF800A0C422 /* GPBMessageTests.m */; };
@@ -158,7 +157,6 @@
 		8B8B615C17DF7056002EE618 /* GPBARCUnittestProtos.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBARCUnittestProtos.m; sourceTree = "<group>"; };
 		8B96157214C8B06000A2AC0B /* GPBDescriptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBDescriptor.h; sourceTree = "<group>"; };
 		8B96157314C8C38C00A2AC0B /* GPBDescriptor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBDescriptor.m; sourceTree = "<group>"; };
-		8BA9364418DA5F4B0056FA2A /* GPBStringTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBStringTests.m; sourceTree = "<group>"; };
 		8BBD9DB016DD1DC8008E1EC1 /* unittest_lite.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_lite.proto; path = ../../src/google/protobuf/unittest_lite.proto; sourceTree = "<group>"; };
 		8BBEA4A6147C727100C4ADB7 /* UnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
 		8BCF338814ED799900BC5317 /* GPBProtocolBuffers.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GPBProtocolBuffers.m; sourceTree = "<group>"; };
@@ -419,7 +417,6 @@
 				F4487C7E1AAF62CD00531423 /* GPBMessageTests+Serialization.m */,
 				F4B51B1D1BBC610700744318 /* GPBObjectiveCPlusPlusTest.mm */,
 				F41C175C1833D3310064ED4D /* GPBPerfTests.m */,
-				8BA9364418DA5F4B0056FA2A /* GPBStringTests.m */,
 				8B4248BA1A8C256A00BC1EC6 /* GPBSwiftTests.swift */,
 				7461B6AB0F94FDF800A0C422 /* GPBTestUtilities.h */,
 				7461B6AC0F94FDF800A0C422 /* GPBTestUtilities.m */,
@@ -689,7 +686,6 @@
 				F41C175D1833D3310064ED4D /* GPBPerfTests.m in Sources */,
 				F4353D341AC06F10005A6198 /* GPBDictionaryTests+Bool.m in Sources */,
 				F4487C831AAF6AB300531423 /* GPBMessageTests+Merge.m in Sources */,
-				8BA9364518DA5F4C0056FA2A /* GPBStringTests.m in Sources */,
 				8BBEA4B6147C727D00C4ADB7 /* GPBUnknownFieldSetTest.m in Sources */,
 				F4353D371AC06F10005A6198 /* GPBDictionaryTests+String.m in Sources */,
 				F4353D381AC06F10005A6198 /* GPBDictionaryTests+UInt32.m in Sources */,

+ 0 - 4
objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj

@@ -36,7 +36,6 @@
 		8B9A5EB41831993600A9D33B /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B9A5EB31831993600A9D33B /* AppDelegate.m */; };
 		8B9A5EB61831993600A9D33B /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8B9A5EB51831993600A9D33B /* Images.xcassets */; };
 		8B9A5EEC18330A0F00A9D33B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B9A5E9F1831913D00A9D33B /* UIKit.framework */; };
-		8BA9364518DA5F4C0056FA2A /* GPBStringTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BA9364418DA5F4B0056FA2A /* GPBStringTests.m */; };
 		8BBEA4A9147C727D00C4ADB7 /* GPBCodedInputStreamTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B69B0F94FDF800A0C422 /* GPBCodedInputStreamTests.m */; };
 		8BBEA4AA147C727D00C4ADB7 /* GPBCodedOuputStreamTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B69D0F94FDF800A0C422 /* GPBCodedOuputStreamTests.m */; };
 		8BBEA4AC147C727D00C4ADB7 /* GPBMessageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B6A30F94FDF800A0C422 /* GPBMessageTests.m */; };
@@ -179,7 +178,6 @@
 		8B9A5EAD1831993600A9D33B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
 		8B9A5EB31831993600A9D33B /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
 		8B9A5EB51831993600A9D33B /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
-		8BA9364418DA5F4B0056FA2A /* GPBStringTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBStringTests.m; sourceTree = "<group>"; };
 		8BBD9DB016DD1DC8008E1EC1 /* unittest_lite.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_lite.proto; path = ../../src/google/protobuf/unittest_lite.proto; sourceTree = "<group>"; };
 		8BBEA4A6147C727100C4ADB7 /* UnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
 		8BCF338814ED799900BC5317 /* GPBProtocolBuffers.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GPBProtocolBuffers.m; sourceTree = "<group>"; };
@@ -457,7 +455,6 @@
 				F4487C801AAF62FC00531423 /* GPBMessageTests+Serialization.m */,
 				F4B51B1B1BBC5C7100744318 /* GPBObjectiveCPlusPlusTest.mm */,
 				F41C175C1833D3310064ED4D /* GPBPerfTests.m */,
-				8BA9364418DA5F4B0056FA2A /* GPBStringTests.m */,
 				8B4248B31A8BD96E00BC1EC6 /* GPBSwiftTests.swift */,
 				7461B6AB0F94FDF800A0C422 /* GPBTestUtilities.h */,
 				7461B6AC0F94FDF800A0C422 /* GPBTestUtilities.m */,
@@ -785,7 +782,6 @@
 				F41C175D1833D3310064ED4D /* GPBPerfTests.m in Sources */,
 				F4353D421AC06F31005A6198 /* GPBDictionaryTests+Bool.m in Sources */,
 				F4487C851AAF6AC500531423 /* GPBMessageTests+Merge.m in Sources */,
-				8BA9364518DA5F4C0056FA2A /* GPBStringTests.m in Sources */,
 				8BBEA4B6147C727D00C4ADB7 /* GPBUnknownFieldSetTest.m in Sources */,
 				F4353D451AC06F31005A6198 /* GPBDictionaryTests+String.m in Sources */,
 				F4353D461AC06F31005A6198 /* GPBDictionaryTests+UInt32.m in Sources */,

+ 5 - 1
objectivec/Tests/GPBCodedInputStreamTests.m

@@ -266,6 +266,9 @@
 }
 
 // Verifies fix for b/10315336.
+// Note: Now that there isn't a custom string class under the hood, this test
+// isn't as critical, but it does cover bad input and if a custom class is added
+// again, it will help validate that class' handing of bad utf8.
 - (void)testReadMalformedString {
   NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory];
   GPBCodedOutputStream* output =
@@ -276,7 +279,7 @@
   [output writeRawVarint32:tag];
   [output writeRawVarint32:5];
   // Create an invalid utf-8 byte array.
-  uint8_t bytes[5] = {0xc2, 0xf2};
+  uint8_t bytes[] = {0xc2, 0xf2, 0x0, 0x0, 0x0};
   [output writeRawData:[NSData dataWithBytes:bytes length:sizeof(bytes)]];
   [output flush];
 
@@ -286,6 +289,7 @@
   TestAllTypes* message = [TestAllTypes parseFromCodedInputStream:input
                                                 extensionRegistry:nil
                                                             error:NULL];
+  XCTAssertNotNil(message);
   // Make sure we can read string properties twice without crashing.
   XCTAssertEqual([message.defaultString length], (NSUInteger)0);
   XCTAssertEqualObjects(@"", message.defaultString);

+ 0 - 513
objectivec/Tests/GPBStringTests.m

@@ -1,513 +0,0 @@
-// 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.
-
-#import <XCTest/XCTest.h>
-
-#import "GPBCodedInputStream_PackagePrivate.h"
-#import "GPBTestUtilities.h"
-
-@interface TestClass : NSObject
-@property(nonatomic, retain) NSString *foo;
-@end
-
-@implementation TestClass
-@synthesize foo;
-@end
-
-@interface GPBStringTests : XCTestCase {
-  NSMutableArray *nsStrings_;
-  NSMutableArray *gpbStrings_;
-}
-
-@end
-
-@implementation GPBStringTests
-
-- (void)setUp {
-  [super setUp];
-  const char *strings[] = {
-      "ascii string",
-      "non-ascii string \xc3\xa9",  // e with acute accent
-      "\xe2\x99\xa1",               // White Heart
-      "mix \xe2\x99\xa4 string",    // White Spade
-
-      // Decomposed forms from http://www.unicode.org/reports/tr15/
-      // 1.2 Singletons
-      "\xe2\x84\xa8 = A\xcc\x8a = \xc3\x85", "\xe2\x84\xa6 = \xce\xa9",
-
-      // 1.2 Canonical Composites
-      "A\xcc\x8a = \xc3\x85",
-      "o\xcc\x82 = \xc3\xb4",
-
-      // 1.2 Multiple Combining Marks
-      "s\xcc\xa3\xcc\x87 = \xe1\xb9\xa9",
-      "\xe1\xb8\x8b\xcc\xa3 = d\xcc\xa3\xcc\x87 = \xe1\xb8\x8d \xcc\x87",
-      "q\xcc\x87\xcc\xa3 = q\xcc\xa3\xcc\x87",
-
-      // BOM
-      "\xEF\xBB\xBF String with BOM",
-      "String with \xEF\xBB\xBF in middle",
-      "String with end bom \xEF\xBB\xBF",
-      "\xEF\xBB\xBF\xe2\x99\xa1",  // BOM White Heart
-      "\xEF\xBB\xBF\xEF\xBB\xBF String with Two BOM",
-
-      // Supplementary Plane
-      "\xf0\x9d\x84\x9e",  // MUSICAL SYMBOL G CLEF
-
-      // Tags
-      "\xf3\xa0\x80\x81",  // Language Tag
-
-      // Variation Selectors
-      "\xf3\xa0\x84\x80",  // VARIATION SELECTOR-17
-
-      // Specials
-      "\xef\xbb\xbf\xef\xbf\xbd\xef\xbf\xbf",
-
-      // Left To Right/Right To Left
-      // http://unicode.org/reports/tr9/
-
-      // Hello! <RTL marker>!Merhaba<LTR marker>
-      "Hello! \xE2\x80\x8F!\xd9\x85\xd8\xb1\xd8\xad\xd8\xa8\xd8\xa7\xE2\x80\x8E",
-
-      "\xE2\x80\x8E LTR At Start",
-      "LTR At End\xE2\x80\x8E",
-      "\xE2\x80\x8F RTL At Start",
-      "RTL At End\xE2\x80\x8F",
-      "\xE2\x80\x8E\xE2\x80\x8E Double LTR \xE2\x80\x8E\xE2\x80\x8E",
-      "\xE2\x80\x8F\xE2\x80\x8F Double RTL \xE2\x80\x8F\xE2\x80\x8F",
-      "\xE2\x80\x8F\xE2\x80\x8E LTR-RTL LTR-RTL \xE2\x80\x8E\xE2\x80\x8F",
-  };
-  size_t stringsSize = GPBARRAYSIZE(strings);
-  size_t numberUnicodeStrings = 17375;
-  nsStrings_ = [[NSMutableArray alloc]
-      initWithCapacity:stringsSize + numberUnicodeStrings];
-  gpbStrings_ = [[NSMutableArray alloc]
-      initWithCapacity:stringsSize + numberUnicodeStrings];
-  for (size_t i = 0; i < stringsSize; ++i) {
-    size_t length = strlen(strings[i]);
-    NSString *nsString = [[NSString alloc] initWithBytes:strings[i]
-                                                  length:length
-                                                encoding:NSUTF8StringEncoding];
-    [nsStrings_ addObject:nsString];
-    [nsString release];
-    GPBString *gpbString = GPBCreateGPBStringWithUTF8(strings[i], length);
-    [gpbStrings_ addObject:gpbString];
-    [gpbString release];
-  }
-
-  // Generate all UTF8 characters in a variety of strings
-  // UTF8-1 - 1 Byte UTF 8 chars
-  int length = 0x7F + 1;
-  char *buffer = (char *)calloc(length, 1);
-  for (int i = 0; i < length; ++i) {
-    buffer[i] = (char)i;
-  }
-  NSString *nsString = [[NSString alloc] initWithBytes:buffer
-                                                length:length
-                                              encoding:NSUTF8StringEncoding];
-  [nsStrings_ addObject:nsString];
-  [nsString release];
-  GPBString *gpbString = GPBCreateGPBStringWithUTF8(buffer, length);
-  [gpbStrings_ addObject:gpbString];
-  [gpbString release];
-
-  // UTF8-2 - 2 Byte UTF 8 chars
-  int pointLength = 0xbf - 0x80 + 1;
-  length = pointLength * 2;
-  buffer = (char *)calloc(length, 1);
-  for (int i = 0xc2; i <= 0xdf; ++i) {
-    char *bufferPtr = buffer;
-    for (int j = 0x80; j <= 0xbf; ++j) {
-      (*bufferPtr++) = (char)i;
-      (*bufferPtr++) = (char)j;
-    }
-    nsString = [[NSString alloc] initWithBytes:buffer
-                                        length:length
-                                      encoding:NSUTF8StringEncoding];
-    [nsStrings_ addObject:nsString];
-    [nsString release];
-    gpbString = GPBCreateGPBStringWithUTF8(buffer, length);
-    [gpbStrings_ addObject:gpbString];
-    [gpbString release];
-  }
-  free(buffer);
-
-  // UTF8-3 - 3 Byte UTF 8 chars
-  length = pointLength * 3;
-  buffer = (char *)calloc(length, 1);
-  for (int i = 0xa0; i <= 0xbf; ++i) {
-    char *bufferPtr = buffer;
-    for (int j = 0x80; j <= 0xbf; ++j) {
-      (*bufferPtr++) = (char)0xE0;
-      (*bufferPtr++) = (char)i;
-      (*bufferPtr++) = (char)j;
-    }
-    nsString = [[NSString alloc] initWithBytes:buffer
-                                        length:length
-                                      encoding:NSUTF8StringEncoding];
-    [nsStrings_ addObject:nsString];
-    [nsString release];
-    gpbString = GPBCreateGPBStringWithUTF8(buffer, length);
-    [gpbStrings_ addObject:gpbString];
-    [gpbString release];
-  }
-  for (int i = 0xe1; i <= 0xec; ++i) {
-    for (int j = 0x80; j <= 0xbf; ++j) {
-      char *bufferPtr = buffer;
-      for (int k = 0x80; k <= 0xbf; ++k) {
-        (*bufferPtr++) = (char)i;
-        (*bufferPtr++) = (char)j;
-        (*bufferPtr++) = (char)k;
-      }
-      nsString = [[NSString alloc] initWithBytes:buffer
-                                          length:length
-                                        encoding:NSUTF8StringEncoding];
-      [nsStrings_ addObject:nsString];
-      [nsString release];
-      gpbString = GPBCreateGPBStringWithUTF8(buffer, length);
-      [gpbStrings_ addObject:gpbString];
-      [gpbString release];
-    }
-  }
-  for (int i = 0x80; i <= 0x9f; ++i) {
-    char *bufferPtr = buffer;
-    for (int j = 0x80; j <= 0xbf; ++j) {
-      (*bufferPtr++) = (char)0xED;
-      (*bufferPtr++) = (char)i;
-      (*bufferPtr++) = (char)j;
-    }
-    nsString = [[NSString alloc] initWithBytes:buffer
-                                        length:length
-                                      encoding:NSUTF8StringEncoding];
-    [nsStrings_ addObject:nsString];
-    [nsString release];
-    gpbString = GPBCreateGPBStringWithUTF8(buffer, length);
-    [gpbStrings_ addObject:gpbString];
-    [gpbString release];
-  }
-  for (int i = 0xee; i <= 0xef; ++i) {
-    for (int j = 0x80; j <= 0xbf; ++j) {
-      char *bufferPtr = buffer;
-      for (int k = 0x80; k <= 0xbf; ++k) {
-        (*bufferPtr++) = (char)i;
-        (*bufferPtr++) = (char)j;
-        (*bufferPtr++) = (char)k;
-      }
-      nsString = [[NSString alloc] initWithBytes:buffer
-                                          length:length
-                                        encoding:NSUTF8StringEncoding];
-      [nsStrings_ addObject:nsString];
-      [nsString release];
-      gpbString = GPBCreateGPBStringWithUTF8(buffer, length);
-      [gpbStrings_ addObject:gpbString];
-      [gpbString release];
-    }
-  }
-  free(buffer);
-
-  // UTF8-4 - 4 Byte UTF 8 chars
-  length = pointLength * 4;
-  buffer = (char *)calloc(length, 1);
-  for (int i = 0x90; i <= 0xbf; ++i) {
-    for (int j = 0x80; j <= 0xbf; ++j) {
-      char *bufferPtr = buffer;
-      for (int k = 0x80; k <= 0xbf; ++k) {
-        (*bufferPtr++) = (char)0xF0;
-        (*bufferPtr++) = (char)i;
-        (*bufferPtr++) = (char)j;
-        (*bufferPtr++) = (char)k;
-      }
-      nsString = [[NSString alloc] initWithBytes:buffer
-                                          length:length
-                                        encoding:NSUTF8StringEncoding];
-      [nsStrings_ addObject:nsString];
-      [nsString release];
-      gpbString = GPBCreateGPBStringWithUTF8(buffer, length);
-      [gpbStrings_ addObject:gpbString];
-      [gpbString release];
-    }
-  }
-  for (int i = 0xf1; i <= 0xf3; ++i) {
-    for (int j = 0x80; j <= 0xbf; ++j) {
-      for (int k = 0x80; k <= 0xbf; ++k) {
-        char *bufferPtr = buffer;
-        for (int m = 0x80; m <= 0xbf; ++m) {
-          (*bufferPtr++) = (char)i;
-          (*bufferPtr++) = (char)j;
-          (*bufferPtr++) = (char)k;
-          (*bufferPtr++) = (char)m;
-        }
-        nsString = [[NSString alloc] initWithBytes:buffer
-                                            length:length
-                                          encoding:NSUTF8StringEncoding];
-        [nsStrings_ addObject:nsString];
-        [nsString release];
-        gpbString = GPBCreateGPBStringWithUTF8(buffer, length);
-        [gpbStrings_ addObject:gpbString];
-        [gpbString release];
-      }
-    }
-  }
-  for (int i = 0x80; i <= 0x8f; ++i) {
-    for (int j = 0x80; j <= 0xbf; ++j) {
-      char *bufferPtr = buffer;
-      for (int k = 0x80; k <= 0xbf; ++k) {
-        (*bufferPtr++) = (char)0xF4;
-        (*bufferPtr++) = (char)i;
-        (*bufferPtr++) = (char)j;
-        (*bufferPtr++) = (char)k;
-      }
-      nsString = [[NSString alloc] initWithBytes:buffer
-                                          length:length
-                                        encoding:NSUTF8StringEncoding];
-      [nsStrings_ addObject:nsString];
-      [nsString release];
-      gpbString = GPBCreateGPBStringWithUTF8(buffer, length);
-      [gpbStrings_ addObject:gpbString];
-      [gpbString release];
-    }
-  }
-  free(buffer);
-}
-
-- (void)tearDown {
-  [nsStrings_ release];
-  [gpbStrings_ release];
-  [super tearDown];
-}
-
-- (void)testLength {
-  size_t i = 0;
-  for (NSString *nsString in nsStrings_) {
-    GPBString *gpbString = gpbStrings_[i];
-    XCTAssertEqual([nsString length], [gpbString length], @"%@ %@", nsString,
-                   gpbString);
-    ++i;
-  }
-}
-
-- (void)testLengthOfBytesUsingEncoding {
-  NSStringEncoding encodings[] = {
-    NSUTF8StringEncoding,
-    NSASCIIStringEncoding,
-    NSISOLatin1StringEncoding,
-    NSMacOSRomanStringEncoding,
-    NSUTF16StringEncoding,
-    NSUTF32StringEncoding,
-  };
-
-  for (size_t j = 0; j < GPBARRAYSIZE(encodings); ++j) {
-    NSStringEncoding testEncoding = encodings[j];
-    size_t i = 0;
-    for (NSString *nsString in nsStrings_) {
-      GPBString *gpbString = gpbStrings_[i];
-      XCTAssertEqual([nsString lengthOfBytesUsingEncoding:testEncoding],
-                     [gpbString lengthOfBytesUsingEncoding:testEncoding],
-                     @"%@ %@", nsString, gpbString);
-      ++i;
-    }
-  }
-}
-
-- (void)testHash {
-  size_t i = 0;
-  for (NSString *nsString in nsStrings_) {
-    GPBString *gpbString = gpbStrings_[i];
-    XCTAssertEqual([nsString hash], [gpbString hash], @"%@ %@", nsString,
-                   gpbString);
-    ++i;
-  }
-}
-
-- (void)testEquality {
-  size_t i = 0;
-  for (NSString *nsString in nsStrings_) {
-    GPBString *gpbString = gpbStrings_[i];
-    XCTAssertEqualObjects(nsString, gpbString);
-    ++i;
-  }
-}
-
-- (void)testCharacterAtIndex {
-  size_t i = 0;
-  for (NSString *nsString in nsStrings_) {
-    GPBString *gpbString = gpbStrings_[i];
-    NSUInteger length = [nsString length];
-    for (size_t j = 0; j < length; ++j) {
-      unichar nsChar = [nsString characterAtIndex:j];
-      unichar pbChar = [gpbString characterAtIndex:j];
-      XCTAssertEqual(nsChar, pbChar, @"%@ %@ %zu", nsString, gpbString, j);
-    }
-    ++i;
-  }
-}
-
-- (void)testCopy {
-  size_t i = 0;
-  for (NSString *nsString in nsStrings_) {
-    GPBString *gpbString = [[gpbStrings_[i] copy] autorelease];
-    XCTAssertEqualObjects(nsString, gpbString);
-    ++i;
-  }
-}
-
-- (void)testMutableCopy {
-  size_t i = 0;
-  for (NSString *nsString in nsStrings_) {
-    GPBString *gpbString = [[gpbStrings_[i] mutableCopy] autorelease];
-    XCTAssertEqualObjects(nsString, gpbString);
-    ++i;
-  }
-}
-
-- (void)testGetBytes {
-  // Do an attempt at a reasonably exhaustive test of get bytes.
-  // Get bytes with options other than 0 should always fall through to Apple
-  // code so we don't bother testing that path.
-  size_t i = 0;
-  char pbBuffer[256];
-  char nsBuffer[256];
-  int count = 0;
-  for (NSString *nsString in nsStrings_) {
-    GPBString *gpbString = gpbStrings_[i];
-    for (int j = 0; j < 100; ++j) {
-      // [NSString getBytes:maxLength:usedLength:encoding:options:range:remainingRange]
-      // does not return reliable results if the maxLength argument is 0,
-      // or range is 0,0.
-      // Radar 16385183
-      NSUInteger length = [nsString length];
-      NSUInteger maxBufferCount = (arc4random() % (length + 3)) + 1;
-      NSUInteger rangeStart = arc4random() % length;
-      NSUInteger rangeLength = arc4random() % (length - rangeStart);
-
-      NSRange range = NSMakeRange(rangeStart, rangeLength);
-
-      NSStringEncoding encodings[] = {
-        NSASCIIStringEncoding,
-        NSUTF8StringEncoding,
-        NSUTF16StringEncoding,
-      };
-
-      for (size_t k = 0; k < GPBARRAYSIZE(encodings); ++k) {
-        NSStringEncoding encoding = encodings[k];
-        NSUInteger pbUsedBufferCount = 0;
-        NSUInteger nsUsedBufferCount = 0;
-        NSRange pbLeftOver = NSMakeRange(0, 0);
-        NSRange nsLeftOver = NSMakeRange(0, 0);
-
-        BOOL pbGotBytes = [gpbString getBytes:pbBuffer
-                                    maxLength:maxBufferCount
-                                   usedLength:&pbUsedBufferCount
-                                     encoding:encoding
-                                      options:0
-                                        range:range
-                               remainingRange:&pbLeftOver];
-        BOOL nsGotBytes = [nsString getBytes:nsBuffer
-                                   maxLength:maxBufferCount
-                                  usedLength:&nsUsedBufferCount
-                                    encoding:encoding
-                                     options:0
-                                       range:range
-                              remainingRange:&nsLeftOver];
-        XCTAssertEqual(
-            (bool)pbGotBytes, (bool)nsGotBytes,
-            @"PB %d '%@' vs '%@' Encoding:%tu MaxLength: %tu Range: %@ "
-            @"Used: %tu, %tu LeftOver %@, %@)",
-            count, gpbString, nsString, encoding, maxBufferCount,
-            NSStringFromRange(range), pbUsedBufferCount, nsUsedBufferCount,
-            NSStringFromRange(pbLeftOver), NSStringFromRange(nsLeftOver));
-        XCTAssertEqual(
-            pbUsedBufferCount, nsUsedBufferCount,
-            @"PB %d '%@' vs '%@' Encoding:%tu MaxLength: %tu Range: %@ "
-            @"Used: %tu, %tu LeftOver %@, %@)",
-            count, gpbString, nsString, encoding, maxBufferCount,
-            NSStringFromRange(range), pbUsedBufferCount, nsUsedBufferCount,
-            NSStringFromRange(pbLeftOver), NSStringFromRange(nsLeftOver));
-        XCTAssertEqual(
-            pbLeftOver.location, nsLeftOver.location,
-            @"PB %d '%@' vs '%@' Encoding:%tu MaxLength: %tu Range: %@ "
-            @"Used: %tu, %tu LeftOver %@, %@)",
-            count, gpbString, nsString, encoding, maxBufferCount,
-            NSStringFromRange(range), pbUsedBufferCount, nsUsedBufferCount,
-            NSStringFromRange(pbLeftOver), NSStringFromRange(nsLeftOver));
-        XCTAssertEqual(
-            pbLeftOver.length, nsLeftOver.length,
-            @"PB %d '%@' vs '%@' Encoding:%tu MaxLength: %tu Range: %@ "
-            @"Used: %tu, %tu LeftOver %@, %@)",
-            count, gpbString, nsString, encoding, maxBufferCount,
-            NSStringFromRange(range), pbUsedBufferCount, nsUsedBufferCount,
-            NSStringFromRange(pbLeftOver), NSStringFromRange(nsLeftOver));
-        ++count;
-      }
-    }
-    ++i;
-  }
-}
-
-- (void)testLengthAndGetBytes {
-  // This test exists as an attempt to ferret out a bug.
-  // http://b/13516532
-  size_t i = 0;
-  char pbBuffer[256];
-  char nsBuffer[256];
-  for (NSString *nsString in nsStrings_) {
-    GPBString *gpbString = gpbStrings_[i++];
-    NSUInteger nsLength =
-        [nsString lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
-    NSUInteger pbLength =
-        [gpbString lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
-    XCTAssertEqual(nsLength, pbLength, @"%@ %@", nsString, gpbString);
-    NSUInteger pbUsedBufferCount = 0;
-    NSUInteger nsUsedBufferCount = 0;
-    NSRange pbLeftOver = NSMakeRange(0, 0);
-    NSRange nsLeftOver = NSMakeRange(0, 0);
-    NSRange range = NSMakeRange(0, [gpbString length]);
-    BOOL pbGotBytes = [gpbString getBytes:pbBuffer
-                                maxLength:sizeof(pbBuffer)
-                               usedLength:&pbUsedBufferCount
-                                 encoding:NSUTF8StringEncoding
-                                  options:0
-                                    range:range
-                           remainingRange:&pbLeftOver];
-    BOOL nsGotBytes = [nsString getBytes:nsBuffer
-                               maxLength:sizeof(nsBuffer)
-                              usedLength:&nsUsedBufferCount
-                                encoding:NSUTF8StringEncoding
-                                 options:0
-                                   range:range
-                          remainingRange:&nsLeftOver];
-    XCTAssertTrue(pbGotBytes, @"%@", gpbString);
-    XCTAssertTrue(nsGotBytes, @"%@", nsString);
-    XCTAssertEqual(pbUsedBufferCount, pbLength, @"%@", gpbString);
-    XCTAssertEqual(nsUsedBufferCount, nsLength, @"%@", nsString);
-  }
-}
-
-@end

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

@@ -353,7 +353,7 @@ void MessageGenerator::GenerateFrameworkMethods(io::Printer* printer) {
 
     printer->Print(
         "public override string ToString() {\n"
-        "  return pb::JsonFormatter.Default.Format(this);\n"
+        "  return pb::JsonFormatter.ToDiagnosticString(this);\n"
         "}\n\n");
 }
 

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

@@ -560,7 +560,7 @@ class FileDescriptorTables {
   ~FileDescriptorTables();
 
   // Empty table, used with placeholder files.
-  static const FileDescriptorTables kEmpty;
+  inline static const FileDescriptorTables& GetEmptyInstance();
 
   // -----------------------------------------------------------------
   // Finding items.
@@ -665,7 +665,32 @@ FileDescriptorTables::FileDescriptorTables()
 
 FileDescriptorTables::~FileDescriptorTables() {}
 
-const FileDescriptorTables FileDescriptorTables::kEmpty;
+namespace {
+
+FileDescriptorTables* file_descriptor_tables_ = NULL;
+GOOGLE_PROTOBUF_DECLARE_ONCE(file_descriptor_tables_once_init_);
+
+void DeleteFileDescriptorTables() {
+  delete file_descriptor_tables_;
+  file_descriptor_tables_ = NULL;
+}
+
+void InitFileDescriptorTables() {
+  file_descriptor_tables_ = new FileDescriptorTables();
+  internal::OnShutdown(&DeleteFileDescriptorTables);
+}
+
+inline void InitFileDescriptorTablesOnce() {
+  ::google::protobuf::GoogleOnceInit(
+      &file_descriptor_tables_once_init_, &InitFileDescriptorTables);
+}
+
+}  // anonymous namespace
+
+inline const FileDescriptorTables& FileDescriptorTables::GetEmptyInstance() {
+  InitFileDescriptorTablesOnce();
+  return *file_descriptor_tables_;
+}
 
 void DescriptorPool::Tables::AddCheckpoint() {
   checkpoints_.push_back(CheckPoint(this));
@@ -3537,7 +3562,7 @@ FileDescriptor* DescriptorBuilder::NewPlaceholderFile(
   placeholder->package_ = &internal::GetEmptyString();
   placeholder->pool_ = pool_;
   placeholder->options_ = &FileOptions::default_instance();
-  placeholder->tables_ = &FileDescriptorTables::kEmpty;
+  placeholder->tables_ = &FileDescriptorTables::GetEmptyInstance();
   placeholder->source_code_info_ = &SourceCodeInfo::default_instance();
   placeholder->is_placeholder_ = true;
   placeholder->syntax_ = FileDescriptor::SYNTAX_PROTO2;