فهرست منبع

Down integrate to GitHub

Hao Nguyen 6 سال پیش
والد
کامیت
09cab821a9
64فایلهای تغییر یافته به همراه1556 افزوده شده و 1877 حذف شده
  1. 2 2
      java/core/src/main/java/com/google/protobuf/AbstractMessage.java
  2. 13 3
      java/core/src/main/java/com/google/protobuf/ExtensionRegistryLite.java
  3. 1 1
      java/core/src/main/java/com/google/protobuf/Message.java
  4. 288 120
      java/core/src/main/java/com/google/protobuf/TextFormat.java
  5. 2 2
      java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
  6. 1 1
      java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
  7. 1 1
      java/core/src/test/java/com/google/protobuf/MapTest.java
  8. 61 40
      java/core/src/test/java/com/google/protobuf/TextFormatTest.java
  9. 1 1
      java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java
  10. 11 11
      js/message.js
  11. 1 0
      protobuf.pc.in
  12. 76 8
      python/google/protobuf/internal/descriptor_pool_test.py
  13. 17 0
      python/google/protobuf/internal/json_format_test.py
  14. 9 7
      python/google/protobuf/json_format.py
  15. 81 49
      python/google/protobuf/pyext/descriptor_pool.cc
  16. 4 0
      python/google/protobuf/pyext/descriptor_pool.h
  17. 1 0
      python/setup.py
  18. 0 9
      src/google/protobuf/any.pb.cc
  19. 8 3
      src/google/protobuf/any.pb.h
  20. 0 37
      src/google/protobuf/api.pb.cc
  21. 34 19
      src/google/protobuf/api.pb.h
  22. 1 1
      src/google/protobuf/arena.h
  23. 4 0
      src/google/protobuf/compiler/command_line_interface_unittest.cc
  24. 3 3
      src/google/protobuf/compiler/cpp/cpp_helpers.cc
  25. 39 52
      src/google/protobuf/compiler/cpp/cpp_message.cc
  26. 13 5
      src/google/protobuf/compiler/js/js_generator.cc
  27. 1 1
      src/google/protobuf/compiler/js/js_generator.h
  28. 0 41
      src/google/protobuf/compiler/plugin.pb.cc
  29. 37 17
      src/google/protobuf/compiler/plugin.pb.h
  30. 4 1
      src/google/protobuf/compiler/subprocess.cc
  31. 0 669
      src/google/protobuf/descriptor.pb.cc
  32. 291 92
      src/google/protobuf/descriptor.pb.h
  33. 0 24
      src/google/protobuf/duration.pb.cc
  34. 17 4
      src/google/protobuf/duration.pb.h
  35. 0 22
      src/google/protobuf/empty.pb.cc
  36. 13 2
      src/google/protobuf/empty.pb.h
  37. 1 2
      src/google/protobuf/extension_set_inl.h
  38. 0 23
      src/google/protobuf/field_mask.pb.cc
  39. 16 3
      src/google/protobuf/field_mask.pb.h
  40. 9 0
      src/google/protobuf/generated_message_util.cc
  41. 1 0
      src/google/protobuf/generated_message_util.h
  42. 8 1
      src/google/protobuf/message.cc
  43. 1 1
      src/google/protobuf/message.h
  44. 8 6
      src/google/protobuf/parse_context.cc
  45. 3 3
      src/google/protobuf/parse_context.h
  46. 43 41
      src/google/protobuf/repeated_field.h
  47. 0 8
      src/google/protobuf/source_context.pb.cc
  48. 7 2
      src/google/protobuf/source_context.pb.h
  49. 0 74
      src/google/protobuf/struct.pb.cc
  50. 53 14
      src/google/protobuf/struct.pb.h
  51. 1 2
      src/google/protobuf/stubs/mathutil.h
  52. 0 24
      src/google/protobuf/timestamp.pb.cc
  53. 17 4
      src/google/protobuf/timestamp.pb.h
  54. 0 136
      src/google/protobuf/type.pb.cc
  55. 101 36
      src/google/protobuf/type.pb.h
  56. 8 6
      src/google/protobuf/unknown_field_set.cc
  57. 4 3
      src/google/protobuf/unknown_field_set.h
  58. 14 0
      src/google/protobuf/util/field_comparator_test.cc
  59. 11 0
      src/google/protobuf/util/json_format.proto
  60. 9 3
      src/google/protobuf/util/message_differencer.cc
  61. 59 0
      src/google/protobuf/util/message_differencer_unittest.cc
  62. 3 3
      src/google/protobuf/wire_format_lite.h
  63. 0 207
      src/google/protobuf/wrappers.pb.cc
  64. 144 27
      src/google/protobuf/wrappers.pb.h

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

@@ -108,7 +108,7 @@ public abstract class AbstractMessage
 
   @Override
   public final String toString() {
-    return TextFormat.printToString(this);
+    return TextFormat.printer().printToString(this);
   }
 
   @Override
@@ -468,7 +468,7 @@ public abstract class AbstractMessage
 
     @Override
     public String toString() {
-      return TextFormat.printToString(this);
+      return TextFormat.printer().printToString(this);
     }
 
     /** Construct an UninitializedMessageException reporting missing fields in the given message. */

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

@@ -76,6 +76,10 @@ public class ExtensionRegistryLite {
   // applications. Need to support this feature on smaller granularity.
   private static volatile boolean eagerlyParseMessageSets = false;
 
+  // short circuit the ExtensionRegistryFactory via assumevalues trickery
+  @SuppressWarnings("JavaOptionalSuggestions")
+  private static boolean doFullRuntimeInheritanceCheck = true;
+
   // Visible for testing.
   static final String EXTENSION_CLASS_NAME = "com.google.protobuf.Extension";
 
@@ -107,7 +111,9 @@ public class ExtensionRegistryLite {
    * available.
    */
   public static ExtensionRegistryLite newInstance() {
-    return ExtensionRegistryFactory.create();
+    return doFullRuntimeInheritanceCheck
+        ? ExtensionRegistryFactory.create()
+        : new ExtensionRegistryLite();
   }
 
   private static volatile ExtensionRegistryLite emptyRegistry;
@@ -122,7 +128,11 @@ public class ExtensionRegistryLite {
       synchronized (ExtensionRegistryLite.class) {
         result = emptyRegistry;
         if (result == null) {
-          result = emptyRegistry = ExtensionRegistryFactory.createEmpty();
+          result =
+              emptyRegistry =
+                  doFullRuntimeInheritanceCheck
+                      ? ExtensionRegistryFactory.createEmpty()
+                      : EMPTY_REGISTRY_LITE;
         }
       }
     }
@@ -163,7 +173,7 @@ public class ExtensionRegistryLite {
     if (GeneratedMessageLite.GeneratedExtension.class.isAssignableFrom(extension.getClass())) {
       add((GeneratedMessageLite.GeneratedExtension<?, ?>) extension);
     }
-    if (ExtensionRegistryFactory.isFullRegistry(this)) {
+    if (doFullRuntimeInheritanceCheck && ExtensionRegistryFactory.isFullRegistry(this)) {
       try {
         this.getClass().getMethod("add", extensionClass).invoke(this, extension);
       } catch (Exception e) {

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

@@ -85,7 +85,7 @@ public interface Message extends MessageLite, MessageOrBuilder {
 
   /**
    * Converts the message to a string in protocol buffer text format. This is just a trivial wrapper
-   * around {@link TextFormat#printToString(MessageOrBuilder)}.
+   * around {@link TextFormat.Printer#printToString(MessageOrBuilder)}.
    */
   @Override
   String toString();

+ 288 - 120
java/core/src/main/java/com/google/protobuf/TextFormat.java

@@ -61,135 +61,132 @@ public final class TextFormat {
    * Outputs a textual representation of the Protocol Message supplied into the parameter output.
    * (This representation is the new version of the classic "ProtocolPrinter" output from the
    * original Protocol Buffer system)
+   *
+   * @deprecated Use {@code printer().print(MessageOrBuilder, Appendable)}
    */
+  @Deprecated
   public static void print(final MessageOrBuilder message, final Appendable output)
       throws IOException {
-    Printer.DEFAULT.print(message, multiLineOutput(output));
+    printer().print(message, output);
   }
 
-  /** Outputs a textual representation of {@code fields} to {@code output}. */
+  /**
+   * Outputs a textual representation of {@code fields} to {@code output}.
+   *
+   * @deprecated Use {@code printer().print(UnknownFieldSet, Appendable)}
+   */
+  @Deprecated
   public static void print(final UnknownFieldSet fields, final Appendable output)
       throws IOException {
-    Printer.DEFAULT.printUnknownFields(fields, multiLineOutput(output));
+    printer().print(fields, output);
   }
 
-  /** Same as {@code print()}, except that non-ASCII characters are not escaped. */
+  /**
+   * Same as {@code print()}, except that non-ASCII characters are not escaped.
+   *
+   * @deprecated Use {@code printer().escapingNonAscii(false).print(MessageOrBuilder, Appendable)}
+   */
+  @Deprecated
   public static void printUnicode(final MessageOrBuilder message, final Appendable output)
       throws IOException {
-    Printer.UNICODE.print(message, multiLineOutput(output));
+    printer().escapingNonAscii(false).print(message, output);
   }
 
-  /** Same as {@code print()}, except that non-ASCII characters are not escaped. */
+  /**
+   * Same as {@code print()}, except that non-ASCII characters are not escaped.
+   *
+   * @deprecated Use {@code printer().escapingNonAscii(false).print(UnknownFieldSet, Appendable)}
+   */
+  @Deprecated
   public static void printUnicode(final UnknownFieldSet fields, final Appendable output)
       throws IOException {
-    Printer.UNICODE.printUnknownFields(fields, multiLineOutput(output));
+    printer().escapingNonAscii(false).print(fields, output);
   }
 
   /**
    * Generates a human readable form of this message, useful for debugging and other purposes, with
-   * no newline characters.
+   * no newline characters. This is just a trivial wrapper around
+   * {@link TextFormat.Printer#shortDebugString(MessageOrBuilder)}.
    */
   public static String shortDebugString(final MessageOrBuilder message) {
-    try {
-      final StringBuilder text = new StringBuilder();
-      Printer.DEFAULT.print(message, singleLineOutput(text));
-      return text.toString();
-    } catch (IOException e) {
-      throw new IllegalStateException(e);
-    }
+    return printer().shortDebugString(message);
   }
 
   /**
    * Generates a human readable form of the field, useful for debugging and other purposes, with no
    * newline characters.
+   *
+   * @deprecated Use {@code printer().shortDebugString(FieldDescriptor, Object)}
    */
+  @Deprecated
   public static String shortDebugString(final FieldDescriptor field, final Object value) {
-    try {
-      final StringBuilder text = new StringBuilder();
-      Printer.DEFAULT.printField(field, value, singleLineOutput(text));
-      return text.toString();
-    } catch (IOException e) {
-      throw new IllegalStateException(e);
-    }
+    return printer().shortDebugString(field, value);
   }
 
   /**
    * Generates a human readable form of the unknown fields, useful for debugging and other purposes,
    * with no newline characters.
+   *
+   * @deprecated Use {@code printer().shortDebugString(UnknownFieldSet)}
    */
+  @Deprecated
   public static String shortDebugString(final UnknownFieldSet fields) {
-    try {
-      final StringBuilder text = new StringBuilder();
-      Printer.DEFAULT.printUnknownFields(fields, singleLineOutput(text));
-      return text.toString();
-    } catch (IOException e) {
-      throw new IllegalStateException(e);
-    }
+    return printer().shortDebugString(fields);
   }
 
-  /** Like {@code print()}, but writes directly to a {@code String} and returns it. */
+  /**
+   * Like {@code print()}, but writes directly to a {@code String} and returns it.
+   *
+   * @deprecated Use {@link MessageOrBuilder#toString()}
+   */
+  @Deprecated
   public static String printToString(final MessageOrBuilder message) {
-    try {
-      final StringBuilder text = new StringBuilder();
-      print(message, text);
-      return text.toString();
-    } catch (IOException e) {
-      throw new IllegalStateException(e);
-    }
+    return printer().printToString(message);
   }
 
-  /** Like {@code print()}, but writes directly to a {@code String} and returns it. */
+  /**
+   * Like {@code print()}, but writes directly to a {@code String} and returns it.
+   *
+   * @deprecated Use {@link UnknownFieldSet#toString()}
+   */
+  @Deprecated
   public static String printToString(final UnknownFieldSet fields) {
-    try {
-      final StringBuilder text = new StringBuilder();
-      print(fields, text);
-      return text.toString();
-    } catch (IOException e) {
-      throw new IllegalStateException(e);
-    }
+    return printer().printToString(fields);
   }
 
   /**
    * Same as {@code printToString()}, except that non-ASCII characters in string type fields are not
    * escaped in backslash+octals.
+   *
+   * @deprecated Use {@code printer().escapingNonAscii(false).printToString(MessageOrBuilder)}
    */
+  @Deprecated
   public static String printToUnicodeString(final MessageOrBuilder message) {
-    try {
-      final StringBuilder text = new StringBuilder();
-      Printer.UNICODE.print(message, multiLineOutput(text));
-      return text.toString();
-    } catch (IOException e) {
-      throw new IllegalStateException(e);
-    }
+    return printer().escapingNonAscii(false).printToString(message);
   }
 
   /**
    * Same as {@code printToString()}, except that non-ASCII characters in string type fields are not
    * escaped in backslash+octals.
+   *
+   * @deprecated Use {@code printer().escapingNonAscii(false).printToString(UnknownFieldSet)}
    */
+  @Deprecated
   public static String printToUnicodeString(final UnknownFieldSet fields) {
-    try {
-      final StringBuilder text = new StringBuilder();
-      Printer.UNICODE.printUnknownFields(fields, multiLineOutput(text));
-      return text.toString();
-    } catch (IOException e) {
-      throw new IllegalStateException(e);
-    }
+    return printer().escapingNonAscii(false).printToString(fields);
   }
 
+  /** @deprecated Use {@code printer().printField(FieldDescriptor, Object, Appendable)} */
+  @Deprecated
   public static void printField(
       final FieldDescriptor field, final Object value, final Appendable output) throws IOException {
-    Printer.DEFAULT.printField(field, value, multiLineOutput(output));
+    printer().printField(field, value, output);
   }
 
+  /** @deprecated Use {@code printer().printFieldToString(FieldDescriptor, Object)} */
+  @Deprecated
   public static String printFieldToString(final FieldDescriptor field, final Object value) {
-    try {
-      final StringBuilder text = new StringBuilder();
-      printField(field, value, text);
-      return text.toString();
-    } catch (IOException e) {
-      throw new IllegalStateException(e);
-    }
+    return printer().printFieldToString(field, value);
   }
 
   /**
@@ -198,29 +195,34 @@ public final class TextFormat {
    * <p>Same as {@code printFieldValue()}, except that non-ASCII characters in string type fields
    * are not escaped in backslash+octals.
    *
+   * @deprecated Use {@code printer().escapingNonAscii(false).printFieldValue(FieldDescriptor,
+   *     Object, Appendable)}
    * @param field the descriptor of the field
    * @param value the value of the field
    * @param output the output to which to append the formatted value
    * @throws ClassCastException if the value is not appropriate for the given field descriptor
    * @throws IOException if there is an exception writing to the output
    */
+  @Deprecated
   public static void printUnicodeFieldValue(
       final FieldDescriptor field, final Object value, final Appendable output) throws IOException {
-    Printer.UNICODE.printFieldValue(field, value, multiLineOutput(output));
+    printer().escapingNonAscii(false).printFieldValue(field, value, output);
   }
 
   /**
    * Outputs a textual representation of the value of given field value.
    *
+   * @deprecated Use {@code printer().printFieldValue(FieldDescriptor, Object, Appendable)}
    * @param field the descriptor of the field
    * @param value the value of the field
    * @param output the output to which to append the formatted value
    * @throws ClassCastException if the value is not appropriate for the given field descriptor
    * @throws IOException if there is an exception writing to the output
    */
+  @Deprecated
   public static void printFieldValue(
       final FieldDescriptor field, final Object value, final Appendable output) throws IOException {
-    Printer.DEFAULT.printFieldValue(field, value, multiLineOutput(output));
+    printer().printFieldValue(field, value, output);
   }
 
   /**
@@ -256,7 +258,7 @@ public final class TextFormat {
           generator.print("{");
           generator.eol();
           generator.indent();
-          Printer.DEFAULT.printUnknownFields(message, generator);
+          Printer.printUnknownFields(message, generator);
           generator.outdent();
           generator.print("}");
         } catch (InvalidProtocolBufferException e) {
@@ -267,19 +269,23 @@ public final class TextFormat {
         }
         break;
       case WireFormat.WIRETYPE_START_GROUP:
-        Printer.DEFAULT.printUnknownFields((UnknownFieldSet) value, generator);
+        Printer.printUnknownFields((UnknownFieldSet) value, generator);
         break;
       default:
         throw new IllegalArgumentException("Bad tag: " + tag);
     }
   }
 
+  /** Printer instance which escapes non-ASCII characters. */
+  public static Printer printer() {
+    return Printer.DEFAULT;
+  }
+
   /** Helper class for converting protobufs to text. */
-  private static final class Printer {
+  public static final class Printer {
+
     // Printer instance which escapes non-ASCII characters.
-    static final Printer DEFAULT = new Printer(true);
-    // Printer instance which emits Unicode (it still escapes newlines and quotes in strings).
-    static final Printer UNICODE = new Printer(false);
+    private static final Printer DEFAULT = new Printer(true);
 
     /** Whether to escape non ASCII characters with backslash and octal. */
     private final boolean escapeNonAscii;
@@ -288,12 +294,51 @@ public final class TextFormat {
       this.escapeNonAscii = escapeNonAscii;
     }
 
+    /**
+     * Return a new Printer instance with the specified escape mode.
+     *
+     * @param escapeNonAscii If true, the new Printer will escape non-ASCII characters (this is the
+     *     default behavior. If false, the new Printer will print non-ASCII characters as is. In
+     *     either case, the new Printer still escapes newlines and quotes in strings.
+     * @return a new Printer that clones all other configurations from the current {@link Printer},
+     *     with the escape mode set to the given parameter.
+     */
+    public Printer escapingNonAscii(boolean escapeNonAscii) {
+      return new Printer(escapeNonAscii);
+    }
+
+    /**
+     * Outputs a textual representation of the Protocol Message supplied into the parameter output.
+     * (This representation is the new version of the classic "ProtocolPrinter" output from the
+     * original Protocol Buffer system)
+     */
+    public void print(final MessageOrBuilder message, final Appendable output) throws IOException {
+      print(message, multiLineOutput(output));
+    }
+
+    /** Outputs a textual representation of {@code fields} to {@code output}. */
+    public void print(final UnknownFieldSet fields, final Appendable output) throws IOException {
+      printUnknownFields(fields, multiLineOutput(output));
+    }
+
     private void print(final MessageOrBuilder message, final TextGenerator generator)
         throws IOException {
-      for (Map.Entry<FieldDescriptor, Object> field : message.getAllFields().entrySet()) {
-        printField(field.getKey(), field.getValue(), generator);
+      printMessage(message, generator);
+    }
+
+    public String printFieldToString(final FieldDescriptor field, final Object value) {
+      try {
+        final StringBuilder text = new StringBuilder();
+        printField(field, value, text);
+        return text.toString();
+      } catch (IOException e) {
+        throw new IllegalStateException(e);
       }
-      printUnknownFields(message.getUnknownFields(), generator);
+    }
+
+    public void printField(final FieldDescriptor field, final Object value, final Appendable output)
+        throws IOException {
+      printField(field, value, multiLineOutput(output));
     }
 
     private void printField(
@@ -309,46 +354,19 @@ public final class TextFormat {
       }
     }
 
-    private void printSingleField(
-        final FieldDescriptor field, final Object value, final TextGenerator generator)
+    /**
+     * Outputs a textual representation of the value of given field value.
+     *
+     * @param field the descriptor of the field
+     * @param value the value of the field
+     * @param output the output to which to append the formatted value
+     * @throws ClassCastException if the value is not appropriate for the given field descriptor
+     * @throws IOException if there is an exception writing to the output
+     */
+    public void printFieldValue(
+        final FieldDescriptor field, final Object value, final Appendable output)
         throws IOException {
-      if (field.isExtension()) {
-        generator.print("[");
-        // We special-case MessageSet elements for compatibility with proto1.
-        if (field.getContainingType().getOptions().getMessageSetWireFormat()
-            && (field.getType() == FieldDescriptor.Type.MESSAGE)
-            && (field.isOptional())
-            // object equality
-            && (field.getExtensionScope() == field.getMessageType())) {
-          generator.print(field.getMessageType().getFullName());
-        } else {
-          generator.print(field.getFullName());
-        }
-        generator.print("]");
-      } else {
-        if (field.getType() == FieldDescriptor.Type.GROUP) {
-          // Groups must be serialized with their original capitalization.
-          generator.print(field.getMessageType().getName());
-        } else {
-          generator.print(field.getName());
-        }
-      }
-
-      if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
-        generator.print(" {");
-        generator.eol();
-        generator.indent();
-      } else {
-        generator.print(": ");
-      }
-
-      printFieldValue(field, value, generator);
-
-      if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
-        generator.outdent();
-        generator.print("}");
-      }
-      generator.eol();
+      printFieldValue(field, value, multiLineOutput(output));
     }
 
     private void printFieldValue(
@@ -419,7 +437,157 @@ public final class TextFormat {
       }
     }
 
-    private void printUnknownFields(
+    /** Like {@code print()}, but writes directly to a {@code String} and returns it. */
+    public String printToString(final MessageOrBuilder message) {
+      try {
+        final StringBuilder text = new StringBuilder();
+        print(message, text);
+        return text.toString();
+      } catch (IOException e) {
+        throw new IllegalStateException(e);
+      }
+    }
+    /** Like {@code print()}, but writes directly to a {@code String} and returns it. */
+    public String printToString(final UnknownFieldSet fields) {
+      try {
+        final StringBuilder text = new StringBuilder();
+        print(fields, text);
+        return text.toString();
+      } catch (IOException e) {
+        throw new IllegalStateException(e);
+      }
+    }
+
+    /**
+     * Generates a human readable form of this message, useful for debugging and other purposes,
+     * with no newline characters.
+     */
+    public String shortDebugString(final MessageOrBuilder message) {
+      try {
+        final StringBuilder text = new StringBuilder();
+        print(message, singleLineOutput(text));
+        return text.toString();
+      } catch (IOException e) {
+        throw new IllegalStateException(e);
+      }
+    }
+
+    /**
+     * Generates a human readable form of the field, useful for debugging and other purposes, with
+     * no newline characters.
+     */
+    public String shortDebugString(final FieldDescriptor field, final Object value) {
+      try {
+        final StringBuilder text = new StringBuilder();
+        printField(field, value, singleLineOutput(text));
+        return text.toString();
+      } catch (IOException e) {
+        throw new IllegalStateException(e);
+      }
+    }
+
+    /**
+     * Generates a human readable form of the unknown fields, useful for debugging and other
+     * purposes, with no newline characters.
+     */
+    public String shortDebugString(final UnknownFieldSet fields) {
+      try {
+        final StringBuilder text = new StringBuilder();
+        printUnknownFields(fields, singleLineOutput(text));
+        return text.toString();
+      } catch (IOException e) {
+        throw new IllegalStateException(e);
+      }
+    }
+
+    private static void printUnknownFieldValue(
+        final int tag, final Object value, final TextGenerator generator) throws IOException {
+      switch (WireFormat.getTagWireType(tag)) {
+        case WireFormat.WIRETYPE_VARINT:
+          generator.print(unsignedToString((Long) value));
+          break;
+        case WireFormat.WIRETYPE_FIXED32:
+          generator.print(String.format((Locale) null, "0x%08x", (Integer) value));
+          break;
+        case WireFormat.WIRETYPE_FIXED64:
+          generator.print(String.format((Locale) null, "0x%016x", (Long) value));
+          break;
+        case WireFormat.WIRETYPE_LENGTH_DELIMITED:
+          try {
+            // Try to parse and print the field as an embedded message
+            UnknownFieldSet message = UnknownFieldSet.parseFrom((ByteString) value);
+            generator.print("{");
+            generator.eol();
+            generator.indent();
+            printUnknownFields(message, generator);
+            generator.outdent();
+            generator.print("}");
+          } catch (InvalidProtocolBufferException e) {
+            // If not parseable as a message, print as a String
+            generator.print("\"");
+            generator.print(escapeBytes((ByteString) value));
+            generator.print("\"");
+          }
+          break;
+        case WireFormat.WIRETYPE_START_GROUP:
+          printUnknownFields((UnknownFieldSet) value, generator);
+          break;
+        default:
+          throw new IllegalArgumentException("Bad tag: " + tag);
+      }
+    }
+
+    private void printMessage(final MessageOrBuilder message, final TextGenerator generator)
+        throws IOException {
+      for (Map.Entry<FieldDescriptor, Object> field : message.getAllFields().entrySet()) {
+        printField(field.getKey(), field.getValue(), generator);
+      }
+      printUnknownFields(message.getUnknownFields(), generator);
+    }
+
+    private void printSingleField(
+        final FieldDescriptor field, final Object value, final TextGenerator generator)
+        throws IOException {
+      if (field.isExtension()) {
+        generator.print("[");
+        // We special-case MessageSet elements for compatibility with proto1.
+        if (field.getContainingType().getOptions().getMessageSetWireFormat()
+            && (field.getType() == FieldDescriptor.Type.MESSAGE)
+            && (field.isOptional())
+            // object equality
+            && (field.getExtensionScope() == field.getMessageType())) {
+          generator.print(field.getMessageType().getFullName());
+        } else {
+          generator.print(field.getFullName());
+        }
+        generator.print("]");
+      } else {
+        if (field.getType() == FieldDescriptor.Type.GROUP) {
+          // Groups must be serialized with their original capitalization.
+          generator.print(field.getMessageType().getName());
+        } else {
+          generator.print(field.getName());
+        }
+      }
+
+      if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+        generator.print(" {");
+        generator.eol();
+        generator.indent();
+      } else {
+        generator.print(": ");
+      }
+
+      printFieldValue(field, value, generator);
+
+      if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+        generator.outdent();
+        generator.print("}");
+      }
+      generator.eol();
+    }
+
+    private static void printUnknownFields(
         final UnknownFieldSet unknownFields, final TextGenerator generator) throws IOException {
       for (Map.Entry<Integer, UnknownFieldSet.Field> entry : unknownFields.asMap().entrySet()) {
         final int number = entry.getKey();
@@ -445,7 +613,7 @@ public final class TextFormat {
       }
     }
 
-    private void printUnknownField(
+    private static void printUnknownField(
         final int number, final int wireType, final List<?> values, final TextGenerator generator)
         throws IOException {
       for (final Object value : values) {
@@ -1994,7 +2162,7 @@ public final class TextFormat {
     return escapeBytes(ByteString.copyFromUtf8(input));
   }
 
-  /** Escape double quotes and backslashes in a String for unicode output of a message. */
+  /** Escape double quotes and backslashes in a String for emittingUnicode output of a message. */
   public static String escapeDoubleQuotesAndBackslashes(final String input) {
     return TextFormatEscaper.escapeDoubleQuotesAndBackslashes(input);
   }

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

@@ -140,11 +140,11 @@ public final class UnknownFieldSet implements MessageLite {
 
   /**
    * Converts the set to a string in protocol buffer text format. This is just a trivial wrapper
-   * around {@link TextFormat#printToString(UnknownFieldSet)}.
+   * around {@link TextFormat.Printer#printToString(UnknownFieldSet)}.
    */
   @Override
   public String toString() {
-    return TextFormat.printToString(this);
+    return TextFormat.printer().printToString(this);
   }
 
   /**

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

@@ -766,7 +766,7 @@ public class MapForProto2Test extends TestCase {
     setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
 
-    String textData = TextFormat.printToString(message);
+    String textData = TextFormat.printer().printToString(message);
 
     builder = TestMap.newBuilder();
     TextFormat.merge(textData, builder);

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

@@ -857,7 +857,7 @@ public class MapTest extends TestCase {
     setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
 
-    String textData = TextFormat.printToString(message);
+    String textData = TextFormat.printer().printToString(message);
 
     builder = TestMap.newBuilder();
     TextFormat.merge(textData, builder);

+ 61 - 40
java/core/src/test/java/com/google/protobuf/TextFormatTest.java

@@ -147,7 +147,7 @@ public class TextFormatTest extends TestCase {
 
   /** Print TestAllTypes and compare with golden file. */
   public void testPrintMessage() throws Exception {
-    String javaText = TextFormat.printToString(TestUtil.getAllSet());
+    String javaText = TextFormat.printer().printToString(TestUtil.getAllSet());
 
     // Java likes to add a trailing ".0" to floats and doubles.  C printf
     // (with %g format) does not.  Our golden files are used for both
@@ -159,7 +159,7 @@ public class TextFormatTest extends TestCase {
 
   /** Print TestAllTypes as Builder and compare with golden file. */
   public void testPrintMessageBuilder() throws Exception {
-    String javaText = TextFormat.printToString(TestUtil.getAllSetBuilder());
+    String javaText = TextFormat.printer().printToString(TestUtil.getAllSetBuilder());
 
     // Java likes to add a trailing ".0" to floats and doubles.  C printf
     // (with %g format) does not.  Our golden files are used for both
@@ -171,7 +171,7 @@ public class TextFormatTest extends TestCase {
 
   /** Print TestAllExtensions and compare with golden file. */
   public void testPrintExtensions() throws Exception {
-    String javaText = TextFormat.printToString(TestUtil.getAllExtensionsSet());
+    String javaText = TextFormat.printer().printToString(TestUtil.getAllExtensionsSet());
 
     // Java likes to add a trailing ".0" to floats and doubles.  C printf
     // (with %g format) does not.  Our golden files are used for both
@@ -237,12 +237,13 @@ public class TextFormatTest extends TestCase {
             + "15: 12379813812177893520\n"
             + "15: 0xabcd1234\n"
             + "15: 0xabcdef1234567890\n",
-        TextFormat.printToString(message));
+        TextFormat.printer().printToString(message));
   }
 
   public void testPrintField() throws Exception {
     final FieldDescriptor dataField = OneString.getDescriptor().findFieldByName("data");
-    assertEquals("data: \"test data\"\n", TextFormat.printFieldToString(dataField, "test data"));
+    assertEquals(
+        "data: \"test data\"\n", TextFormat.printer().printFieldToString(dataField, "test data"));
 
     final FieldDescriptor optionalField =
         TestAllTypes.getDescriptor().findFieldByName("optional_nested_message");
@@ -250,7 +251,7 @@ public class TextFormatTest extends TestCase {
 
     assertEquals(
         "optional_nested_message {\n  bb: 42\n}\n",
-        TextFormat.printFieldToString(optionalField, value));
+        TextFormat.printer().printFieldToString(optionalField, value));
   }
 
   /**
@@ -885,7 +886,8 @@ public class TextFormatTest extends TestCase {
   private void assertPrintFieldValue(String expect, Object value, String fieldName)
       throws Exception {
     StringBuilder sb = new StringBuilder();
-    TextFormat.printFieldValue(TestAllTypes.getDescriptor().findFieldByName(fieldName), value, sb);
+    TextFormat.printer()
+        .printFieldValue(TestAllTypes.getDescriptor().findFieldByName(fieldName), value, sb);
     assertEquals(expect, sb.toString());
   }
 
@@ -902,14 +904,17 @@ public class TextFormatTest extends TestCase {
 
   public void testShortDebugString_field() {
     final FieldDescriptor dataField = OneString.getDescriptor().findFieldByName("data");
-    assertEquals("data: \"test data\"", TextFormat.shortDebugString(dataField, "test data"));
+    assertEquals(
+        "data: \"test data\"",
+        TextFormat.printer().shortDebugString(dataField, "test data"));
 
     final FieldDescriptor optionalField =
         TestAllTypes.getDescriptor().findFieldByName("optional_nested_message");
     final Object value = NestedMessage.newBuilder().setBb(42).build();
 
     assertEquals(
-        "optional_nested_message { bb: 42 }", TextFormat.shortDebugString(optionalField, value));
+        "optional_nested_message { bb: 42 }",
+        TextFormat.printer().shortDebugString(optionalField, value));
   }
 
   public void testShortDebugString_unknown() {
@@ -917,7 +922,7 @@ public class TextFormatTest extends TestCase {
         "5: 1 5: 0x00000002 5: 0x0000000000000003 5: \"4\" 5: { 12: 6 } 5 { 10: 5 }"
             + " 8: 1 8: 2 8: 3 15: 12379813812177893520 15: 0xabcd1234 15:"
             + " 0xabcdef1234567890",
-        TextFormat.shortDebugString(makeUnknownFieldSet()));
+        TextFormat.printer().shortDebugString(makeUnknownFieldSet()));
   }
 
   public void testPrintToUnicodeString() throws Exception {
@@ -925,23 +930,26 @@ public class TextFormatTest extends TestCase {
         "optional_string: \"abc\u3042efg\"\n"
             + "optional_bytes: \"\\343\\201\\202\"\n"
             + "repeated_string: \"\u3093XYZ\"\n",
-        TextFormat.printToUnicodeString(
-            TestAllTypes.newBuilder()
-                .setOptionalString("abc\u3042efg")
-                .setOptionalBytes(bytes(0xe3, 0x81, 0x82))
-                .addRepeatedString("\u3093XYZ")
-                .build()));
+        TextFormat.printer()
+            .escapingNonAscii(false)
+            .printToString(
+                TestAllTypes.newBuilder()
+                    .setOptionalString("abc\u3042efg")
+                    .setOptionalBytes(bytes(0xe3, 0x81, 0x82))
+                    .addRepeatedString("\u3093XYZ")
+                    .build()));
 
     // Double quotes and backslashes should be escaped
     assertEquals(
         "optional_string: \"a\\\\bc\\\"ef\\\"g\"\n",
-        TextFormat.printToUnicodeString(
-            TestAllTypes.newBuilder().setOptionalString("a\\bc\"ef\"g").build()));
+        TextFormat.printer()
+            .escapingNonAscii(false)
+            .printToString(TestAllTypes.newBuilder().setOptionalString("a\\bc\"ef\"g").build()));
 
     // Test escaping roundtrip
     TestAllTypes message = TestAllTypes.newBuilder().setOptionalString("a\\bc\\\"ef\"g").build();
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    TextFormat.merge(TextFormat.printToUnicodeString(message), builder);
+    TextFormat.merge(TextFormat.printer().escapingNonAscii(false).printToString(message), builder);
     assertEquals(message.getOptionalString(), builder.getOptionalString());
   }
 
@@ -949,48 +957,61 @@ public class TextFormatTest extends TestCase {
     // No newlines at start and end
     assertEquals(
         "optional_string: \"test newlines\\n\\nin\\nstring\"\n",
-        TextFormat.printToUnicodeString(
-            TestAllTypes.newBuilder().setOptionalString("test newlines\n\nin\nstring").build()));
+        TextFormat.printer()
+            .escapingNonAscii(false)
+            .printToString(
+                TestAllTypes.newBuilder()
+                    .setOptionalString("test newlines\n\nin\nstring")
+                    .build()));
 
     // Newlines at start and end
     assertEquals(
         "optional_string: \"\\ntest\\nnewlines\\n\\nin\\nstring\\n\"\n",
-        TextFormat.printToUnicodeString(
-            TestAllTypes.newBuilder()
-                .setOptionalString("\ntest\nnewlines\n\nin\nstring\n")
-                .build()));
+        TextFormat.printer()
+            .escapingNonAscii(false)
+            .printToString(
+                TestAllTypes.newBuilder()
+                    .setOptionalString("\ntest\nnewlines\n\nin\nstring\n")
+                    .build()));
 
     // Strings with 0, 1 and 2 newlines.
     assertEquals(
         "optional_string: \"\"\n",
-        TextFormat.printToUnicodeString(TestAllTypes.newBuilder().setOptionalString("").build()));
+        TextFormat.printer()
+            .escapingNonAscii(false)
+            .printToString(TestAllTypes.newBuilder().setOptionalString("").build()));
     assertEquals(
         "optional_string: \"\\n\"\n",
-        TextFormat.printToUnicodeString(TestAllTypes.newBuilder().setOptionalString("\n").build()));
+        TextFormat.printer()
+            .escapingNonAscii(false)
+            .printToString(TestAllTypes.newBuilder().setOptionalString("\n").build()));
     assertEquals(
         "optional_string: \"\\n\\n\"\n",
-        TextFormat.printToUnicodeString(
-            TestAllTypes.newBuilder().setOptionalString("\n\n").build()));
+        TextFormat.printer()
+            .escapingNonAscii(false)
+            .printToString(TestAllTypes.newBuilder().setOptionalString("\n\n").build()));
 
     // Test escaping roundtrip
     TestAllTypes message =
         TestAllTypes.newBuilder().setOptionalString("\ntest\nnewlines\n\nin\nstring\n").build();
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    TextFormat.merge(TextFormat.printToUnicodeString(message), builder);
+    TextFormat.merge(TextFormat.printer().escapingNonAscii(false).printToString(message), builder);
     assertEquals(message.getOptionalString(), builder.getOptionalString());
   }
 
   public void testPrintToUnicodeString_unknown() {
     assertEquals(
         "1: \"\\343\\201\\202\"\n",
-        TextFormat.printToUnicodeString(
-            UnknownFieldSet.newBuilder()
-                .addField(
-                    1,
-                    UnknownFieldSet.Field.newBuilder()
-                        .addLengthDelimited(bytes(0xe3, 0x81, 0x82))
-                        .build())
-                .build()));
+        TextFormat.printer()
+            .escapingNonAscii(false)
+            .printToString(
+                UnknownFieldSet.newBuilder()
+                    .addField(
+                        1,
+                        UnknownFieldSet.Field.newBuilder()
+                            .addLengthDelimited(bytes(0xe3, 0x81, 0x82))
+                            .build())
+                    .build()));
   }
 
 
@@ -1120,7 +1141,7 @@ public class TextFormatTest extends TestCase {
     TestUtil.setOneof(builder);
     TestOneof2 message = builder.build();
     TestOneof2.Builder dest = TestOneof2.newBuilder();
-    TextFormat.merge(TextFormat.printToUnicodeString(message), dest);
+    TextFormat.merge(TextFormat.printer().escapingNonAscii(false).printToString(message), dest);
     TestUtil.assertOneofSet(dest.build());
   }
 
@@ -1159,7 +1180,7 @@ public class TextFormatTest extends TestCase {
             .putInt32ToStringField(20, "banana")
             .putInt32ToStringField(30, "cherry")
             .build();
-    String text = TextFormat.printToUnicodeString(message);
+    String text = TextFormat.printer().escapingNonAscii(false).printToString(message);
     {
       TestMap.Builder dest = TestMap.newBuilder();
       TextFormat.merge(text, dest);

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

@@ -234,7 +234,7 @@ public class UnknownEnumValueTest extends TestCase {
     TestAllTypes message = builder.build();
 
     // We can print a message with unknown enum values.
-    String textData = TextFormat.printToString(message);
+    String textData = TextFormat.printer().printToString(message);
     assertEquals(
         "optional_nested_enum: UNKNOWN_ENUM_VALUE_NestedEnum_4321\n"
             + "repeated_nested_enum: UNKNOWN_ENUM_VALUE_NestedEnum_5432\n"

+ 11 - 11
js/message.js

@@ -958,19 +958,19 @@ jspb.Message.getMapField = function(msg, fieldNumber, noLazyCreate,
   // If we already have a map in the map wrappers, return that.
   if (fieldNumber in msg.wrappers_) {
     return msg.wrappers_[fieldNumber];
-  } else if (noLazyCreate) {
-    return undefined;
-  } else {
-    // Wrap the underlying elements array with a Map.
-    var arr = jspb.Message.getField(msg, fieldNumber);
-    if (!arr) {
-      arr = [];
-      jspb.Message.setField(msg, fieldNumber, arr);
+  }
+  var arr = jspb.Message.getField(msg, fieldNumber);
+  // Wrap the underlying elements array with a Map.
+  if (!arr) {
+    if (noLazyCreate) {
+      return undefined;
     }
-    return msg.wrappers_[fieldNumber] =
-        new jspb.Map(
-            /** @type {!Array<!Array<!Object>>} */ (arr), opt_valueCtor);
+    arr = [];
+    jspb.Message.setField(msg, fieldNumber, arr);
   }
+  return msg.wrappers_[fieldNumber] =
+      new jspb.Map(
+          /** @type {!Array<!Array<!Object>>} */ (arr), opt_valueCtor);
 };
 
 

+ 1 - 0
protobuf.pc.in

@@ -8,5 +8,6 @@ Description: Google's Data Interchange Format
 Version: @VERSION@
 Libs: -L${libdir} -lprotobuf @PTHREAD_LIBS@
 Libs.private: @LIBS@
+
 Cflags: -I${includedir} @PTHREAD_CFLAGS@
 Conflicts: protobuf-lite

+ 76 - 8
python/google/protobuf/internal/descriptor_pool_test.py

@@ -615,18 +615,86 @@ class SecondaryDescriptorFromDescriptorDB(DescriptorPoolTestBase,
         factory_test1_pb2.DESCRIPTOR.serialized_pb)
     self.factory_test2_fd = descriptor_pb2.FileDescriptorProto.FromString(
         factory_test2_pb2.DESCRIPTOR.serialized_pb)
-    db = descriptor_database.DescriptorDatabase()
-    db.Add(self.factory_test1_fd)
-    db.Add(self.factory_test2_fd)
-    db.Add(descriptor_pb2.FileDescriptorProto.FromString(
+    self.db = descriptor_database.DescriptorDatabase()
+    self.db.Add(self.factory_test1_fd)
+    self.db.Add(self.factory_test2_fd)
+    self.db.Add(descriptor_pb2.FileDescriptorProto.FromString(
         unittest_import_public_pb2.DESCRIPTOR.serialized_pb))
-    db.Add(descriptor_pb2.FileDescriptorProto.FromString(
+    self.db.Add(descriptor_pb2.FileDescriptorProto.FromString(
         unittest_import_pb2.DESCRIPTOR.serialized_pb))
-    db.Add(descriptor_pb2.FileDescriptorProto.FromString(
+    self.db.Add(descriptor_pb2.FileDescriptorProto.FromString(
         unittest_pb2.DESCRIPTOR.serialized_pb))
-    db.Add(descriptor_pb2.FileDescriptorProto.FromString(
+    self.db.Add(descriptor_pb2.FileDescriptorProto.FromString(
         no_package_pb2.DESCRIPTOR.serialized_pb))
-    self.pool = descriptor_pool.DescriptorPool(descriptor_db=db)
+    self.pool = descriptor_pool.DescriptorPool(descriptor_db=self.db)
+
+  def testErrorCollector(self):
+    file_proto = descriptor_pb2.FileDescriptorProto()
+    file_proto.package = 'collector'
+    file_proto.name = 'error_file'
+    message_type = file_proto.message_type.add()
+    message_type.name = 'ErrorMessage'
+    field = message_type.field.add()
+    field.number = 1
+    field.name = 'nested_message_field'
+    field.label = descriptor.FieldDescriptor.LABEL_OPTIONAL
+    field.type = descriptor.FieldDescriptor.TYPE_MESSAGE
+    field.type_name = 'SubMessage'
+    oneof = message_type.oneof_decl.add()
+    oneof.name = 'MyOneof'
+    enum_type = file_proto.enum_type.add()
+    enum_type.name = 'MyEnum'
+    enum_value = enum_type.value.add()
+    enum_value.name = 'MyEnumValue'
+    enum_value.number = 0
+    self.db.Add(file_proto)
+
+    self.assertRaisesRegexp(KeyError, 'SubMessage',
+                            self.pool.FindMessageTypeByName,
+                            'collector.ErrorMessage')
+    self.assertRaisesRegexp(KeyError, 'SubMessage',
+                            self.pool.FindFileByName, 'error_file')
+    with self.assertRaises(KeyError) as exc:
+      self.pool.FindFileByName('none_file')
+    self.assertIn(str(exc.exception), ('\'none_file\'',
+                                       '\"Couldn\'t find file none_file\"'))
+
+    # Pure python _ConvertFileProtoToFileDescriptor() method has side effect
+    # that all the symbols found in the file will load into the pool even the
+    # file can not build. So when FindMessageTypeByName('ErrorMessage') was
+    # called the first time, a KeyError will be raised but call the find
+    # method later will return a descriptor which is not build.
+    # TODO(jieluo): fix pure python to revert the load if file can not be build
+    if api_implementation.Type() == 'cpp':
+      error_msg = ('Invalid proto descriptor for file "error_file":\\n  '
+                   'collector.ErrorMessage.nested_message_field: "SubMessage" '
+                   'is not defined.\\n  collector.ErrorMessage.MyOneof: Oneof '
+                   'must have at least one field.\\n\'')
+      with self.assertRaises(KeyError) as exc:
+        self.pool.FindMessageTypeByName('collector.ErrorMessage')
+      self.assertEqual(str(exc.exception), '\'Couldn\\\'t build file for '
+                       'message collector.ErrorMessage\\n' + error_msg)
+
+      with self.assertRaises(KeyError) as exc:
+        self.pool.FindFieldByName('collector.ErrorMessage.nested_message_field')
+      self.assertEqual(str(exc.exception), '\'Couldn\\\'t build file for field'
+                       ' collector.ErrorMessage.nested_message_field\\n'
+                       + error_msg)
+
+      with self.assertRaises(KeyError) as exc:
+        self.pool.FindEnumTypeByName('collector.MyEnum')
+      self.assertEqual(str(exc.exception), '\'Couldn\\\'t build file for enum'
+                       ' collector.MyEnum\\n' + error_msg)
+
+      with self.assertRaises(KeyError) as exc:
+        self.pool.FindFileContainingSymbol('collector.MyEnumValue')
+      self.assertEqual(str(exc.exception), '\'Couldn\\\'t build file for symbol'
+                       ' collector.MyEnumValue\\n' + error_msg)
+
+      with self.assertRaises(KeyError) as exc:
+        self.pool.FindOneofByName('collector.ErrorMessage.MyOneof')
+      self.assertEqual(str(exc.exception), '\'Couldn\\\'t build file for oneof'
+                       ' collector.ErrorMessage.MyOneof\\n' + error_msg)
 
 
 class ProtoFile(object):

+ 17 - 0
python/google/protobuf/internal/json_format_test.py

@@ -54,6 +54,7 @@ from google.protobuf import unittest_mset_pb2
 from google.protobuf import unittest_pb2
 from google.protobuf import descriptor_pool
 from google.protobuf import json_format
+from google.protobuf.util import json_format_pb2
 from google.protobuf.util import json_format_proto3_pb2
 
 
@@ -247,6 +248,22 @@ class JsonFormatTest(JsonFormatBase):
     }
     self.assertEqual(golden_dict, message_dict)
 
+  def testExtensionSerializationDictMatchesProto3SpecMore(self):
+    """See go/proto3-json-spec for spec.
+    """
+    message = json_format_pb2.TestMessageWithExtension()
+    ext = json_format_pb2.TestExtension.ext
+    message.Extensions[ext].value = 'stuff'
+    message_dict = json_format.MessageToDict(
+        message
+    )
+    expected_dict = {
+        '[protobuf_unittest.TestExtension.ext]': {
+            'value': u'stuff',
+        },
+    }
+    self.assertEqual(expected_dict, message_dict)
+
 
   def testExtensionSerializationJsonMatchesProto3Spec(self):
     """See go/proto3-json-spec for spec.

+ 9 - 7
python/google/protobuf/json_format.py

@@ -233,12 +233,8 @@ class _Printer(object):
           js[name] = [self._FieldToJsonObject(field, k)
                       for k in value]
         elif field.is_extension:
-          f = field
-          if (f.containing_type.GetOptions().message_set_wire_format and
-              f.type == descriptor.FieldDescriptor.TYPE_MESSAGE and
-              f.label == descriptor.FieldDescriptor.LABEL_OPTIONAL):
-            f = f.message_type
-          name = '[%s.%s]' % (f.full_name, name)
+          full_qualifier = field.full_name[:-len(field.name)]
+          name = '[%s%s]' % (full_qualifier, name)
           js[name] = self._FieldToJsonObject(field, value)
         else:
           js[name] = self._FieldToJsonObject(field, value)
@@ -493,10 +489,16 @@ class _Parser(object):
             raise ParseError('Message type {0} does not have extensions'.format(
                 message_descriptor.full_name))
           identifier = name[1:-1]  # strip [] brackets
-          identifier = '.'.join(identifier.split('.')[:-1])
           # pylint: disable=protected-access
           field = message.Extensions._FindExtensionByName(identifier)
           # pylint: enable=protected-access
+          if not field:
+            # Try looking for extension by the message type name, dropping the
+            # field name following the final . separator in full_name.
+            identifier = '.'.join(identifier.split('.')[:-1])
+            # pylint: disable=protected-access
+            field = message.Extensions._FindExtensionByName(identifier)
+            # pylint: enable=protected-access
         if not field:
           if self.ignore_unknown_fields:
             continue

+ 81 - 49
python/google/protobuf/pyext/descriptor_pool.cc

@@ -67,6 +67,38 @@ static std::unordered_map<const DescriptorPool*, PyDescriptorPool*>*
 
 namespace cdescriptor_pool {
 
+// Collects errors that occur during proto file building to allow them to be
+// propagated in the python exception instead of only living in ERROR logs.
+class BuildFileErrorCollector : public DescriptorPool::ErrorCollector {
+ public:
+  BuildFileErrorCollector() : error_message(""), had_errors_(false) {}
+
+  void AddError(const string& filename, const string& element_name,
+                const Message* descriptor, ErrorLocation location,
+                const string& message) override {
+    // Replicates the logging behavior that happens in the C++ implementation
+    // when an error collector is not passed in.
+    if (!had_errors_) {
+      error_message +=
+          ("Invalid proto descriptor for file \"" + filename + "\":\n");
+      had_errors_ = true;
+    }
+    // As this only happens on failure and will result in the program not
+    // running at all, no effort is made to optimize this string manipulation.
+    error_message += ("  " + element_name + ": " + message + "\n");
+  }
+
+  void Clear() {
+    had_errors_ = false;
+    error_message = "";
+  }
+
+  string error_message;
+
+ private:
+  bool had_errors_;
+};
+
 // Create a Python DescriptorPool object, but does not fill the "pool"
 // attribute.
 static PyDescriptorPool* _CreateDescriptorPool() {
@@ -76,6 +108,7 @@ static PyDescriptorPool* _CreateDescriptorPool() {
     return NULL;
   }
 
+  cpool->error_collector = nullptr;
   cpool->underlay = NULL;
   cpool->database = NULL;
 
@@ -124,7 +157,8 @@ static PyDescriptorPool* PyDescriptorPool_NewWithDatabase(
     return NULL;
   }
   if (database != NULL) {
-    cpool->pool = new DescriptorPool(database);
+    cpool->error_collector = new BuildFileErrorCollector();
+    cpool->pool = new DescriptorPool(database, cpool->error_collector);
     cpool->database = database;
   } else {
     cpool->pool = new DescriptorPool();
@@ -167,6 +201,7 @@ static void Dealloc(PyObject* pself) {
   delete self->descriptor_options;
   delete self->database;
   delete self->pool;
+  delete self->error_collector;
   Py_TYPE(self)->tp_free(pself);
 }
 
@@ -182,6 +217,20 @@ static int GcClear(PyObject* pself) {
   return 0;
 }
 
+PyObject* SetErrorFromCollector(DescriptorPool::ErrorCollector* self,
+                                char* name, char* error_type) {
+  BuildFileErrorCollector* error_collector =
+      reinterpret_cast<BuildFileErrorCollector*>(self);
+  if (error_collector && !error_collector->error_message.empty()) {
+    PyErr_Format(PyExc_KeyError, "Couldn't build file for %s %.200s\n%s",
+                 error_type, name, error_collector->error_message.c_str());
+    error_collector->Clear();
+    return NULL;
+  }
+  PyErr_Format(PyExc_KeyError, "Couldn't find %s %.200s", error_type, name);
+  return NULL;
+}
+
 static PyObject* FindMessageByName(PyObject* self, PyObject* arg) {
   Py_ssize_t name_size;
   char* name;
@@ -194,8 +243,9 @@ static PyObject* FindMessageByName(PyObject* self, PyObject* arg) {
           string(name, name_size));
 
   if (message_descriptor == NULL) {
-    PyErr_Format(PyExc_KeyError, "Couldn't find message %.200s", name);
-    return NULL;
+    return SetErrorFromCollector(
+        reinterpret_cast<PyDescriptorPool*>(self)->error_collector, name,
+        "message");
   }
 
 
@@ -212,12 +262,12 @@ static PyObject* FindFileByName(PyObject* self, PyObject* arg) {
     return NULL;
   }
 
+  PyDescriptorPool* py_pool = reinterpret_cast<PyDescriptorPool*>(self);
   const FileDescriptor* file_descriptor =
-      reinterpret_cast<PyDescriptorPool*>(self)->pool->FindFileByName(
-          string(name, name_size));
+      py_pool->pool->FindFileByName(string(name, name_size));
+
   if (file_descriptor == NULL) {
-    PyErr_Format(PyExc_KeyError, "Couldn't find file %.200s", name);
-    return NULL;
+    return SetErrorFromCollector(py_pool->error_collector, name, "file");
   }
   return PyFileDescriptor_FromDescriptor(file_descriptor);
 }
@@ -232,9 +282,7 @@ PyObject* FindFieldByName(PyDescriptorPool* self, PyObject* arg) {
   const FieldDescriptor* field_descriptor =
       self->pool->FindFieldByName(string(name, name_size));
   if (field_descriptor == NULL) {
-    PyErr_Format(PyExc_KeyError, "Couldn't find field %.200s",
-                 name);
-    return NULL;
+    return SetErrorFromCollector(self->error_collector, name, "field");
   }
 
 
@@ -255,8 +303,8 @@ PyObject* FindExtensionByName(PyDescriptorPool* self, PyObject* arg) {
   const FieldDescriptor* field_descriptor =
       self->pool->FindExtensionByName(string(name, name_size));
   if (field_descriptor == NULL) {
-    PyErr_Format(PyExc_KeyError, "Couldn't find extension field %.200s", name);
-    return NULL;
+    return SetErrorFromCollector(self->error_collector, name,
+                                 "extension field");
   }
 
 
@@ -277,8 +325,7 @@ PyObject* FindEnumTypeByName(PyDescriptorPool* self, PyObject* arg) {
   const EnumDescriptor* enum_descriptor =
       self->pool->FindEnumTypeByName(string(name, name_size));
   if (enum_descriptor == NULL) {
-    PyErr_Format(PyExc_KeyError, "Couldn't find enum %.200s", name);
-    return NULL;
+    return SetErrorFromCollector(self->error_collector, name, "enum");
   }
 
 
@@ -299,8 +346,7 @@ PyObject* FindOneofByName(PyDescriptorPool* self, PyObject* arg) {
   const OneofDescriptor* oneof_descriptor =
       self->pool->FindOneofByName(string(name, name_size));
   if (oneof_descriptor == NULL) {
-    PyErr_Format(PyExc_KeyError, "Couldn't find oneof %.200s", name);
-    return NULL;
+    return SetErrorFromCollector(self->error_collector, name, "oneof");
   }
 
 
@@ -322,8 +368,9 @@ static PyObject* FindServiceByName(PyObject* self, PyObject* arg) {
       reinterpret_cast<PyDescriptorPool*>(self)->pool->FindServiceByName(
           string(name, name_size));
   if (service_descriptor == NULL) {
-    PyErr_Format(PyExc_KeyError, "Couldn't find service %.200s", name);
-    return NULL;
+    return SetErrorFromCollector(
+        reinterpret_cast<PyDescriptorPool*>(self)->error_collector, name,
+        "service");
   }
 
 
@@ -341,8 +388,9 @@ static PyObject* FindMethodByName(PyObject* self, PyObject* arg) {
       reinterpret_cast<PyDescriptorPool*>(self)->pool->FindMethodByName(
           string(name, name_size));
   if (method_descriptor == NULL) {
-    PyErr_Format(PyExc_KeyError, "Couldn't find method %.200s", name);
-    return NULL;
+    return SetErrorFromCollector(
+        reinterpret_cast<PyDescriptorPool*>(self)->error_collector, name,
+        "method");
   }
 
 
@@ -360,8 +408,9 @@ static PyObject* FindFileContainingSymbol(PyObject* self, PyObject* arg) {
       reinterpret_cast<PyDescriptorPool*>(self)->pool->FindFileContainingSymbol(
           string(name, name_size));
   if (file_descriptor == NULL) {
-    PyErr_Format(PyExc_KeyError, "Couldn't find symbol %.200s", name);
-    return NULL;
+    return SetErrorFromCollector(
+        reinterpret_cast<PyDescriptorPool*>(self)->error_collector, name,
+        "symbol");
   }
 
 
@@ -384,7 +433,16 @@ static PyObject* FindExtensionByNumber(PyObject* self, PyObject* args) {
       reinterpret_cast<PyDescriptorPool*>(self)->pool->FindExtensionByNumber(
           descriptor, number);
   if (extension_descriptor == NULL) {
-    PyErr_Format(PyExc_KeyError, "Couldn't find extension %d", number);
+    BuildFileErrorCollector* error_collector =
+        reinterpret_cast<BuildFileErrorCollector*>(
+            reinterpret_cast<PyDescriptorPool*>(self)->error_collector);
+    if (error_collector && !error_collector->error_message.empty()) {
+      PyErr_Format(PyExc_KeyError, "Couldn't build file for Extension %.d\n%s",
+                   number, error_collector->error_message.c_str());
+      error_collector->Clear();
+      return NULL;
+    }
+    PyErr_Format(PyExc_KeyError, "Couldn't find Extension %d", number);
     return NULL;
   }
 
@@ -511,32 +569,6 @@ static PyObject* AddServiceDescriptor(PyObject* self, PyObject* descriptor) {
 }
 
 // The code below loads new Descriptors from a serialized FileDescriptorProto.
-
-// Collects errors that occur during proto file building to allow them to be
-// propagated in the python exception instead of only living in ERROR logs.
-class BuildFileErrorCollector : public DescriptorPool::ErrorCollector {
- public:
-  BuildFileErrorCollector() : error_message(""), had_errors(false) {}
-
-  void AddError(const string& filename, const string& element_name,
-                const Message* descriptor, ErrorLocation location,
-                const string& message) {
-    // Replicates the logging behavior that happens in the C++ implementation
-    // when an error collector is not passed in.
-    if (!had_errors) {
-      error_message +=
-          ("Invalid proto descriptor for file \"" + filename + "\":\n");
-      had_errors = true;
-    }
-    // As this only happens on failure and will result in the program not
-    // running at all, no effort is made to optimize this string manipulation.
-    error_message += ("  " + element_name + ": " + message + "\n");
-  }
-
-  string error_message;
-  bool had_errors;
-};
-
 static PyObject* AddSerializedFile(PyObject* pself, PyObject* serialized_pb) {
   PyDescriptorPool* self = reinterpret_cast<PyDescriptorPool*>(pself);
   char* message_type;

+ 4 - 0
python/google/protobuf/pyext/descriptor_pool.h

@@ -59,6 +59,10 @@ typedef struct PyDescriptorPool {
   // The C++ pool containing Descriptors.
   DescriptorPool* pool;
 
+  // The error collector to store error info. Can be NULL. This pointer is
+  // owned.
+  DescriptorPool::ErrorCollector* error_collector;
+
   // The C++ pool acting as an underlay. Can be NULL.
   // This pointer is not owned and must stay alive.
   const DescriptorPool* underlay;

+ 1 - 0
python/setup.py

@@ -92,6 +92,7 @@ def GenerateUnittestProtos():
   generate_proto("../src/google/protobuf/unittest_mset_wire_format.proto", False)
   generate_proto("../src/google/protobuf/unittest_no_generic_services.proto", False)
   generate_proto("../src/google/protobuf/unittest_proto3_arena.proto", False)
+  generate_proto("../src/google/protobuf/util/json_format.proto", False)
   generate_proto("../src/google/protobuf/util/json_format_proto3.proto", False)
   generate_proto("google/protobuf/internal/any_test.proto", False)
   generate_proto("google/protobuf/internal/descriptor_pool_test1.proto", False)

+ 0 - 9
src/google/protobuf/any.pb.cc

@@ -115,11 +115,6 @@ class Any::_Internal {
  public:
 };
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const int Any::kTypeUrlFieldNumber;
-const int Any::kValueFieldNumber;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 Any::Any()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr), _any_metadata_(&type_url_, &value_) {
   SharedCtor();
@@ -419,10 +414,6 @@ bool Any::IsInitialized() const {
   return true;
 }
 
-void Any::Swap(Any* other) {
-  if (other == this) return;
-  InternalSwap(other);
-}
 void Any::InternalSwap(Any* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);

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

@@ -126,10 +126,13 @@ class PROTOBUF_EXPORT Any :
   }
   static bool ParseAnyTypeUrl(const string& type_url,
                               std::string* full_type_name);
-  void Swap(Any* other);
   friend void swap(Any& a, Any& b) {
     a.Swap(&b);
   }
+  inline void Swap(Any* other) {
+    if (other == this) return;
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 
@@ -191,9 +194,12 @@ class PROTOBUF_EXPORT Any :
 
   // accessors -------------------------------------------------------
 
+  enum : int {
+    kTypeUrlFieldNumber = 1,
+    kValueFieldNumber = 2,
+  };
   // string type_url = 1;
   void clear_type_url();
-  static const int kTypeUrlFieldNumber = 1;
   const std::string& type_url() const;
   void set_type_url(const std::string& value);
   void set_type_url(std::string&& value);
@@ -205,7 +211,6 @@ class PROTOBUF_EXPORT Any :
 
   // bytes value = 2;
   void clear_value();
-  static const int kValueFieldNumber = 2;
   const std::string& value() const;
   void set_value(const std::string& value);
   void set_value(std::string&& value);

+ 0 - 37
src/google/protobuf/api.pb.cc

@@ -196,16 +196,6 @@ void Api::clear_source_context() {
   }
   source_context_ = nullptr;
 }
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const int Api::kNameFieldNumber;
-const int Api::kMethodsFieldNumber;
-const int Api::kOptionsFieldNumber;
-const int Api::kVersionFieldNumber;
-const int Api::kSourceContextFieldNumber;
-const int Api::kMixinsFieldNumber;
-const int Api::kSyntaxFieldNumber;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 Api::Api()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr) {
   SharedCtor();
@@ -777,10 +767,6 @@ bool Api::IsInitialized() const {
   return true;
 }
 
-void Api::Swap(Api* other) {
-  if (other == this) return;
-  InternalSwap(other);
-}
 void Api::InternalSwap(Api* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);
@@ -811,16 +797,6 @@ class Method::_Internal {
 void Method::clear_options() {
   options_.Clear();
 }
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const int Method::kNameFieldNumber;
-const int Method::kRequestTypeUrlFieldNumber;
-const int Method::kRequestStreamingFieldNumber;
-const int Method::kResponseTypeUrlFieldNumber;
-const int Method::kResponseStreamingFieldNumber;
-const int Method::kOptionsFieldNumber;
-const int Method::kSyntaxFieldNumber;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 Method::Method()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr) {
   SharedCtor();
@@ -1374,10 +1350,6 @@ bool Method::IsInitialized() const {
   return true;
 }
 
-void Method::Swap(Method* other) {
-  if (other == this) return;
-  InternalSwap(other);
-}
 void Method::InternalSwap(Method* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);
@@ -1406,11 +1378,6 @@ class Mixin::_Internal {
  public:
 };
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const int Mixin::kNameFieldNumber;
-const int Mixin::kRootFieldNumber;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 Mixin::Mixin()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr) {
   SharedCtor();
@@ -1721,10 +1688,6 @@ bool Mixin::IsInitialized() const {
   return true;
 }
 
-void Mixin::Swap(Mixin* other) {
-  if (other == this) return;
-  InternalSwap(other);
-}
 void Mixin::InternalSwap(Mixin* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);

+ 34 - 19
src/google/protobuf/api.pb.h

@@ -120,10 +120,13 @@ class PROTOBUF_EXPORT Api :
   static constexpr int kIndexInFileMessages =
     0;
 
-  void Swap(Api* other);
   friend void swap(Api& a, Api& b) {
     a.Swap(&b);
   }
+  inline void Swap(Api* other) {
+    if (other == this) return;
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 
@@ -185,10 +188,18 @@ class PROTOBUF_EXPORT Api :
 
   // accessors -------------------------------------------------------
 
+  enum : int {
+    kMethodsFieldNumber = 2,
+    kOptionsFieldNumber = 3,
+    kMixinsFieldNumber = 6,
+    kNameFieldNumber = 1,
+    kVersionFieldNumber = 4,
+    kSourceContextFieldNumber = 5,
+    kSyntaxFieldNumber = 7,
+  };
   // repeated .google.protobuf.Method methods = 2;
   int methods_size() const;
   void clear_methods();
-  static const int kMethodsFieldNumber = 2;
   PROTOBUF_NAMESPACE_ID::Method* mutable_methods(int index);
   ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< PROTOBUF_NAMESPACE_ID::Method >*
       mutable_methods();
@@ -200,7 +211,6 @@ class PROTOBUF_EXPORT Api :
   // repeated .google.protobuf.Option options = 3;
   int options_size() const;
   void clear_options();
-  static const int kOptionsFieldNumber = 3;
   PROTOBUF_NAMESPACE_ID::Option* mutable_options(int index);
   ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< PROTOBUF_NAMESPACE_ID::Option >*
       mutable_options();
@@ -212,7 +222,6 @@ class PROTOBUF_EXPORT Api :
   // repeated .google.protobuf.Mixin mixins = 6;
   int mixins_size() const;
   void clear_mixins();
-  static const int kMixinsFieldNumber = 6;
   PROTOBUF_NAMESPACE_ID::Mixin* mutable_mixins(int index);
   ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< PROTOBUF_NAMESPACE_ID::Mixin >*
       mutable_mixins();
@@ -223,7 +232,6 @@ class PROTOBUF_EXPORT Api :
 
   // string name = 1;
   void clear_name();
-  static const int kNameFieldNumber = 1;
   const std::string& name() const;
   void set_name(const std::string& value);
   void set_name(std::string&& value);
@@ -235,7 +243,6 @@ class PROTOBUF_EXPORT Api :
 
   // string version = 4;
   void clear_version();
-  static const int kVersionFieldNumber = 4;
   const std::string& version() const;
   void set_version(const std::string& value);
   void set_version(std::string&& value);
@@ -248,7 +255,6 @@ class PROTOBUF_EXPORT Api :
   // .google.protobuf.SourceContext source_context = 5;
   bool has_source_context() const;
   void clear_source_context();
-  static const int kSourceContextFieldNumber = 5;
   const PROTOBUF_NAMESPACE_ID::SourceContext& source_context() const;
   PROTOBUF_NAMESPACE_ID::SourceContext* release_source_context();
   PROTOBUF_NAMESPACE_ID::SourceContext* mutable_source_context();
@@ -256,7 +262,6 @@ class PROTOBUF_EXPORT Api :
 
   // .google.protobuf.Syntax syntax = 7;
   void clear_syntax();
-  static const int kSyntaxFieldNumber = 7;
   PROTOBUF_NAMESPACE_ID::Syntax syntax() const;
   void set_syntax(PROTOBUF_NAMESPACE_ID::Syntax value);
 
@@ -321,10 +326,13 @@ class PROTOBUF_EXPORT Method :
   static constexpr int kIndexInFileMessages =
     1;
 
-  void Swap(Method* other);
   friend void swap(Method& a, Method& b) {
     a.Swap(&b);
   }
+  inline void Swap(Method* other) {
+    if (other == this) return;
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 
@@ -386,10 +394,18 @@ class PROTOBUF_EXPORT Method :
 
   // accessors -------------------------------------------------------
 
+  enum : int {
+    kOptionsFieldNumber = 6,
+    kNameFieldNumber = 1,
+    kRequestTypeUrlFieldNumber = 2,
+    kResponseTypeUrlFieldNumber = 4,
+    kRequestStreamingFieldNumber = 3,
+    kResponseStreamingFieldNumber = 5,
+    kSyntaxFieldNumber = 7,
+  };
   // repeated .google.protobuf.Option options = 6;
   int options_size() const;
   void clear_options();
-  static const int kOptionsFieldNumber = 6;
   PROTOBUF_NAMESPACE_ID::Option* mutable_options(int index);
   ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< PROTOBUF_NAMESPACE_ID::Option >*
       mutable_options();
@@ -400,7 +416,6 @@ class PROTOBUF_EXPORT Method :
 
   // string name = 1;
   void clear_name();
-  static const int kNameFieldNumber = 1;
   const std::string& name() const;
   void set_name(const std::string& value);
   void set_name(std::string&& value);
@@ -412,7 +427,6 @@ class PROTOBUF_EXPORT Method :
 
   // string request_type_url = 2;
   void clear_request_type_url();
-  static const int kRequestTypeUrlFieldNumber = 2;
   const std::string& request_type_url() const;
   void set_request_type_url(const std::string& value);
   void set_request_type_url(std::string&& value);
@@ -424,7 +438,6 @@ class PROTOBUF_EXPORT Method :
 
   // string response_type_url = 4;
   void clear_response_type_url();
-  static const int kResponseTypeUrlFieldNumber = 4;
   const std::string& response_type_url() const;
   void set_response_type_url(const std::string& value);
   void set_response_type_url(std::string&& value);
@@ -436,19 +449,16 @@ class PROTOBUF_EXPORT Method :
 
   // bool request_streaming = 3;
   void clear_request_streaming();
-  static const int kRequestStreamingFieldNumber = 3;
   bool request_streaming() const;
   void set_request_streaming(bool value);
 
   // bool response_streaming = 5;
   void clear_response_streaming();
-  static const int kResponseStreamingFieldNumber = 5;
   bool response_streaming() const;
   void set_response_streaming(bool value);
 
   // .google.protobuf.Syntax syntax = 7;
   void clear_syntax();
-  static const int kSyntaxFieldNumber = 7;
   PROTOBUF_NAMESPACE_ID::Syntax syntax() const;
   void set_syntax(PROTOBUF_NAMESPACE_ID::Syntax value);
 
@@ -513,10 +523,13 @@ class PROTOBUF_EXPORT Mixin :
   static constexpr int kIndexInFileMessages =
     2;
 
-  void Swap(Mixin* other);
   friend void swap(Mixin& a, Mixin& b) {
     a.Swap(&b);
   }
+  inline void Swap(Mixin* other) {
+    if (other == this) return;
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 
@@ -578,9 +591,12 @@ class PROTOBUF_EXPORT Mixin :
 
   // accessors -------------------------------------------------------
 
+  enum : int {
+    kNameFieldNumber = 1,
+    kRootFieldNumber = 2,
+  };
   // string name = 1;
   void clear_name();
-  static const int kNameFieldNumber = 1;
   const std::string& name() const;
   void set_name(const std::string& value);
   void set_name(std::string&& value);
@@ -592,7 +608,6 @@ class PROTOBUF_EXPORT Mixin :
 
   // string root = 2;
   void clear_root();
-  static const int kRootFieldNumber = 2;
   const std::string& root() const;
   void set_root(const std::string& value);
   void set_root(std::string&& value);

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

@@ -245,7 +245,7 @@ struct ArenaOptions {
 // well as protobuf container types like RepeatedPtrField and Map. The protocol
 // is internal to protobuf and is not guaranteed to be stable. Non-proto types
 // should not rely on this protocol.
-class PROTOBUF_EXPORT Arena final {
+class PROTOBUF_EXPORT alignas(8) Arena final {
  public:
   // Arena constructor taking custom options. See ArenaOptions below for
   // descriptions of the options available.

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

@@ -2023,6 +2023,10 @@ TEST_F(CommandLineInterfaceTest, GeneratorPluginNotFound) {
   // Error written to stdout by child process after exec() fails.
   ExpectErrorSubstring("no_such_file: program not found or is not executable");
 
+  ExpectErrorSubstring(
+      "Please specify a program using absolute path or make sure "
+      "the program is available in your PATH system variable");
+
   // Error written by parent process when child fails.
   ExpectErrorSubstring(
       "--badplug_out: prefix-gen-badplug: Plugin failed with status code 1.");

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

@@ -1489,9 +1489,9 @@ class ParseLoopGenerator {
       std::string enum_validator;
       if (field->type() == FieldDescriptor::TYPE_ENUM &&
           !HasPreservingUnknownEnumSemantics(field)) {
-        enum_validator = StrCat(
-            ", ", QualifiedClassName(field->enum_type(), options_),
-            "_IsValid, mutable_unknown_fields(), ", field->number());
+        enum_validator =
+            StrCat(", ", QualifiedClassName(field->enum_type(), options_),
+                         "_IsValid, &_internal_metadata_, ", field->number());
       }
       format_("ptr = $pi_ns$::Packed$1$Parser(mutable_$2$(), ptr, ctx$3$);\n",
               DeclaredTypeMethodName(field->type()), FieldName(field),

+ 39 - 52
src/google/protobuf/compiler/cpp/cpp_message.cc

@@ -714,6 +714,18 @@ void MessageGenerator::GenerateFieldAccessorDeclarations(io::Printer* printer) {
     ordered_fields.push_back(field);
   }
 
+  if (!ordered_fields.empty()) {
+    format("enum : int {\n");
+    for (auto field : ordered_fields) {
+      Formatter::SaveState save(&format);
+
+      std::map<std::string, std::string> vars;
+      SetCommonFieldVariables(field, &vars, options_);
+      format.AddMap(vars);
+      format("  ${1$$2$$}$ = $number$,\n", field, FieldConstantName(field));
+    }
+    format("};\n");
+  }
   for (auto field : ordered_fields) {
     PrintFieldComment(format, field);
 
@@ -735,10 +747,7 @@ void MessageGenerator::GenerateFieldAccessorDeclarations(io::Printer* printer) {
           field);
     }
 
-    format(
-        "$deprecated_attr$void ${1$clear_$name$$}$();\n"
-        "$deprecated_attr$static const int ${1$$2$$}$ = $number$;\n",
-        field, FieldConstantName(field));
+    format("$deprecated_attr$void ${1$clear_$name$$}$();\n", field);
 
     // Generate type-specific accessor declarations.
     field_generators_.get(field).GenerateAccessorDeclarations(printer);
@@ -1159,10 +1168,6 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) {
       "\n",
       index_in_file_messages_);
 
-  if (SupportsArenas(descriptor_)) {
-    format("void UnsafeArenaSwap($classname$* other);\n");
-  }
-
   if (IsAnyMessage(descriptor_, options_)) {
     format(
         "// implements Any -----------------------------------------------\n"
@@ -1205,10 +1210,34 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) {
              ShouldMarkNewAsFinal(descriptor_, options_) ? "final" : "");
 
   format(
-      "void Swap($classname$* other);\n"
       "friend void swap($classname$& a, $classname$& b) {\n"
       "  a.Swap(&b);\n"
-      "}\n"
+      "}\n");
+
+  if (SupportsArenas(descriptor_)) {
+    format(
+        "inline void Swap($classname$* other) {\n"
+        "  if (other == this) return;\n"
+        "  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {\n"
+        "    InternalSwap(other);\n"
+        "  } else {\n"
+        "    ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);\n"
+        "  }\n"
+        "}\n"
+        "void UnsafeArenaSwap($classname$* other) {\n"
+        "  if (other == this) return;\n"
+        "  $DCHK$(GetArenaNoVirtual() == other->GetArenaNoVirtual());\n"
+        "  InternalSwap(other);\n"
+        "}\n");
+  } else {
+    format(
+        "inline void Swap($classname$* other) {\n"
+        "  if (other == this) return;\n"
+        "  InternalSwap(other);\n"
+        "}\n");
+  }
+
+  format(
       "\n"
       "// implements Message ----------------------------------------------\n"
       "\n"
@@ -2031,15 +2060,6 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) {
     }
   }
 
-  // Generate field number constants.
-  format("#if !defined(_MSC_VER) || _MSC_VER >= 1900\n");
-  for (auto field : FieldRange(descriptor_)) {
-    format("const int $classname$::$1$;\n", FieldConstantName(field));
-  }
-  format(
-      "#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900\n"
-      "\n");
-
   GenerateStructors(printer);
   format("\n");
 
@@ -3003,40 +3023,7 @@ void MessageGenerator::GenerateOneofClear(io::Printer* printer) {
 
 void MessageGenerator::GenerateSwap(io::Printer* printer) {
   Formatter format(printer, variables_);
-  if (SupportsArenas(descriptor_)) {
-    // Generate the Swap member function. This is a lightweight wrapper around
-    // UnsafeArenaSwap() / MergeFrom() with temporaries, depending on the memory
-    // ownership situation: swapping across arenas or between an arena and a
-    // heap requires copying.
-    format(
-        "void $classname$::Swap($classname$* other) {\n"
-        "  if (other == this) return;\n"
-        "  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {\n"
-        "    InternalSwap(other);\n"
-        "  } else {\n"
-        "    $classname$* temp = New(GetArenaNoVirtual());\n"
-        "    temp->MergeFrom(*other);\n"
-        "    other->CopyFrom(*this);\n"
-        "    InternalSwap(temp);\n"
-        "    if (GetArenaNoVirtual() == nullptr) {\n"
-        "      delete temp;\n"
-        "    }\n"
-        "  }\n"
-        "}\n"
-        "void $classname$::UnsafeArenaSwap($classname$* other) {\n"
-        "  if (other == this) return;\n"
-        "  $DCHK$(GetArenaNoVirtual() == other->GetArenaNoVirtual());\n"
-        "  InternalSwap(other);\n"
-        "}\n");
-  } else {
-    format(
-        "void $classname$::Swap($classname$* other) {\n"
-        "  if (other == this) return;\n"
-        "  InternalSwap(other);\n"
-        "}\n");
-  }
 
-  // Generate the UnsafeArenaSwap member function.
   format("void $classname$::InternalSwap($classname$* other) {\n");
   format.Indent();
   format("using std::swap;\n");

+ 13 - 5
src/google/protobuf/compiler/js/js_generator.cc

@@ -1651,7 +1651,11 @@ bool IsWellKnownTypeFile(const FileDescriptor* file) {
 }  // anonymous namespace
 
 void Generator::GenerateHeader(const GeneratorOptions& options,
+                               const FileDescriptor* file,
                                io::Printer* printer) const {
+  if (file != nullptr) {
+    printer->Print("// source: $filename$\n", "filename", file->name());
+  }
   printer->Print(
       "/**\n"
       " * @fileoverview\n"
@@ -3637,7 +3641,7 @@ bool Generator::GenerateFile(const FileDescriptor* file,
 void Generator::GenerateFile(const GeneratorOptions& options,
                              io::Printer* printer,
                              const FileDescriptor* file) const {
-  GenerateHeader(options, printer);
+  GenerateHeader(options, file, printer);
 
   // Generate "require" statements.
   if ((options.import_style == GeneratorOptions::kImportCommonJs ||
@@ -3748,7 +3752,11 @@ bool Generator::GenerateAll(const std::vector<const FileDescriptor*>& files,
       }
     }
 
-    GenerateHeader(options, &printer);
+    if (files.size() == 1) {
+      GenerateHeader(options, files[0], &printer);
+    } else {
+      GenerateHeader(options, nullptr, &printer);
+    }
 
     std::set<std::string> provided;
     FindProvides(options, &printer, files, &provided);
@@ -3811,7 +3819,7 @@ bool Generator::GenerateAll(const std::vector<const FileDescriptor*>& files,
             output.get(), '$',
             options.annotate_code ? &annotation_collector : nullptr);
 
-        GenerateHeader(options, &printer);
+        GenerateHeader(options, file, &printer);
 
         std::set<std::string> provided;
         for (auto one_desc : scc->descriptors) {
@@ -3864,7 +3872,7 @@ bool Generator::GenerateAll(const std::vector<const FileDescriptor*>& files,
             output.get(), '$',
             options.annotate_code ? &annotation_collector : nullptr);
 
-        GenerateHeader(options, &printer);
+        GenerateHeader(options, file, &printer);
 
         std::set<std::string> provided;
         FindProvidesForEnum(options, &printer, enumdesc, &provided);
@@ -3896,7 +3904,7 @@ bool Generator::GenerateAll(const std::vector<const FileDescriptor*>& files,
             output.get(), '$',
             options.annotate_code ? &annotation_collector : nullptr);
 
-        GenerateHeader(options, &printer);
+        GenerateHeader(options, file, &printer);
 
         std::set<std::string> provided;
         std::vector<const FieldDescriptor*> fields;

+ 1 - 1
src/google/protobuf/compiler/js/js_generator.h

@@ -157,7 +157,7 @@ class PROTOC_EXPORT Generator : public CodeGenerator {
 
  private:
   void GenerateHeader(const GeneratorOptions& options,
-                      io::Printer* printer) const;
+                      const FileDescriptor* file, io::Printer* printer) const;
 
   // Generate goog.provides() calls.
   void FindProvides(const GeneratorOptions& options, io::Printer* printer,

+ 0 - 41
src/google/protobuf/compiler/plugin.pb.cc

@@ -225,13 +225,6 @@ class Version::_Internal {
   }
 };
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const int Version::kMajorFieldNumber;
-const int Version::kMinorFieldNumber;
-const int Version::kPatchFieldNumber;
-const int Version::kSuffixFieldNumber;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 Version::Version()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr) {
   SharedCtor();
@@ -631,10 +624,6 @@ bool Version::IsInitialized() const {
   return true;
 }
 
-void Version::Swap(Version* other) {
-  if (other == this) return;
-  InternalSwap(other);
-}
 void Version::InternalSwap(Version* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);
@@ -676,13 +665,6 @@ CodeGeneratorRequest::_Internal::compiler_version(const CodeGeneratorRequest* ms
 void CodeGeneratorRequest::clear_proto_file() {
   proto_file_.Clear();
 }
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const int CodeGeneratorRequest::kFileToGenerateFieldNumber;
-const int CodeGeneratorRequest::kParameterFieldNumber;
-const int CodeGeneratorRequest::kProtoFileFieldNumber;
-const int CodeGeneratorRequest::kCompilerVersionFieldNumber;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 CodeGeneratorRequest::CodeGeneratorRequest()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr) {
   SharedCtor();
@@ -1115,10 +1097,6 @@ bool CodeGeneratorRequest::IsInitialized() const {
   return true;
 }
 
-void CodeGeneratorRequest::Swap(CodeGeneratorRequest* other) {
-  if (other == this) return;
-  InternalSwap(other);
-}
 void CodeGeneratorRequest::InternalSwap(CodeGeneratorRequest* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);
@@ -1153,12 +1131,6 @@ class CodeGeneratorResponse_File::_Internal {
   }
 };
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const int CodeGeneratorResponse_File::kNameFieldNumber;
-const int CodeGeneratorResponse_File::kInsertionPointFieldNumber;
-const int CodeGeneratorResponse_File::kContentFieldNumber;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 CodeGeneratorResponse_File::CodeGeneratorResponse_File()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr) {
   SharedCtor();
@@ -1551,10 +1523,6 @@ bool CodeGeneratorResponse_File::IsInitialized() const {
   return true;
 }
 
-void CodeGeneratorResponse_File::Swap(CodeGeneratorResponse_File* other) {
-  if (other == this) return;
-  InternalSwap(other);
-}
 void CodeGeneratorResponse_File::InternalSwap(CodeGeneratorResponse_File* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);
@@ -1584,11 +1552,6 @@ class CodeGeneratorResponse::_Internal {
   }
 };
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const int CodeGeneratorResponse::kErrorFieldNumber;
-const int CodeGeneratorResponse::kFileFieldNumber;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 CodeGeneratorResponse::CodeGeneratorResponse()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr) {
   SharedCtor();
@@ -1902,10 +1865,6 @@ bool CodeGeneratorResponse::IsInitialized() const {
   return true;
 }
 
-void CodeGeneratorResponse::Swap(CodeGeneratorResponse* other) {
-  if (other == this) return;
-  InternalSwap(other);
-}
 void CodeGeneratorResponse::InternalSwap(CodeGeneratorResponse* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);

+ 37 - 17
src/google/protobuf/compiler/plugin.pb.h

@@ -139,10 +139,13 @@ class PROTOC_EXPORT Version :
   static constexpr int kIndexInFileMessages =
     0;
 
-  void Swap(Version* other);
   friend void swap(Version& a, Version& b) {
     a.Swap(&b);
   }
+  inline void Swap(Version* other) {
+    if (other == this) return;
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 
@@ -204,10 +207,15 @@ class PROTOC_EXPORT Version :
 
   // accessors -------------------------------------------------------
 
+  enum : int {
+    kSuffixFieldNumber = 4,
+    kMajorFieldNumber = 1,
+    kMinorFieldNumber = 2,
+    kPatchFieldNumber = 3,
+  };
   // optional string suffix = 4;
   bool has_suffix() const;
   void clear_suffix();
-  static const int kSuffixFieldNumber = 4;
   const std::string& suffix() const;
   void set_suffix(const std::string& value);
   void set_suffix(std::string&& value);
@@ -220,21 +228,18 @@ class PROTOC_EXPORT Version :
   // optional int32 major = 1;
   bool has_major() const;
   void clear_major();
-  static const int kMajorFieldNumber = 1;
   ::PROTOBUF_NAMESPACE_ID::int32 major() const;
   void set_major(::PROTOBUF_NAMESPACE_ID::int32 value);
 
   // optional int32 minor = 2;
   bool has_minor() const;
   void clear_minor();
-  static const int kMinorFieldNumber = 2;
   ::PROTOBUF_NAMESPACE_ID::int32 minor() const;
   void set_minor(::PROTOBUF_NAMESPACE_ID::int32 value);
 
   // optional int32 patch = 3;
   bool has_patch() const;
   void clear_patch();
-  static const int kPatchFieldNumber = 3;
   ::PROTOBUF_NAMESPACE_ID::int32 patch() const;
   void set_patch(::PROTOBUF_NAMESPACE_ID::int32 value);
 
@@ -304,10 +309,13 @@ class PROTOC_EXPORT CodeGeneratorRequest :
   static constexpr int kIndexInFileMessages =
     1;
 
-  void Swap(CodeGeneratorRequest* other);
   friend void swap(CodeGeneratorRequest& a, CodeGeneratorRequest& b) {
     a.Swap(&b);
   }
+  inline void Swap(CodeGeneratorRequest* other) {
+    if (other == this) return;
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 
@@ -369,10 +377,15 @@ class PROTOC_EXPORT CodeGeneratorRequest :
 
   // accessors -------------------------------------------------------
 
+  enum : int {
+    kFileToGenerateFieldNumber = 1,
+    kProtoFileFieldNumber = 15,
+    kParameterFieldNumber = 2,
+    kCompilerVersionFieldNumber = 3,
+  };
   // repeated string file_to_generate = 1;
   int file_to_generate_size() const;
   void clear_file_to_generate();
-  static const int kFileToGenerateFieldNumber = 1;
   const std::string& file_to_generate(int index) const;
   std::string* mutable_file_to_generate(int index);
   void set_file_to_generate(int index, const std::string& value);
@@ -390,7 +403,6 @@ class PROTOC_EXPORT CodeGeneratorRequest :
   // repeated .google.protobuf.FileDescriptorProto proto_file = 15;
   int proto_file_size() const;
   void clear_proto_file();
-  static const int kProtoFileFieldNumber = 15;
   PROTOBUF_NAMESPACE_ID::FileDescriptorProto* mutable_proto_file(int index);
   ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< PROTOBUF_NAMESPACE_ID::FileDescriptorProto >*
       mutable_proto_file();
@@ -402,7 +414,6 @@ class PROTOC_EXPORT CodeGeneratorRequest :
   // optional string parameter = 2;
   bool has_parameter() const;
   void clear_parameter();
-  static const int kParameterFieldNumber = 2;
   const std::string& parameter() const;
   void set_parameter(const std::string& value);
   void set_parameter(std::string&& value);
@@ -415,7 +426,6 @@ class PROTOC_EXPORT CodeGeneratorRequest :
   // optional .google.protobuf.compiler.Version compiler_version = 3;
   bool has_compiler_version() const;
   void clear_compiler_version();
-  static const int kCompilerVersionFieldNumber = 3;
   const PROTOBUF_NAMESPACE_ID::compiler::Version& compiler_version() const;
   PROTOBUF_NAMESPACE_ID::compiler::Version* release_compiler_version();
   PROTOBUF_NAMESPACE_ID::compiler::Version* mutable_compiler_version();
@@ -487,10 +497,13 @@ class PROTOC_EXPORT CodeGeneratorResponse_File :
   static constexpr int kIndexInFileMessages =
     2;
 
-  void Swap(CodeGeneratorResponse_File* other);
   friend void swap(CodeGeneratorResponse_File& a, CodeGeneratorResponse_File& b) {
     a.Swap(&b);
   }
+  inline void Swap(CodeGeneratorResponse_File* other) {
+    if (other == this) return;
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 
@@ -552,10 +565,14 @@ class PROTOC_EXPORT CodeGeneratorResponse_File :
 
   // accessors -------------------------------------------------------
 
+  enum : int {
+    kNameFieldNumber = 1,
+    kInsertionPointFieldNumber = 2,
+    kContentFieldNumber = 15,
+  };
   // optional string name = 1;
   bool has_name() const;
   void clear_name();
-  static const int kNameFieldNumber = 1;
   const std::string& name() const;
   void set_name(const std::string& value);
   void set_name(std::string&& value);
@@ -568,7 +585,6 @@ class PROTOC_EXPORT CodeGeneratorResponse_File :
   // optional string insertion_point = 2;
   bool has_insertion_point() const;
   void clear_insertion_point();
-  static const int kInsertionPointFieldNumber = 2;
   const std::string& insertion_point() const;
   void set_insertion_point(const std::string& value);
   void set_insertion_point(std::string&& value);
@@ -581,7 +597,6 @@ class PROTOC_EXPORT CodeGeneratorResponse_File :
   // optional string content = 15;
   bool has_content() const;
   void clear_content();
-  static const int kContentFieldNumber = 15;
   const std::string& content() const;
   void set_content(const std::string& value);
   void set_content(std::string&& value);
@@ -656,10 +671,13 @@ class PROTOC_EXPORT CodeGeneratorResponse :
   static constexpr int kIndexInFileMessages =
     3;
 
-  void Swap(CodeGeneratorResponse* other);
   friend void swap(CodeGeneratorResponse& a, CodeGeneratorResponse& b) {
     a.Swap(&b);
   }
+  inline void Swap(CodeGeneratorResponse* other) {
+    if (other == this) return;
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 
@@ -723,10 +741,13 @@ class PROTOC_EXPORT CodeGeneratorResponse :
 
   // accessors -------------------------------------------------------
 
+  enum : int {
+    kFileFieldNumber = 15,
+    kErrorFieldNumber = 1,
+  };
   // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
   int file_size() const;
   void clear_file();
-  static const int kFileFieldNumber = 15;
   PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File* mutable_file(int index);
   ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File >*
       mutable_file();
@@ -738,7 +759,6 @@ class PROTOC_EXPORT CodeGeneratorResponse :
   // optional string error = 1;
   bool has_error() const;
   void clear_error();
-  static const int kErrorFieldNumber = 1;
   const std::string& error() const;
   void set_error(const std::string& value);
   void set_error(std::string&& value);

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

@@ -338,7 +338,10 @@ void Subprocess::Start(const std::string& program, SearchMode search_mode) {
     // stuff that is unsafe here.
     int ignored;
     ignored = write(STDERR_FILENO, argv[0], strlen(argv[0]));
-    const char* message = ": program not found or is not executable\n";
+    const char* message =
+        ": program not found or is not executable\n"
+        "Please specify a program using absolute path or make sure "
+        "the program is available in your PATH system variable\n";
     ignored = write(STDERR_FILENO, message, strlen(message));
     (void)ignored;
 

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


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


+ 0 - 24
src/google/protobuf/duration.pb.cc

@@ -90,11 +90,6 @@ class Duration::_Internal {
  public:
 };
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const int Duration::kSecondsFieldNumber;
-const int Duration::kNanosFieldNumber;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 Duration::Duration()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr) {
   SharedCtor();
@@ -386,25 +381,6 @@ bool Duration::IsInitialized() const {
   return true;
 }
 
-void Duration::Swap(Duration* other) {
-  if (other == this) return;
-  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
-    InternalSwap(other);
-  } else {
-    Duration* temp = New(GetArenaNoVirtual());
-    temp->MergeFrom(*other);
-    other->CopyFrom(*this);
-    InternalSwap(temp);
-    if (GetArenaNoVirtual() == nullptr) {
-      delete temp;
-    }
-  }
-}
-void Duration::UnsafeArenaSwap(Duration* other) {
-  if (other == this) return;
-  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
-  InternalSwap(other);
-}
 void Duration::InternalSwap(Duration* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);

+ 17 - 4
src/google/protobuf/duration.pb.h

@@ -116,11 +116,22 @@ class PROTOBUF_EXPORT Duration :
   static constexpr int kIndexInFileMessages =
     0;
 
-  void UnsafeArenaSwap(Duration* other);
-  void Swap(Duration* other);
   friend void swap(Duration& a, Duration& b) {
     a.Swap(&b);
   }
+  inline void Swap(Duration* other) {
+    if (other == this) return;
+    if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Duration* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 
@@ -187,15 +198,17 @@ class PROTOBUF_EXPORT Duration :
 
   // accessors -------------------------------------------------------
 
+  enum : int {
+    kSecondsFieldNumber = 1,
+    kNanosFieldNumber = 2,
+  };
   // int64 seconds = 1;
   void clear_seconds();
-  static const int kSecondsFieldNumber = 1;
   ::PROTOBUF_NAMESPACE_ID::int64 seconds() const;
   void set_seconds(::PROTOBUF_NAMESPACE_ID::int64 value);
 
   // int32 nanos = 2;
   void clear_nanos();
-  static const int kNanosFieldNumber = 2;
   ::PROTOBUF_NAMESPACE_ID::int32 nanos() const;
   void set_nanos(::PROTOBUF_NAMESPACE_ID::int32 value);
 

+ 0 - 22
src/google/protobuf/empty.pb.cc

@@ -87,9 +87,6 @@ class Empty::_Internal {
  public:
 };
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 Empty::Empty()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr) {
   SharedCtor();
@@ -286,25 +283,6 @@ bool Empty::IsInitialized() const {
   return true;
 }
 
-void Empty::Swap(Empty* other) {
-  if (other == this) return;
-  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
-    InternalSwap(other);
-  } else {
-    Empty* temp = New(GetArenaNoVirtual());
-    temp->MergeFrom(*other);
-    other->CopyFrom(*this);
-    InternalSwap(temp);
-    if (GetArenaNoVirtual() == nullptr) {
-      delete temp;
-    }
-  }
-}
-void Empty::UnsafeArenaSwap(Empty* other) {
-  if (other == this) return;
-  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
-  InternalSwap(other);
-}
 void Empty::InternalSwap(Empty* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);

+ 13 - 2
src/google/protobuf/empty.pb.h

@@ -116,11 +116,22 @@ class PROTOBUF_EXPORT Empty :
   static constexpr int kIndexInFileMessages =
     0;
 
-  void UnsafeArenaSwap(Empty* other);
-  void Swap(Empty* other);
   friend void swap(Empty& a, Empty& b) {
     a.Swap(&b);
   }
+  inline void Swap(Empty* other) {
+    if (other == this) return;
+    if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Empty* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 

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

@@ -71,8 +71,7 @@ const char* ExtensionSet::ParseFieldWithExtensionInfo(
             MutableRawRepeatedField(number, extension.type, extension.is_packed,
                                     extension.descriptor),
             ptr, ctx, extension.enum_validity_check.func,
-            extension.enum_validity_check.arg,
-            metadata->mutable_unknown_fields(), number);
+            extension.enum_validity_check.arg, metadata, number);
       case WireFormatLite::TYPE_STRING:
       case WireFormatLite::TYPE_BYTES:
       case WireFormatLite::TYPE_GROUP:

+ 0 - 23
src/google/protobuf/field_mask.pb.cc

@@ -89,10 +89,6 @@ class FieldMask::_Internal {
  public:
 };
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const int FieldMask::kPathsFieldNumber;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 FieldMask::FieldMask()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr) {
   SharedCtor();
@@ -356,25 +352,6 @@ bool FieldMask::IsInitialized() const {
   return true;
 }
 
-void FieldMask::Swap(FieldMask* other) {
-  if (other == this) return;
-  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
-    InternalSwap(other);
-  } else {
-    FieldMask* temp = New(GetArenaNoVirtual());
-    temp->MergeFrom(*other);
-    other->CopyFrom(*this);
-    InternalSwap(temp);
-    if (GetArenaNoVirtual() == nullptr) {
-      delete temp;
-    }
-  }
-}
-void FieldMask::UnsafeArenaSwap(FieldMask* other) {
-  if (other == this) return;
-  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
-  InternalSwap(other);
-}
 void FieldMask::InternalSwap(FieldMask* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);

+ 16 - 3
src/google/protobuf/field_mask.pb.h

@@ -116,11 +116,22 @@ class PROTOBUF_EXPORT FieldMask :
   static constexpr int kIndexInFileMessages =
     0;
 
-  void UnsafeArenaSwap(FieldMask* other);
-  void Swap(FieldMask* other);
   friend void swap(FieldMask& a, FieldMask& b) {
     a.Swap(&b);
   }
+  inline void Swap(FieldMask* other) {
+    if (other == this) return;
+    if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(FieldMask* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 
@@ -187,10 +198,12 @@ class PROTOBUF_EXPORT FieldMask :
 
   // accessors -------------------------------------------------------
 
+  enum : int {
+    kPathsFieldNumber = 1,
+  };
   // repeated string paths = 1;
   int paths_size() const;
   void clear_paths();
-  static const int kPathsFieldNumber = 1;
   const std::string& paths(int index) const;
   std::string* mutable_paths(int index);
   void set_paths(int index, const std::string& value);

+ 9 - 0
src/google/protobuf/generated_message_util.cc

@@ -747,6 +747,15 @@ MessageLite* DuplicateIfNonNullInternal(MessageLite* message) {
   }
 }
 
+void GenericSwap(MessageLite* m1, MessageLite* m2) {
+  std::unique_ptr<MessageLite> tmp(m1->New());
+  tmp->CheckTypeAndMergeFrom(*m1);
+  m1->Clear();
+  m1->CheckTypeAndMergeFrom(*m2);
+  m2->Clear();
+  m2->CheckTypeAndMergeFrom(*tmp);
+}
+
 // Returns a message owned by this Arena.  This may require Own()ing or
 // duplicating the message.
 MessageLite* GetOwnedMessageInternal(Arena* message_arena,

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

@@ -145,6 +145,7 @@ PROTOBUF_EXPORT MessageLite* DuplicateIfNonNullInternal(MessageLite* message);
 PROTOBUF_EXPORT MessageLite* GetOwnedMessageInternal(Arena* message_arena,
                                                      MessageLite* submessage,
                                                      Arena* submessage_arena);
+PROTOBUF_EXPORT void GenericSwap(MessageLite* m1, MessageLite* m2);
 
 template <typename T>
 T* DuplicateIfNonNull(T* message) {

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

@@ -158,6 +158,11 @@ class ReflectionAccessor {
     return reflection->MutableRawRepeatedField(
         msg, field, FieldDescriptor::CPPTYPE_ENUM, 0, nullptr);
   }
+
+  static InternalMetadataWithArena* MutableInternalMetadataWithArena(
+      const Reflection* reflection, Message* msg) {
+    return reflection->MutableInternalMetadataWithArena(msg);
+  }
 };
 
 }  // namespace internal
@@ -263,7 +268,9 @@ const char* ParsePackedField(const FieldDescriptor* field, Message* msg,
       } else {
         return internal::PackedEnumParserArg(
             object, ptr, ctx, ReflectiveValidator, field->enum_type(),
-            reflection->MutableUnknownFields(msg), field->number());
+            internal::ReflectionAccessor::MutableInternalMetadataWithArena(
+                reflection, msg),
+            field->number());
       }
     }
       HANDLE_PACKED_TYPE(FIXED32, uint32, Fixed32);

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

@@ -982,7 +982,7 @@ class PROTOBUF_EXPORT Reflection final {
   inline const internal::InternalMetadataWithArena&
   GetInternalMetadataWithArena(const Message& message) const;
 
-  inline internal::InternalMetadataWithArena* MutableInternalMetadataWithArena(
+  internal::InternalMetadataWithArena* MutableInternalMetadataWithArena(
       Message* message) const;
 
   inline bool IsInlined(const FieldDescriptor* field) const;

+ 8 - 6
src/google/protobuf/parse_context.cc

@@ -421,14 +421,15 @@ const char* PackedEnumParser(void* object, const char* ptr, ParseContext* ctx) {
 }
 
 const char* PackedEnumParser(void* object, const char* ptr, ParseContext* ctx,
-                             bool (*is_valid)(int), std::string* unknown,
+                             bool (*is_valid)(int),
+                             InternalMetadataWithArenaLite* metadata,
                              int field_num) {
   return ctx->ReadPackedVarint(
-      ptr, [object, is_valid, unknown, field_num](uint64 val) {
+      ptr, [object, is_valid, metadata, field_num](uint64 val) {
         if (is_valid(val)) {
           static_cast<RepeatedField<int>*>(object)->Add(val);
         } else {
-          WriteVarint(field_num, val, unknown);
+          WriteVarint(field_num, val, metadata->mutable_unknown_fields());
         }
       });
 }
@@ -436,14 +437,15 @@ const char* PackedEnumParser(void* object, const char* ptr, ParseContext* ctx,
 const char* PackedEnumParserArg(void* object, const char* ptr,
                                 ParseContext* ctx,
                                 bool (*is_valid)(const void*, int),
-                                const void* data, std::string* unknown,
+                                const void* data,
+                                InternalMetadataWithArenaLite* metadata,
                                 int field_num) {
   return ctx->ReadPackedVarint(
-      ptr, [object, is_valid, data, unknown, field_num](uint64 val) {
+      ptr, [object, is_valid, data, metadata, field_num](uint64 val) {
         if (is_valid(data, val)) {
           static_cast<RepeatedField<int>*>(object)->Add(val);
         } else {
-          WriteVarint(field_num, val, unknown);
+          WriteVarint(field_num, val, metadata->mutable_unknown_fields());
         }
       });
 }

+ 3 - 3
src/google/protobuf/parse_context.h

@@ -718,11 +718,11 @@ PROTOBUF_EXPORT PROTOBUF_MUST_USE_RESULT const char* PackedEnumParser(
     void* object, const char* ptr, ParseContext* ctx);
 PROTOBUF_EXPORT PROTOBUF_MUST_USE_RESULT const char* PackedEnumParser(
     void* object, const char* ptr, ParseContext* ctx, bool (*is_valid)(int),
-    std::string* unknown, int field_num);
+    InternalMetadataWithArenaLite* metadata, int field_num);
 PROTOBUF_EXPORT PROTOBUF_MUST_USE_RESULT const char* PackedEnumParserArg(
     void* object, const char* ptr, ParseContext* ctx,
-    bool (*is_valid)(const void*, int), const void* data, std::string* unknown,
-    int field_num);
+    bool (*is_valid)(const void*, int), const void* data,
+    InternalMetadataWithArenaLite* metadata, int field_num);
 
 PROTOBUF_EXPORT PROTOBUF_MUST_USE_RESULT const char* PackedBoolParser(
     void* object, const char* ptr, ParseContext* ctx);

+ 43 - 41
src/google/protobuf/repeated_field.h

@@ -118,6 +118,10 @@ inline int CalculateReserve(Iter begin, Iter end) {
 // set-by-index, and add accessors that are generated for all repeated fields.
 template <typename Element>
 class RepeatedField final {
+  static_assert(
+      alignof(Arena) >= alignof(Element),
+      "We only support types that have an alignment smaller than Arena");
+
  public:
   RepeatedField();
   explicit RepeatedField(Arena* arena);
@@ -289,23 +293,30 @@ class RepeatedField final {
   // Element is double and pointer is 32bit).
   static const size_t kRepHeaderSize;
 
-  // We reuse the Rep* for an Arena* when total_size == 0, to avoid having to do
-  // an allocation in the constructor when we have an Arena.
-  union Pointer {
-    Pointer(Arena* a) : arena(a) {}
-    Arena* arena;       // When total_size_ == 0.
-    Element* elements;  // When total_size_ != 0, this is Rep->elements of Rep.
-  } ptr_;
+  // If total_size_ == 0 this points to an Arena otherwise it points to the
+  // elements member of a Rep struct. Using this invariant allows the storage of
+  // the arena pointer without an extra allocation in the constructor.
+  void* arena_or_elements_;
 
+  // Return pointer to elements array.
+  // pre-condition: the array must have been allocated.
   Element* elements() const {
     GOOGLE_DCHECK_GT(total_size_, 0);
-    return ptr_.elements;
+    // Because of above pre-condition this cast is safe.
+    return unsafe_elements();
+  }
+
+  // Return pointer to elements array if it exists otherwise either null or
+  // a invalid pointer is returned. This only happens for empty repeated fields,
+  // where you can't dereference this pointer anyway (it's empty).
+  Element* unsafe_elements() const {
+    return static_cast<Element*>(arena_or_elements_);
   }
 
+  // Return pointer to the Rep struct.
+  // pre-condition: the Rep must have been allocated, ie elements() is safe.
   Rep* rep() const {
-    GOOGLE_DCHECK_GT(total_size_, 0);
-    char* addr =
-        reinterpret_cast<char*>(ptr_.elements) - offsetof(Rep, elements);
+    char* addr = reinterpret_cast<char*>(elements()) - offsetof(Rep, elements);
     return reinterpret_cast<Rep*>(addr);
   }
 
@@ -323,7 +334,8 @@ class RepeatedField final {
 
   // Internal helper expected by Arena methods.
   inline Arena* GetArenaNoVirtual() const {
-    return (total_size_ == 0) ? ptr_.arena : rep()->arena;
+    return (total_size_ == 0) ? static_cast<Arena*>(arena_or_elements_)
+                              : rep()->arena;
   }
 
   // Internal helper to delete all elements and deallocate the storage.
@@ -346,9 +358,6 @@ class RepeatedField final {
       }
     }
   }
-
-  friend class internal::WireFormatLite;
-  const Element* unsafe_data() const;
 };
 
 template <typename Element>
@@ -1057,15 +1066,15 @@ class RepeatedPtrField final : private internal::RepeatedPtrFieldBase {
 
 template <typename Element>
 inline RepeatedField<Element>::RepeatedField()
-    : current_size_(0), total_size_(0), ptr_(NULL) {}
+    : current_size_(0), total_size_(0), arena_or_elements_(nullptr) {}
 
 template <typename Element>
 inline RepeatedField<Element>::RepeatedField(Arena* arena)
-    : current_size_(0), total_size_(0), ptr_(arena) {}
+    : current_size_(0), total_size_(0), arena_or_elements_(arena) {}
 
 template <typename Element>
 inline RepeatedField<Element>::RepeatedField(const RepeatedField& other)
-    : current_size_(0), total_size_(0), ptr_(NULL) {
+    : current_size_(0), total_size_(0), arena_or_elements_(nullptr) {
   if (other.current_size_ != 0) {
     Reserve(other.size());
     AddNAlreadyReserved(other.size());
@@ -1076,7 +1085,7 @@ inline RepeatedField<Element>::RepeatedField(const RepeatedField& other)
 template <typename Element>
 template <typename Iter>
 RepeatedField<Element>::RepeatedField(Iter begin, const Iter& end)
-    : current_size_(0), total_size_(0), ptr_(NULL) {
+    : current_size_(0), total_size_(0), arena_or_elements_(nullptr) {
   Add(begin, end);
 }
 
@@ -1153,13 +1162,11 @@ template <typename Element>
 inline Element* RepeatedField<Element>::AddNAlreadyReserved(int n) {
   GOOGLE_DCHECK_GE(total_size_ - current_size_, n)
       << total_size_ << ", " << current_size_;
-  // Warning: sometimes people call this when n==0 and total_size_==0.  This
-  // forces us to add this branch, to avoid reading the non-active union member
-  // (which is UB).  Luckily the compiler is smart enough to optimize the branch
-  // away.
-  Element* ret =
-      total_size_ == 0 ? reinterpret_cast<Element*>(ptr_.arena) : ptr_.elements;
-  ret += current_size_;
+  // Warning: sometimes people call this when n == 0 and total_size_ == 0. In
+  // this case the return pointer points to a zero size array (n == 0). Hence
+  // we can just use unsafe_elements(), because the user cannot dereference the
+  // pointer anyway.
+  Element* ret = unsafe_elements() + current_size_;
   current_size_ += n;
   return ret;
 }
@@ -1313,17 +1320,12 @@ inline typename RepeatedField<Element>::iterator RepeatedField<Element>::erase(
 
 template <typename Element>
 inline Element* RepeatedField<Element>::mutable_data() {
-  return total_size_ > 0 ? elements() : NULL;
+  return unsafe_elements();
 }
 
 template <typename Element>
 inline const Element* RepeatedField<Element>::data() const {
-  return total_size_ > 0 ? elements() : NULL;
-}
-
-template <typename Element>
-inline const Element* RepeatedField<Element>::unsafe_data() const {
-  return elements();
+  return unsafe_elements();
 }
 
 template <typename Element>
@@ -1331,7 +1333,7 @@ inline void RepeatedField<Element>::InternalSwap(RepeatedField* other) {
   GOOGLE_DCHECK(this != other);
   GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
 
-  std::swap(ptr_, other->ptr_);
+  std::swap(arena_or_elements_, other->arena_or_elements_);
   std::swap(current_size_, other->current_size_);
   std::swap(total_size_, other->total_size_);
 }
@@ -1364,31 +1366,31 @@ void RepeatedField<Element>::SwapElements(int index1, int index2) {
 template <typename Element>
 inline typename RepeatedField<Element>::iterator
 RepeatedField<Element>::begin() {
-  return total_size_ > 0 ? elements() : NULL;
+  return unsafe_elements();
 }
 template <typename Element>
 inline typename RepeatedField<Element>::const_iterator
 RepeatedField<Element>::begin() const {
-  return total_size_ > 0 ? elements() : NULL;
+  return unsafe_elements();
 }
 template <typename Element>
 inline typename RepeatedField<Element>::const_iterator
 RepeatedField<Element>::cbegin() const {
-  return total_size_ > 0 ? elements() : NULL;
+  return unsafe_elements();
 }
 template <typename Element>
 inline typename RepeatedField<Element>::iterator RepeatedField<Element>::end() {
-  return total_size_ > 0 ? elements() + current_size_ : NULL;
+  return unsafe_elements() + current_size_;
 }
 template <typename Element>
 inline typename RepeatedField<Element>::const_iterator
 RepeatedField<Element>::end() const {
-  return total_size_ > 0 ? elements() + current_size_ : NULL;
+  return unsafe_elements() + current_size_;
 }
 template <typename Element>
 inline typename RepeatedField<Element>::const_iterator
 RepeatedField<Element>::cend() const {
-  return total_size_ > 0 ? elements() + current_size_ : NULL;
+  return unsafe_elements() + current_size_;
 }
 
 template <typename Element>
@@ -1420,7 +1422,7 @@ void RepeatedField<Element>::Reserve(int new_size) {
   new_rep->arena = arena;
   int old_total_size = total_size_;
   total_size_ = new_size;
-  ptr_.elements = new_rep->elements;
+  arena_or_elements_ = new_rep->elements;
   // Invoke placement-new on newly allocated elements. We shouldn't have to do
   // this, since Element is supposed to be POD, but a previous version of this
   // code allocated storage with "new Element[size]" and some code uses

+ 0 - 8
src/google/protobuf/source_context.pb.cc

@@ -90,10 +90,6 @@ class SourceContext::_Internal {
  public:
 };
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const int SourceContext::kFileNameFieldNumber;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 SourceContext::SourceContext()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr) {
   SharedCtor();
@@ -343,10 +339,6 @@ bool SourceContext::IsInitialized() const {
   return true;
 }
 
-void SourceContext::Swap(SourceContext* other) {
-  if (other == this) return;
-  InternalSwap(other);
-}
 void SourceContext::InternalSwap(SourceContext* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);

+ 7 - 2
src/google/protobuf/source_context.pb.h

@@ -110,10 +110,13 @@ class PROTOBUF_EXPORT SourceContext :
   static constexpr int kIndexInFileMessages =
     0;
 
-  void Swap(SourceContext* other);
   friend void swap(SourceContext& a, SourceContext& b) {
     a.Swap(&b);
   }
+  inline void Swap(SourceContext* other) {
+    if (other == this) return;
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 
@@ -175,9 +178,11 @@ class PROTOBUF_EXPORT SourceContext :
 
   // accessors -------------------------------------------------------
 
+  enum : int {
+    kFileNameFieldNumber = 1,
+  };
   // string file_name = 1;
   void clear_file_name();
-  static const int kFileNameFieldNumber = 1;
   const std::string& file_name() const;
   void set_file_name(const std::string& value);
   void set_file_name(std::string&& value);

+ 0 - 74
src/google/protobuf/struct.pb.cc

@@ -199,10 +199,6 @@ class Struct::_Internal {
  public:
 };
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const int Struct::kFieldsFieldNumber;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 Struct::Struct()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr) {
   SharedCtor();
@@ -535,25 +531,6 @@ bool Struct::IsInitialized() const {
   return true;
 }
 
-void Struct::Swap(Struct* other) {
-  if (other == this) return;
-  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
-    InternalSwap(other);
-  } else {
-    Struct* temp = New(GetArenaNoVirtual());
-    temp->MergeFrom(*other);
-    other->CopyFrom(*this);
-    InternalSwap(temp);
-    if (GetArenaNoVirtual() == nullptr) {
-      delete temp;
-    }
-  }
-}
-void Struct::UnsafeArenaSwap(Struct* other) {
-  if (other == this) return;
-  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
-  InternalSwap(other);
-}
 void Struct::InternalSwap(Struct* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);
@@ -622,15 +599,6 @@ void Value::set_allocated_list_value(PROTOBUF_NAMESPACE_ID::ListValue* list_valu
   }
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.Value.list_value)
 }
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const int Value::kNullValueFieldNumber;
-const int Value::kNumberValueFieldNumber;
-const int Value::kStringValueFieldNumber;
-const int Value::kBoolValueFieldNumber;
-const int Value::kStructValueFieldNumber;
-const int Value::kListValueFieldNumber;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 Value::Value()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr) {
   SharedCtor();
@@ -1181,25 +1149,6 @@ bool Value::IsInitialized() const {
   return true;
 }
 
-void Value::Swap(Value* other) {
-  if (other == this) return;
-  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
-    InternalSwap(other);
-  } else {
-    Value* temp = New(GetArenaNoVirtual());
-    temp->MergeFrom(*other);
-    other->CopyFrom(*this);
-    InternalSwap(temp);
-    if (GetArenaNoVirtual() == nullptr) {
-      delete temp;
-    }
-  }
-}
-void Value::UnsafeArenaSwap(Value* other) {
-  if (other == this) return;
-  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
-  InternalSwap(other);
-}
 void Value::InternalSwap(Value* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);
@@ -1220,10 +1169,6 @@ class ListValue::_Internal {
  public:
 };
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const int ListValue::kValuesFieldNumber;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 ListValue::ListValue()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr) {
   SharedCtor();
@@ -1482,25 +1427,6 @@ bool ListValue::IsInitialized() const {
   return true;
 }
 
-void ListValue::Swap(ListValue* other) {
-  if (other == this) return;
-  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
-    InternalSwap(other);
-  } else {
-    ListValue* temp = New(GetArenaNoVirtual());
-    temp->MergeFrom(*other);
-    other->CopyFrom(*this);
-    InternalSwap(temp);
-    if (GetArenaNoVirtual() == nullptr) {
-      delete temp;
-    }
-  }
-}
-void ListValue::UnsafeArenaSwap(ListValue* other) {
-  if (other == this) return;
-  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
-  InternalSwap(other);
-}
 void ListValue::InternalSwap(ListValue* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);

+ 53 - 14
src/google/protobuf/struct.pb.h

@@ -188,11 +188,22 @@ class PROTOBUF_EXPORT Struct :
   static constexpr int kIndexInFileMessages =
     1;
 
-  void UnsafeArenaSwap(Struct* other);
-  void Swap(Struct* other);
   friend void swap(Struct& a, Struct& b) {
     a.Swap(&b);
   }
+  inline void Swap(Struct* other) {
+    if (other == this) return;
+    if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Struct* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 
@@ -260,10 +271,12 @@ class PROTOBUF_EXPORT Struct :
 
   // accessors -------------------------------------------------------
 
+  enum : int {
+    kFieldsFieldNumber = 1,
+  };
   // map<string, .google.protobuf.Value> fields = 1;
   int fields_size() const;
   void clear_fields();
-  static const int kFieldsFieldNumber = 1;
   const ::PROTOBUF_NAMESPACE_ID::Map< std::string, PROTOBUF_NAMESPACE_ID::Value >&
       fields() const;
   ::PROTOBUF_NAMESPACE_ID::Map< std::string, PROTOBUF_NAMESPACE_ID::Value >*
@@ -348,11 +361,22 @@ class PROTOBUF_EXPORT Value :
   static constexpr int kIndexInFileMessages =
     2;
 
-  void UnsafeArenaSwap(Value* other);
-  void Swap(Value* other);
   friend void swap(Value& a, Value& b) {
     a.Swap(&b);
   }
+  inline void Swap(Value* other) {
+    if (other == this) return;
+    if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Value* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 
@@ -419,12 +443,19 @@ class PROTOBUF_EXPORT Value :
 
   // accessors -------------------------------------------------------
 
+  enum : int {
+    kNullValueFieldNumber = 1,
+    kNumberValueFieldNumber = 2,
+    kStringValueFieldNumber = 3,
+    kBoolValueFieldNumber = 4,
+    kStructValueFieldNumber = 5,
+    kListValueFieldNumber = 6,
+  };
   // .google.protobuf.NullValue null_value = 1;
   private:
   bool has_null_value() const;
   public:
   void clear_null_value();
-  static const int kNullValueFieldNumber = 1;
   PROTOBUF_NAMESPACE_ID::NullValue null_value() const;
   void set_null_value(PROTOBUF_NAMESPACE_ID::NullValue value);
 
@@ -433,7 +464,6 @@ class PROTOBUF_EXPORT Value :
   bool has_number_value() const;
   public:
   void clear_number_value();
-  static const int kNumberValueFieldNumber = 2;
   double number_value() const;
   void set_number_value(double value);
 
@@ -442,7 +472,6 @@ class PROTOBUF_EXPORT Value :
   bool has_string_value() const;
   public:
   void clear_string_value();
-  static const int kStringValueFieldNumber = 3;
   const std::string& string_value() const;
   void set_string_value(const std::string& value);
   void set_string_value(std::string&& value);
@@ -466,14 +495,12 @@ class PROTOBUF_EXPORT Value :
   bool has_bool_value() const;
   public:
   void clear_bool_value();
-  static const int kBoolValueFieldNumber = 4;
   bool bool_value() const;
   void set_bool_value(bool value);
 
   // .google.protobuf.Struct struct_value = 5;
   bool has_struct_value() const;
   void clear_struct_value();
-  static const int kStructValueFieldNumber = 5;
   const PROTOBUF_NAMESPACE_ID::Struct& struct_value() const;
   PROTOBUF_NAMESPACE_ID::Struct* release_struct_value();
   PROTOBUF_NAMESPACE_ID::Struct* mutable_struct_value();
@@ -485,7 +512,6 @@ class PROTOBUF_EXPORT Value :
   // .google.protobuf.ListValue list_value = 6;
   bool has_list_value() const;
   void clear_list_value();
-  static const int kListValueFieldNumber = 6;
   const PROTOBUF_NAMESPACE_ID::ListValue& list_value() const;
   PROTOBUF_NAMESPACE_ID::ListValue* release_list_value();
   PROTOBUF_NAMESPACE_ID::ListValue* mutable_list_value();
@@ -579,11 +605,22 @@ class PROTOBUF_EXPORT ListValue :
   static constexpr int kIndexInFileMessages =
     3;
 
-  void UnsafeArenaSwap(ListValue* other);
-  void Swap(ListValue* other);
   friend void swap(ListValue& a, ListValue& b) {
     a.Swap(&b);
   }
+  inline void Swap(ListValue* other) {
+    if (other == this) return;
+    if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(ListValue* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 
@@ -650,10 +687,12 @@ class PROTOBUF_EXPORT ListValue :
 
   // accessors -------------------------------------------------------
 
+  enum : int {
+    kValuesFieldNumber = 1,
+  };
   // repeated .google.protobuf.Value values = 1;
   int values_size() const;
   void clear_values();
-  static const int kValuesFieldNumber = 1;
   PROTOBUF_NAMESPACE_ID::Value* mutable_values(int index);
   ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< PROTOBUF_NAMESPACE_ID::Value >*
       mutable_values();

+ 1 - 2
src/google/protobuf/stubs/mathutil.h

@@ -126,8 +126,7 @@ bool MathUtil::WithinFractionOrMargin(const T x, const T y,
   if (MathLimits<T>::kIsInteger) {
     return x == y;
   } else {
-    // IsFinite checks are to make kPosInf and kNegInf not within fraction
-    if (!MathLimits<T>::IsFinite(x) && !MathLimits<T>::IsFinite(y)) {
+    if (!MathLimits<T>::IsFinite(x) || !MathLimits<T>::IsFinite(y)) {
       return false;
     }
     T relative_margin = static_cast<T>(fraction * Max(Abs(x), Abs(y)));

+ 0 - 24
src/google/protobuf/timestamp.pb.cc

@@ -90,11 +90,6 @@ class Timestamp::_Internal {
  public:
 };
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const int Timestamp::kSecondsFieldNumber;
-const int Timestamp::kNanosFieldNumber;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 Timestamp::Timestamp()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr) {
   SharedCtor();
@@ -386,25 +381,6 @@ bool Timestamp::IsInitialized() const {
   return true;
 }
 
-void Timestamp::Swap(Timestamp* other) {
-  if (other == this) return;
-  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
-    InternalSwap(other);
-  } else {
-    Timestamp* temp = New(GetArenaNoVirtual());
-    temp->MergeFrom(*other);
-    other->CopyFrom(*this);
-    InternalSwap(temp);
-    if (GetArenaNoVirtual() == nullptr) {
-      delete temp;
-    }
-  }
-}
-void Timestamp::UnsafeArenaSwap(Timestamp* other) {
-  if (other == this) return;
-  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
-  InternalSwap(other);
-}
 void Timestamp::InternalSwap(Timestamp* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);

+ 17 - 4
src/google/protobuf/timestamp.pb.h

@@ -116,11 +116,22 @@ class PROTOBUF_EXPORT Timestamp :
   static constexpr int kIndexInFileMessages =
     0;
 
-  void UnsafeArenaSwap(Timestamp* other);
-  void Swap(Timestamp* other);
   friend void swap(Timestamp& a, Timestamp& b) {
     a.Swap(&b);
   }
+  inline void Swap(Timestamp* other) {
+    if (other == this) return;
+    if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Timestamp* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 
@@ -187,15 +198,17 @@ class PROTOBUF_EXPORT Timestamp :
 
   // accessors -------------------------------------------------------
 
+  enum : int {
+    kSecondsFieldNumber = 1,
+    kNanosFieldNumber = 2,
+  };
   // int64 seconds = 1;
   void clear_seconds();
-  static const int kSecondsFieldNumber = 1;
   ::PROTOBUF_NAMESPACE_ID::int64 seconds() const;
   void set_seconds(::PROTOBUF_NAMESPACE_ID::int64 value);
 
   // int32 nanos = 2;
   void clear_nanos();
-  static const int kNanosFieldNumber = 2;
   ::PROTOBUF_NAMESPACE_ID::int32 nanos() const;
   void set_nanos(::PROTOBUF_NAMESPACE_ID::int32 value);
 

+ 0 - 136
src/google/protobuf/type.pb.cc

@@ -388,15 +388,6 @@ void Type::clear_source_context() {
   }
   source_context_ = nullptr;
 }
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const int Type::kNameFieldNumber;
-const int Type::kFieldsFieldNumber;
-const int Type::kOneofsFieldNumber;
-const int Type::kOptionsFieldNumber;
-const int Type::kSourceContextFieldNumber;
-const int Type::kSyntaxFieldNumber;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 Type::Type()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr) {
   SharedCtor();
@@ -930,25 +921,6 @@ bool Type::IsInitialized() const {
   return true;
 }
 
-void Type::Swap(Type* other) {
-  if (other == this) return;
-  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
-    InternalSwap(other);
-  } else {
-    Type* temp = New(GetArenaNoVirtual());
-    temp->MergeFrom(*other);
-    other->CopyFrom(*this);
-    InternalSwap(temp);
-    if (GetArenaNoVirtual() == nullptr) {
-      delete temp;
-    }
-  }
-}
-void Type::UnsafeArenaSwap(Type* other) {
-  if (other == this) return;
-  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
-  InternalSwap(other);
-}
 void Type::InternalSwap(Type* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);
@@ -974,19 +946,6 @@ class Field::_Internal {
  public:
 };
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const int Field::kKindFieldNumber;
-const int Field::kCardinalityFieldNumber;
-const int Field::kNumberFieldNumber;
-const int Field::kNameFieldNumber;
-const int Field::kTypeUrlFieldNumber;
-const int Field::kOneofIndexFieldNumber;
-const int Field::kPackedFieldNumber;
-const int Field::kOptionsFieldNumber;
-const int Field::kJsonNameFieldNumber;
-const int Field::kDefaultValueFieldNumber;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 Field::Field()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr) {
   SharedCtor();
@@ -1702,25 +1661,6 @@ bool Field::IsInitialized() const {
   return true;
 }
 
-void Field::Swap(Field* other) {
-  if (other == this) return;
-  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
-    InternalSwap(other);
-  } else {
-    Field* temp = New(GetArenaNoVirtual());
-    temp->MergeFrom(*other);
-    other->CopyFrom(*this);
-    InternalSwap(temp);
-    if (GetArenaNoVirtual() == nullptr) {
-      delete temp;
-    }
-  }
-}
-void Field::UnsafeArenaSwap(Field* other) {
-  if (other == this) return;
-  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
-  InternalSwap(other);
-}
 void Field::InternalSwap(Field* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);
@@ -1779,14 +1719,6 @@ void Enum::clear_source_context() {
   }
   source_context_ = nullptr;
 }
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const int Enum::kNameFieldNumber;
-const int Enum::kEnumvalueFieldNumber;
-const int Enum::kOptionsFieldNumber;
-const int Enum::kSourceContextFieldNumber;
-const int Enum::kSyntaxFieldNumber;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 Enum::Enum()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr) {
   SharedCtor();
@@ -2260,25 +2192,6 @@ bool Enum::IsInitialized() const {
   return true;
 }
 
-void Enum::Swap(Enum* other) {
-  if (other == this) return;
-  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
-    InternalSwap(other);
-  } else {
-    Enum* temp = New(GetArenaNoVirtual());
-    temp->MergeFrom(*other);
-    other->CopyFrom(*this);
-    InternalSwap(temp);
-    if (GetArenaNoVirtual() == nullptr) {
-      delete temp;
-    }
-  }
-}
-void Enum::UnsafeArenaSwap(Enum* other) {
-  if (other == this) return;
-  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
-  InternalSwap(other);
-}
 void Enum::InternalSwap(Enum* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);
@@ -2303,12 +2216,6 @@ class EnumValue::_Internal {
  public:
 };
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const int EnumValue::kNameFieldNumber;
-const int EnumValue::kNumberFieldNumber;
-const int EnumValue::kOptionsFieldNumber;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 EnumValue::EnumValue()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr) {
   SharedCtor();
@@ -2671,25 +2578,6 @@ bool EnumValue::IsInitialized() const {
   return true;
 }
 
-void EnumValue::Swap(EnumValue* other) {
-  if (other == this) return;
-  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
-    InternalSwap(other);
-  } else {
-    EnumValue* temp = New(GetArenaNoVirtual());
-    temp->MergeFrom(*other);
-    other->CopyFrom(*this);
-    InternalSwap(temp);
-    if (GetArenaNoVirtual() == nullptr) {
-      delete temp;
-    }
-  }
-}
-void EnumValue::UnsafeArenaSwap(EnumValue* other) {
-  if (other == this) return;
-  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
-  InternalSwap(other);
-}
 void EnumValue::InternalSwap(EnumValue* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);
@@ -2738,11 +2626,6 @@ void Option::clear_value() {
   }
   value_ = nullptr;
 }
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const int Option::kNameFieldNumber;
-const int Option::kValueFieldNumber;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 Option::Option()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr) {
   SharedCtor();
@@ -3059,25 +2942,6 @@ bool Option::IsInitialized() const {
   return true;
 }
 
-void Option::Swap(Option* other) {
-  if (other == this) return;
-  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
-    InternalSwap(other);
-  } else {
-    Option* temp = New(GetArenaNoVirtual());
-    temp->MergeFrom(*other);
-    other->CopyFrom(*this);
-    InternalSwap(temp);
-    if (GetArenaNoVirtual() == nullptr) {
-      delete temp;
-    }
-  }
-}
-void Option::UnsafeArenaSwap(Option* other) {
-  if (other == this) return;
-  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
-  InternalSwap(other);
-}
 void Option::InternalSwap(Option* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);

+ 101 - 36
src/google/protobuf/type.pb.h

@@ -229,11 +229,22 @@ class PROTOBUF_EXPORT Type :
   static constexpr int kIndexInFileMessages =
     0;
 
-  void UnsafeArenaSwap(Type* other);
-  void Swap(Type* other);
   friend void swap(Type& a, Type& b) {
     a.Swap(&b);
   }
+  inline void Swap(Type* other) {
+    if (other == this) return;
+    if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Type* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 
@@ -300,10 +311,17 @@ class PROTOBUF_EXPORT Type :
 
   // accessors -------------------------------------------------------
 
+  enum : int {
+    kFieldsFieldNumber = 2,
+    kOneofsFieldNumber = 3,
+    kOptionsFieldNumber = 4,
+    kNameFieldNumber = 1,
+    kSourceContextFieldNumber = 5,
+    kSyntaxFieldNumber = 6,
+  };
   // repeated .google.protobuf.Field fields = 2;
   int fields_size() const;
   void clear_fields();
-  static const int kFieldsFieldNumber = 2;
   PROTOBUF_NAMESPACE_ID::Field* mutable_fields(int index);
   ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< PROTOBUF_NAMESPACE_ID::Field >*
       mutable_fields();
@@ -315,7 +333,6 @@ class PROTOBUF_EXPORT Type :
   // repeated string oneofs = 3;
   int oneofs_size() const;
   void clear_oneofs();
-  static const int kOneofsFieldNumber = 3;
   const std::string& oneofs(int index) const;
   std::string* mutable_oneofs(int index);
   void set_oneofs(int index, const std::string& value);
@@ -333,7 +350,6 @@ class PROTOBUF_EXPORT Type :
   // repeated .google.protobuf.Option options = 4;
   int options_size() const;
   void clear_options();
-  static const int kOptionsFieldNumber = 4;
   PROTOBUF_NAMESPACE_ID::Option* mutable_options(int index);
   ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< PROTOBUF_NAMESPACE_ID::Option >*
       mutable_options();
@@ -344,7 +360,6 @@ class PROTOBUF_EXPORT Type :
 
   // string name = 1;
   void clear_name();
-  static const int kNameFieldNumber = 1;
   const std::string& name() const;
   void set_name(const std::string& value);
   void set_name(std::string&& value);
@@ -366,7 +381,6 @@ class PROTOBUF_EXPORT Type :
   // .google.protobuf.SourceContext source_context = 5;
   bool has_source_context() const;
   void clear_source_context();
-  static const int kSourceContextFieldNumber = 5;
   const PROTOBUF_NAMESPACE_ID::SourceContext& source_context() const;
   PROTOBUF_NAMESPACE_ID::SourceContext* release_source_context();
   PROTOBUF_NAMESPACE_ID::SourceContext* mutable_source_context();
@@ -377,7 +391,6 @@ class PROTOBUF_EXPORT Type :
 
   // .google.protobuf.Syntax syntax = 6;
   void clear_syntax();
-  static const int kSyntaxFieldNumber = 6;
   PROTOBUF_NAMESPACE_ID::Syntax syntax() const;
   void set_syntax(PROTOBUF_NAMESPACE_ID::Syntax value);
 
@@ -450,11 +463,22 @@ class PROTOBUF_EXPORT Field :
   static constexpr int kIndexInFileMessages =
     1;
 
-  void UnsafeArenaSwap(Field* other);
-  void Swap(Field* other);
   friend void swap(Field& a, Field& b) {
     a.Swap(&b);
   }
+  inline void Swap(Field* other) {
+    if (other == this) return;
+    if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Field* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 
@@ -619,10 +643,21 @@ class PROTOBUF_EXPORT Field :
 
   // accessors -------------------------------------------------------
 
+  enum : int {
+    kOptionsFieldNumber = 9,
+    kNameFieldNumber = 4,
+    kTypeUrlFieldNumber = 6,
+    kJsonNameFieldNumber = 10,
+    kDefaultValueFieldNumber = 11,
+    kKindFieldNumber = 1,
+    kCardinalityFieldNumber = 2,
+    kNumberFieldNumber = 3,
+    kOneofIndexFieldNumber = 7,
+    kPackedFieldNumber = 8,
+  };
   // repeated .google.protobuf.Option options = 9;
   int options_size() const;
   void clear_options();
-  static const int kOptionsFieldNumber = 9;
   PROTOBUF_NAMESPACE_ID::Option* mutable_options(int index);
   ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< PROTOBUF_NAMESPACE_ID::Option >*
       mutable_options();
@@ -633,7 +668,6 @@ class PROTOBUF_EXPORT Field :
 
   // string name = 4;
   void clear_name();
-  static const int kNameFieldNumber = 4;
   const std::string& name() const;
   void set_name(const std::string& value);
   void set_name(std::string&& value);
@@ -654,7 +688,6 @@ class PROTOBUF_EXPORT Field :
 
   // string type_url = 6;
   void clear_type_url();
-  static const int kTypeUrlFieldNumber = 6;
   const std::string& type_url() const;
   void set_type_url(const std::string& value);
   void set_type_url(std::string&& value);
@@ -675,7 +708,6 @@ class PROTOBUF_EXPORT Field :
 
   // string json_name = 10;
   void clear_json_name();
-  static const int kJsonNameFieldNumber = 10;
   const std::string& json_name() const;
   void set_json_name(const std::string& value);
   void set_json_name(std::string&& value);
@@ -696,7 +728,6 @@ class PROTOBUF_EXPORT Field :
 
   // string default_value = 11;
   void clear_default_value();
-  static const int kDefaultValueFieldNumber = 11;
   const std::string& default_value() const;
   void set_default_value(const std::string& value);
   void set_default_value(std::string&& value);
@@ -717,31 +748,26 @@ class PROTOBUF_EXPORT Field :
 
   // .google.protobuf.Field.Kind kind = 1;
   void clear_kind();
-  static const int kKindFieldNumber = 1;
   PROTOBUF_NAMESPACE_ID::Field_Kind kind() const;
   void set_kind(PROTOBUF_NAMESPACE_ID::Field_Kind value);
 
   // .google.protobuf.Field.Cardinality cardinality = 2;
   void clear_cardinality();
-  static const int kCardinalityFieldNumber = 2;
   PROTOBUF_NAMESPACE_ID::Field_Cardinality cardinality() const;
   void set_cardinality(PROTOBUF_NAMESPACE_ID::Field_Cardinality value);
 
   // int32 number = 3;
   void clear_number();
-  static const int kNumberFieldNumber = 3;
   ::PROTOBUF_NAMESPACE_ID::int32 number() const;
   void set_number(::PROTOBUF_NAMESPACE_ID::int32 value);
 
   // int32 oneof_index = 7;
   void clear_oneof_index();
-  static const int kOneofIndexFieldNumber = 7;
   ::PROTOBUF_NAMESPACE_ID::int32 oneof_index() const;
   void set_oneof_index(::PROTOBUF_NAMESPACE_ID::int32 value);
 
   // bool packed = 8;
   void clear_packed();
-  static const int kPackedFieldNumber = 8;
   bool packed() const;
   void set_packed(bool value);
 
@@ -818,11 +844,22 @@ class PROTOBUF_EXPORT Enum :
   static constexpr int kIndexInFileMessages =
     2;
 
-  void UnsafeArenaSwap(Enum* other);
-  void Swap(Enum* other);
   friend void swap(Enum& a, Enum& b) {
     a.Swap(&b);
   }
+  inline void Swap(Enum* other) {
+    if (other == this) return;
+    if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Enum* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 
@@ -889,10 +926,16 @@ class PROTOBUF_EXPORT Enum :
 
   // accessors -------------------------------------------------------
 
+  enum : int {
+    kEnumvalueFieldNumber = 2,
+    kOptionsFieldNumber = 3,
+    kNameFieldNumber = 1,
+    kSourceContextFieldNumber = 4,
+    kSyntaxFieldNumber = 5,
+  };
   // repeated .google.protobuf.EnumValue enumvalue = 2;
   int enumvalue_size() const;
   void clear_enumvalue();
-  static const int kEnumvalueFieldNumber = 2;
   PROTOBUF_NAMESPACE_ID::EnumValue* mutable_enumvalue(int index);
   ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< PROTOBUF_NAMESPACE_ID::EnumValue >*
       mutable_enumvalue();
@@ -904,7 +947,6 @@ class PROTOBUF_EXPORT Enum :
   // repeated .google.protobuf.Option options = 3;
   int options_size() const;
   void clear_options();
-  static const int kOptionsFieldNumber = 3;
   PROTOBUF_NAMESPACE_ID::Option* mutable_options(int index);
   ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< PROTOBUF_NAMESPACE_ID::Option >*
       mutable_options();
@@ -915,7 +957,6 @@ class PROTOBUF_EXPORT Enum :
 
   // string name = 1;
   void clear_name();
-  static const int kNameFieldNumber = 1;
   const std::string& name() const;
   void set_name(const std::string& value);
   void set_name(std::string&& value);
@@ -937,7 +978,6 @@ class PROTOBUF_EXPORT Enum :
   // .google.protobuf.SourceContext source_context = 4;
   bool has_source_context() const;
   void clear_source_context();
-  static const int kSourceContextFieldNumber = 4;
   const PROTOBUF_NAMESPACE_ID::SourceContext& source_context() const;
   PROTOBUF_NAMESPACE_ID::SourceContext* release_source_context();
   PROTOBUF_NAMESPACE_ID::SourceContext* mutable_source_context();
@@ -948,7 +988,6 @@ class PROTOBUF_EXPORT Enum :
 
   // .google.protobuf.Syntax syntax = 5;
   void clear_syntax();
-  static const int kSyntaxFieldNumber = 5;
   PROTOBUF_NAMESPACE_ID::Syntax syntax() const;
   void set_syntax(PROTOBUF_NAMESPACE_ID::Syntax value);
 
@@ -1020,11 +1059,22 @@ class PROTOBUF_EXPORT EnumValue :
   static constexpr int kIndexInFileMessages =
     3;
 
-  void UnsafeArenaSwap(EnumValue* other);
-  void Swap(EnumValue* other);
   friend void swap(EnumValue& a, EnumValue& b) {
     a.Swap(&b);
   }
+  inline void Swap(EnumValue* other) {
+    if (other == this) return;
+    if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(EnumValue* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 
@@ -1091,10 +1141,14 @@ class PROTOBUF_EXPORT EnumValue :
 
   // accessors -------------------------------------------------------
 
+  enum : int {
+    kOptionsFieldNumber = 3,
+    kNameFieldNumber = 1,
+    kNumberFieldNumber = 2,
+  };
   // repeated .google.protobuf.Option options = 3;
   int options_size() const;
   void clear_options();
-  static const int kOptionsFieldNumber = 3;
   PROTOBUF_NAMESPACE_ID::Option* mutable_options(int index);
   ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< PROTOBUF_NAMESPACE_ID::Option >*
       mutable_options();
@@ -1105,7 +1159,6 @@ class PROTOBUF_EXPORT EnumValue :
 
   // string name = 1;
   void clear_name();
-  static const int kNameFieldNumber = 1;
   const std::string& name() const;
   void set_name(const std::string& value);
   void set_name(std::string&& value);
@@ -1126,7 +1179,6 @@ class PROTOBUF_EXPORT EnumValue :
 
   // int32 number = 2;
   void clear_number();
-  static const int kNumberFieldNumber = 2;
   ::PROTOBUF_NAMESPACE_ID::int32 number() const;
   void set_number(::PROTOBUF_NAMESPACE_ID::int32 value);
 
@@ -1196,11 +1248,22 @@ class PROTOBUF_EXPORT Option :
   static constexpr int kIndexInFileMessages =
     4;
 
-  void UnsafeArenaSwap(Option* other);
-  void Swap(Option* other);
   friend void swap(Option& a, Option& b) {
     a.Swap(&b);
   }
+  inline void Swap(Option* other) {
+    if (other == this) return;
+    if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Option* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 
@@ -1267,9 +1330,12 @@ class PROTOBUF_EXPORT Option :
 
   // accessors -------------------------------------------------------
 
+  enum : int {
+    kNameFieldNumber = 1,
+    kValueFieldNumber = 2,
+  };
   // string name = 1;
   void clear_name();
-  static const int kNameFieldNumber = 1;
   const std::string& name() const;
   void set_name(const std::string& value);
   void set_name(std::string&& value);
@@ -1291,7 +1357,6 @@ class PROTOBUF_EXPORT Option :
   // .google.protobuf.Any value = 2;
   bool has_value() const;
   void clear_value();
-  static const int kValueFieldNumber = 2;
   const PROTOBUF_NAMESPACE_ID::Any& value() const;
   PROTOBUF_NAMESPACE_ID::Any* release_value();
   PROTOBUF_NAMESPACE_ID::Any* mutable_value();

+ 8 - 6
src/google/protobuf/unknown_field_set.cc

@@ -287,28 +287,30 @@ uint8* UnknownField::SerializeLengthDelimitedNoTagToArray(uint8* target) const {
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 namespace internal {
 const char* PackedEnumParser(void* object, const char* ptr, ParseContext* ctx,
-                             bool (*is_valid)(int), UnknownFieldSet* unknown,
+                             bool (*is_valid)(int),
+                             InternalMetadataWithArena* metadata,
                              int field_num) {
   return ctx->ReadPackedVarint(
-      ptr, [object, is_valid, unknown, field_num](uint64 val) {
+      ptr, [object, is_valid, metadata, field_num](uint64 val) {
         if (is_valid(val)) {
           static_cast<RepeatedField<int>*>(object)->Add(val);
         } else {
-          WriteVarint(field_num, val, unknown);
+          WriteVarint(field_num, val, metadata->mutable_unknown_fields());
         }
       });
 }
 const char* PackedEnumParserArg(void* object, const char* ptr,
                                 ParseContext* ctx,
                                 bool (*is_valid)(const void*, int),
-                                const void* data, UnknownFieldSet* unknown,
+                                const void* data,
+                                InternalMetadataWithArena* metadata,
                                 int field_num) {
   return ctx->ReadPackedVarint(
-      ptr, [object, is_valid, data, unknown, field_num](uint64 val) {
+      ptr, [object, is_valid, data, metadata, field_num](uint64 val) {
         if (is_valid(data, val)) {
           static_cast<RepeatedField<int>*>(object)->Add(val);
         } else {
-          WriteVarint(field_num, val, unknown);
+          WriteVarint(field_num, val, metadata->mutable_unknown_fields());
         }
       });
 }

+ 4 - 3
src/google/protobuf/unknown_field_set.h

@@ -196,13 +196,14 @@ inline void WriteLengthDelimited(uint32 num, StringPiece val,
 
 PROTOBUF_EXPORT
 const char* PackedEnumParser(void* object, const char* ptr, ParseContext* ctx,
-                             bool (*is_valid)(int), UnknownFieldSet* unknown,
-                             int field_num);
+                             bool (*is_valid)(int),
+                             InternalMetadataWithArena* unknown, int field_num);
 PROTOBUF_EXPORT
 const char* PackedEnumParserArg(void* object, const char* ptr,
                                 ParseContext* ctx,
                                 bool (*is_valid)(const void*, int),
-                                const void* data, UnknownFieldSet* unknown,
+                                const void* data,
+                                InternalMetadataWithArena* unknown,
                                 int field_num);
 
 PROTOBUF_EXPORT

+ 14 - 0
src/google/protobuf/util/field_comparator_test.cc

@@ -388,6 +388,20 @@ TEST_F(DefaultFieldComparatorTest,
   EXPECT_EQ(
       FieldComparator::SAME,
       comparator_.Compare(message_1_, message_2_, field_double, -1, -1, NULL));
+
+  // Finite values and inf should not be equal, even for a positive fraction.
+  message_1_.set_optional_float(std::numeric_limits<float>::infinity());
+  message_2_.set_optional_float(0.0f);
+  message_1_.set_optional_double(std::numeric_limits<double>::infinity());
+  message_2_.set_optional_double(0.0);
+  comparator_.SetFractionAndMargin(field_float, 0.1, 0.0);
+  comparator_.SetFractionAndMargin(field_double, 0.1, 0.0);
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
 }
 
 TEST_F(DefaultFieldComparatorTest,

+ 11 - 0
src/google/protobuf/util/json_format.proto

@@ -117,3 +117,14 @@ message TestStringSerializer {
   repeated string repeated_string = 2;
   map<string, string> string_map = 3;
 }
+
+message TestMessageWithExtension {
+  extensions 100 to max;
+}
+
+message TestExtension {
+  extend TestMessageWithExtension {
+    optional TestExtension ext = 100;
+  }
+  optional string value = 1;
+}

+ 9 - 3
src/google/protobuf/util/message_differencer.cc

@@ -1640,7 +1640,8 @@ bool MessageDifferencer::MatchRepeatedFieldIndices(
 
       for (int j = start_offset; j < count2; j++) {
         if (match_list2->at(j) != -1) {
-          if (!is_treated_as_smart_set || num_diffs_list1[i] == 0) {
+          if (!is_treated_as_smart_set || num_diffs_list1[i] == 0 ||
+              num_diffs_list1[match_list2->at(j)] == 0) {
             continue;
           }
         }
@@ -1662,8 +1663,13 @@ bool MessageDifferencer::MatchRepeatedFieldIndices(
             // Replace with the one with fewer diffs.
             const int32 num_diffs = num_diffs_reporter.GetNumDiffs();
             if (num_diffs < num_diffs_list1[i]) {
-              num_diffs_list1[i] = num_diffs;
-              match = true;
+              // If j has been already matched to some element, ensure the
+              // current num_diffs is smaller.
+              if (match_list2->at(j) == -1 ||
+                  num_diffs < num_diffs_list1[match_list2->at(j)]) {
+                num_diffs_list1[i] = num_diffs;
+                match = true;
+              }
             }
           }
         }

+ 59 - 0
src/google/protobuf/util/message_differencer_unittest.cc

@@ -1158,6 +1158,65 @@ TEST(MessageDifferencerTest, RepeatedFieldSmartSetTest) {
       diff_report);
 }
 
+TEST(MessageDifferencerTest, RepeatedFieldSmartSetTest_IdenticalElements) {
+  // Create the testing protos
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+  protobuf_unittest::TestField elem;
+
+  elem.set_a(1);
+  elem.set_b(1);
+  elem.set_c(1);
+
+  *msg1.add_rm() = elem;
+  *msg1.add_rm() = elem;
+  *msg2.add_rm() = elem;
+  *msg2.add_rm() = elem;
+
+  util::MessageDifferencer differencer;
+  differencer.set_repeated_field_comparison(
+      util::MessageDifferencer::AS_SMART_SET);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+}
+
+TEST(MessageDifferencerTest, RepeatedFieldSmartSetTest_PreviouslyMatch) {
+  // Create the testing protos
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+  protobuf_unittest::TestField elem1_1, elem1_2;
+  protobuf_unittest::TestField elem2_1, elem2_2;
+
+  elem1_1.set_a(1);
+  elem1_1.set_b(1);
+  elem1_1.set_c(1);
+  elem1_2.set_a(1);
+  elem1_2.set_b(1);
+  elem1_2.set_c(0);
+
+  elem2_1.set_a(1);
+  elem2_1.set_b(1);
+  elem2_1.set_c(1);
+  elem2_2.set_a(1);
+  elem2_2.set_b(0);
+  elem2_2.set_c(1);
+
+  *msg1.add_rm() = elem1_1;
+  *msg1.add_rm() = elem2_1;
+  *msg2.add_rm() = elem1_2;
+  *msg2.add_rm() = elem2_2;
+
+  string diff_report;
+  util::MessageDifferencer differencer;
+  differencer.ReportDifferencesToString(&diff_report);
+  differencer.set_repeated_field_comparison(
+      util::MessageDifferencer::AS_SMART_SET);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+  EXPECT_EQ(
+      "modified: rm[0].c: 1 -> 0\n"
+      "modified: rm[1].b: 1 -> 0\n",
+      diff_report);
+}
+
 TEST(MessageDifferencerTest, RepeatedFieldSmartSet_MultipleMatches) {
   // Create the testing protos
   protobuf_unittest::TestDiffMessage msg1;

+ 3 - 3
src/google/protobuf/wire_format_lite.h

@@ -1427,7 +1427,7 @@ inline uint8* WireFormatLite::WritePrimitiveNoTagToArray(
   const int n = value.size();
   GOOGLE_DCHECK_GT(n, 0);
 
-  const T* ii = value.unsafe_data();
+  const T* ii = value.data();
   int i = 0;
   do {
     target = Writer(ii[i], target);
@@ -1445,7 +1445,7 @@ inline uint8* WireFormatLite::WriteFixedNoTagToArray(
   const int n = value.size();
   GOOGLE_DCHECK_GT(n, 0);
 
-  const T* ii = value.unsafe_data();
+  const T* ii = value.data();
   const int bytes = n * static_cast<int>(sizeof(ii[0]));
   memcpy(target, ii, static_cast<size_t>(bytes));
   return target + bytes;
@@ -1591,7 +1591,7 @@ inline uint8* WireFormatLite::WritePrimitiveToArray(
     return target;
   }
 
-  const T* ii = value.unsafe_data();
+  const T* ii = value.data();
   int i = 0;
   do {
     target = Writer(field_number, ii[i], target);

+ 0 - 207
src/google/protobuf/wrappers.pb.cc

@@ -311,10 +311,6 @@ class DoubleValue::_Internal {
  public:
 };
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const int DoubleValue::kValueFieldNumber;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 DoubleValue::DoubleValue()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr) {
   SharedCtor();
@@ -558,25 +554,6 @@ bool DoubleValue::IsInitialized() const {
   return true;
 }
 
-void DoubleValue::Swap(DoubleValue* other) {
-  if (other == this) return;
-  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
-    InternalSwap(other);
-  } else {
-    DoubleValue* temp = New(GetArenaNoVirtual());
-    temp->MergeFrom(*other);
-    other->CopyFrom(*this);
-    InternalSwap(temp);
-    if (GetArenaNoVirtual() == nullptr) {
-      delete temp;
-    }
-  }
-}
-void DoubleValue::UnsafeArenaSwap(DoubleValue* other) {
-  if (other == this) return;
-  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
-  InternalSwap(other);
-}
 void DoubleValue::InternalSwap(DoubleValue* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);
@@ -596,10 +573,6 @@ class FloatValue::_Internal {
  public:
 };
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const int FloatValue::kValueFieldNumber;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 FloatValue::FloatValue()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr) {
   SharedCtor();
@@ -843,25 +816,6 @@ bool FloatValue::IsInitialized() const {
   return true;
 }
 
-void FloatValue::Swap(FloatValue* other) {
-  if (other == this) return;
-  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
-    InternalSwap(other);
-  } else {
-    FloatValue* temp = New(GetArenaNoVirtual());
-    temp->MergeFrom(*other);
-    other->CopyFrom(*this);
-    InternalSwap(temp);
-    if (GetArenaNoVirtual() == nullptr) {
-      delete temp;
-    }
-  }
-}
-void FloatValue::UnsafeArenaSwap(FloatValue* other) {
-  if (other == this) return;
-  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
-  InternalSwap(other);
-}
 void FloatValue::InternalSwap(FloatValue* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);
@@ -881,10 +835,6 @@ class Int64Value::_Internal {
  public:
 };
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const int Int64Value::kValueFieldNumber;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 Int64Value::Int64Value()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr) {
   SharedCtor();
@@ -1130,25 +1080,6 @@ bool Int64Value::IsInitialized() const {
   return true;
 }
 
-void Int64Value::Swap(Int64Value* other) {
-  if (other == this) return;
-  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
-    InternalSwap(other);
-  } else {
-    Int64Value* temp = New(GetArenaNoVirtual());
-    temp->MergeFrom(*other);
-    other->CopyFrom(*this);
-    InternalSwap(temp);
-    if (GetArenaNoVirtual() == nullptr) {
-      delete temp;
-    }
-  }
-}
-void Int64Value::UnsafeArenaSwap(Int64Value* other) {
-  if (other == this) return;
-  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
-  InternalSwap(other);
-}
 void Int64Value::InternalSwap(Int64Value* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);
@@ -1168,10 +1099,6 @@ class UInt64Value::_Internal {
  public:
 };
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const int UInt64Value::kValueFieldNumber;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 UInt64Value::UInt64Value()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr) {
   SharedCtor();
@@ -1417,25 +1344,6 @@ bool UInt64Value::IsInitialized() const {
   return true;
 }
 
-void UInt64Value::Swap(UInt64Value* other) {
-  if (other == this) return;
-  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
-    InternalSwap(other);
-  } else {
-    UInt64Value* temp = New(GetArenaNoVirtual());
-    temp->MergeFrom(*other);
-    other->CopyFrom(*this);
-    InternalSwap(temp);
-    if (GetArenaNoVirtual() == nullptr) {
-      delete temp;
-    }
-  }
-}
-void UInt64Value::UnsafeArenaSwap(UInt64Value* other) {
-  if (other == this) return;
-  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
-  InternalSwap(other);
-}
 void UInt64Value::InternalSwap(UInt64Value* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);
@@ -1455,10 +1363,6 @@ class Int32Value::_Internal {
  public:
 };
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const int Int32Value::kValueFieldNumber;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 Int32Value::Int32Value()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr) {
   SharedCtor();
@@ -1704,25 +1608,6 @@ bool Int32Value::IsInitialized() const {
   return true;
 }
 
-void Int32Value::Swap(Int32Value* other) {
-  if (other == this) return;
-  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
-    InternalSwap(other);
-  } else {
-    Int32Value* temp = New(GetArenaNoVirtual());
-    temp->MergeFrom(*other);
-    other->CopyFrom(*this);
-    InternalSwap(temp);
-    if (GetArenaNoVirtual() == nullptr) {
-      delete temp;
-    }
-  }
-}
-void Int32Value::UnsafeArenaSwap(Int32Value* other) {
-  if (other == this) return;
-  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
-  InternalSwap(other);
-}
 void Int32Value::InternalSwap(Int32Value* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);
@@ -1742,10 +1627,6 @@ class UInt32Value::_Internal {
  public:
 };
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const int UInt32Value::kValueFieldNumber;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 UInt32Value::UInt32Value()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr) {
   SharedCtor();
@@ -1991,25 +1872,6 @@ bool UInt32Value::IsInitialized() const {
   return true;
 }
 
-void UInt32Value::Swap(UInt32Value* other) {
-  if (other == this) return;
-  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
-    InternalSwap(other);
-  } else {
-    UInt32Value* temp = New(GetArenaNoVirtual());
-    temp->MergeFrom(*other);
-    other->CopyFrom(*this);
-    InternalSwap(temp);
-    if (GetArenaNoVirtual() == nullptr) {
-      delete temp;
-    }
-  }
-}
-void UInt32Value::UnsafeArenaSwap(UInt32Value* other) {
-  if (other == this) return;
-  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
-  InternalSwap(other);
-}
 void UInt32Value::InternalSwap(UInt32Value* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);
@@ -2029,10 +1891,6 @@ class BoolValue::_Internal {
  public:
 };
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const int BoolValue::kValueFieldNumber;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 BoolValue::BoolValue()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr) {
   SharedCtor();
@@ -2276,25 +2134,6 @@ bool BoolValue::IsInitialized() const {
   return true;
 }
 
-void BoolValue::Swap(BoolValue* other) {
-  if (other == this) return;
-  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
-    InternalSwap(other);
-  } else {
-    BoolValue* temp = New(GetArenaNoVirtual());
-    temp->MergeFrom(*other);
-    other->CopyFrom(*this);
-    InternalSwap(temp);
-    if (GetArenaNoVirtual() == nullptr) {
-      delete temp;
-    }
-  }
-}
-void BoolValue::UnsafeArenaSwap(BoolValue* other) {
-  if (other == this) return;
-  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
-  InternalSwap(other);
-}
 void BoolValue::InternalSwap(BoolValue* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);
@@ -2314,10 +2153,6 @@ class StringValue::_Internal {
  public:
 };
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const int StringValue::kValueFieldNumber;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 StringValue::StringValue()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr) {
   SharedCtor();
@@ -2582,25 +2417,6 @@ bool StringValue::IsInitialized() const {
   return true;
 }
 
-void StringValue::Swap(StringValue* other) {
-  if (other == this) return;
-  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
-    InternalSwap(other);
-  } else {
-    StringValue* temp = New(GetArenaNoVirtual());
-    temp->MergeFrom(*other);
-    other->CopyFrom(*this);
-    InternalSwap(temp);
-    if (GetArenaNoVirtual() == nullptr) {
-      delete temp;
-    }
-  }
-}
-void StringValue::UnsafeArenaSwap(StringValue* other) {
-  if (other == this) return;
-  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
-  InternalSwap(other);
-}
 void StringValue::InternalSwap(StringValue* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);
@@ -2621,10 +2437,6 @@ class BytesValue::_Internal {
  public:
 };
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const int BytesValue::kValueFieldNumber;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
-
 BytesValue::BytesValue()
   : ::PROTOBUF_NAMESPACE_ID::Message(), _internal_metadata_(nullptr) {
   SharedCtor();
@@ -2877,25 +2689,6 @@ bool BytesValue::IsInitialized() const {
   return true;
 }
 
-void BytesValue::Swap(BytesValue* other) {
-  if (other == this) return;
-  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
-    InternalSwap(other);
-  } else {
-    BytesValue* temp = New(GetArenaNoVirtual());
-    temp->MergeFrom(*other);
-    other->CopyFrom(*this);
-    InternalSwap(temp);
-    if (GetArenaNoVirtual() == nullptr) {
-      delete temp;
-    }
-  }
-}
-void BytesValue::UnsafeArenaSwap(BytesValue* other) {
-  if (other == this) return;
-  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
-  InternalSwap(other);
-}
 void BytesValue::InternalSwap(BytesValue* other) {
   using std::swap;
   _internal_metadata_.Swap(&other->_internal_metadata_);

+ 144 - 27
src/google/protobuf/wrappers.pb.h

@@ -148,11 +148,22 @@ class PROTOBUF_EXPORT DoubleValue :
   static constexpr int kIndexInFileMessages =
     0;
 
-  void UnsafeArenaSwap(DoubleValue* other);
-  void Swap(DoubleValue* other);
   friend void swap(DoubleValue& a, DoubleValue& b) {
     a.Swap(&b);
   }
+  inline void Swap(DoubleValue* other) {
+    if (other == this) return;
+    if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(DoubleValue* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 
@@ -219,9 +230,11 @@ class PROTOBUF_EXPORT DoubleValue :
 
   // accessors -------------------------------------------------------
 
+  enum : int {
+    kValueFieldNumber = 1,
+  };
   // double value = 1;
   void clear_value();
-  static const int kValueFieldNumber = 1;
   double value() const;
   void set_value(double value);
 
@@ -289,11 +302,22 @@ class PROTOBUF_EXPORT FloatValue :
   static constexpr int kIndexInFileMessages =
     1;
 
-  void UnsafeArenaSwap(FloatValue* other);
-  void Swap(FloatValue* other);
   friend void swap(FloatValue& a, FloatValue& b) {
     a.Swap(&b);
   }
+  inline void Swap(FloatValue* other) {
+    if (other == this) return;
+    if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(FloatValue* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 
@@ -360,9 +384,11 @@ class PROTOBUF_EXPORT FloatValue :
 
   // accessors -------------------------------------------------------
 
+  enum : int {
+    kValueFieldNumber = 1,
+  };
   // float value = 1;
   void clear_value();
-  static const int kValueFieldNumber = 1;
   float value() const;
   void set_value(float value);
 
@@ -430,11 +456,22 @@ class PROTOBUF_EXPORT Int64Value :
   static constexpr int kIndexInFileMessages =
     2;
 
-  void UnsafeArenaSwap(Int64Value* other);
-  void Swap(Int64Value* other);
   friend void swap(Int64Value& a, Int64Value& b) {
     a.Swap(&b);
   }
+  inline void Swap(Int64Value* other) {
+    if (other == this) return;
+    if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Int64Value* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 
@@ -501,9 +538,11 @@ class PROTOBUF_EXPORT Int64Value :
 
   // accessors -------------------------------------------------------
 
+  enum : int {
+    kValueFieldNumber = 1,
+  };
   // int64 value = 1;
   void clear_value();
-  static const int kValueFieldNumber = 1;
   ::PROTOBUF_NAMESPACE_ID::int64 value() const;
   void set_value(::PROTOBUF_NAMESPACE_ID::int64 value);
 
@@ -571,11 +610,22 @@ class PROTOBUF_EXPORT UInt64Value :
   static constexpr int kIndexInFileMessages =
     3;
 
-  void UnsafeArenaSwap(UInt64Value* other);
-  void Swap(UInt64Value* other);
   friend void swap(UInt64Value& a, UInt64Value& b) {
     a.Swap(&b);
   }
+  inline void Swap(UInt64Value* other) {
+    if (other == this) return;
+    if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(UInt64Value* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 
@@ -642,9 +692,11 @@ class PROTOBUF_EXPORT UInt64Value :
 
   // accessors -------------------------------------------------------
 
+  enum : int {
+    kValueFieldNumber = 1,
+  };
   // uint64 value = 1;
   void clear_value();
-  static const int kValueFieldNumber = 1;
   ::PROTOBUF_NAMESPACE_ID::uint64 value() const;
   void set_value(::PROTOBUF_NAMESPACE_ID::uint64 value);
 
@@ -712,11 +764,22 @@ class PROTOBUF_EXPORT Int32Value :
   static constexpr int kIndexInFileMessages =
     4;
 
-  void UnsafeArenaSwap(Int32Value* other);
-  void Swap(Int32Value* other);
   friend void swap(Int32Value& a, Int32Value& b) {
     a.Swap(&b);
   }
+  inline void Swap(Int32Value* other) {
+    if (other == this) return;
+    if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(Int32Value* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 
@@ -783,9 +846,11 @@ class PROTOBUF_EXPORT Int32Value :
 
   // accessors -------------------------------------------------------
 
+  enum : int {
+    kValueFieldNumber = 1,
+  };
   // int32 value = 1;
   void clear_value();
-  static const int kValueFieldNumber = 1;
   ::PROTOBUF_NAMESPACE_ID::int32 value() const;
   void set_value(::PROTOBUF_NAMESPACE_ID::int32 value);
 
@@ -853,11 +918,22 @@ class PROTOBUF_EXPORT UInt32Value :
   static constexpr int kIndexInFileMessages =
     5;
 
-  void UnsafeArenaSwap(UInt32Value* other);
-  void Swap(UInt32Value* other);
   friend void swap(UInt32Value& a, UInt32Value& b) {
     a.Swap(&b);
   }
+  inline void Swap(UInt32Value* other) {
+    if (other == this) return;
+    if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(UInt32Value* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 
@@ -924,9 +1000,11 @@ class PROTOBUF_EXPORT UInt32Value :
 
   // accessors -------------------------------------------------------
 
+  enum : int {
+    kValueFieldNumber = 1,
+  };
   // uint32 value = 1;
   void clear_value();
-  static const int kValueFieldNumber = 1;
   ::PROTOBUF_NAMESPACE_ID::uint32 value() const;
   void set_value(::PROTOBUF_NAMESPACE_ID::uint32 value);
 
@@ -994,11 +1072,22 @@ class PROTOBUF_EXPORT BoolValue :
   static constexpr int kIndexInFileMessages =
     6;
 
-  void UnsafeArenaSwap(BoolValue* other);
-  void Swap(BoolValue* other);
   friend void swap(BoolValue& a, BoolValue& b) {
     a.Swap(&b);
   }
+  inline void Swap(BoolValue* other) {
+    if (other == this) return;
+    if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(BoolValue* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 
@@ -1065,9 +1154,11 @@ class PROTOBUF_EXPORT BoolValue :
 
   // accessors -------------------------------------------------------
 
+  enum : int {
+    kValueFieldNumber = 1,
+  };
   // bool value = 1;
   void clear_value();
-  static const int kValueFieldNumber = 1;
   bool value() const;
   void set_value(bool value);
 
@@ -1135,11 +1226,22 @@ class PROTOBUF_EXPORT StringValue :
   static constexpr int kIndexInFileMessages =
     7;
 
-  void UnsafeArenaSwap(StringValue* other);
-  void Swap(StringValue* other);
   friend void swap(StringValue& a, StringValue& b) {
     a.Swap(&b);
   }
+  inline void Swap(StringValue* other) {
+    if (other == this) return;
+    if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(StringValue* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 
@@ -1206,9 +1308,11 @@ class PROTOBUF_EXPORT StringValue :
 
   // accessors -------------------------------------------------------
 
+  enum : int {
+    kValueFieldNumber = 1,
+  };
   // string value = 1;
   void clear_value();
-  static const int kValueFieldNumber = 1;
   const std::string& value() const;
   void set_value(const std::string& value);
   void set_value(std::string&& value);
@@ -1291,11 +1395,22 @@ class PROTOBUF_EXPORT BytesValue :
   static constexpr int kIndexInFileMessages =
     8;
 
-  void UnsafeArenaSwap(BytesValue* other);
-  void Swap(BytesValue* other);
   friend void swap(BytesValue& a, BytesValue& b) {
     a.Swap(&b);
   }
+  inline void Swap(BytesValue* other) {
+    if (other == this) return;
+    if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+      InternalSwap(other);
+    } else {
+      ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
+    }
+  }
+  void UnsafeArenaSwap(BytesValue* other) {
+    if (other == this) return;
+    GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+    InternalSwap(other);
+  }
 
   // implements Message ----------------------------------------------
 
@@ -1362,9 +1477,11 @@ class PROTOBUF_EXPORT BytesValue :
 
   // accessors -------------------------------------------------------
 
+  enum : int {
+    kValueFieldNumber = 1,
+  };
   // bytes value = 1;
   void clear_value();
-  static const int kValueFieldNumber = 1;
   const std::string& value() const;
   void set_value(const std::string& value);
   void set_value(std::string&& value);

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