Commit cbe25059 authored by Jon Skeet's avatar Jon Skeet Committed by Jon Skeet

Fix merging with message-valued oneof

If messages A and B have the same oneof case, which is a message
type, and we merge B into A, those sub-messages should be merged.

Fixes #3200.

Note that I haven't regenerated all the code, as some of the protos
have been changed, breaking generation.
parent 6dd82243
......@@ -124,3 +124,18 @@ message TestJsonName {
string description = 2 [json_name = "desc"];
string guid = 3 [json_name = "exid"];
}
// Issue 3200: When merging two messages which use the same
// oneof case, which is itself a message type, the submessages should
// be merged.
message OneofMerging {
message Nested {
int32 x = 1;
int32 y = 2;
}
oneof value {
string text = 1;
Nested nested = 2;
}
}
\ No newline at end of file
......@@ -33,7 +33,7 @@
using Google.Protobuf.Reflection;
using UnitTest.Issues.TestProtos;
using NUnit.Framework;
using static UnitTest.Issues.TestProtos.OneofMerging.Types;
namespace Google.Protobuf
{
......@@ -78,5 +78,17 @@ namespace Google.Protobuf
Assert.AreEqual("{ \"name\": \"test\", \"desc\": \"test2\", \"exid\": \"test3\" }",
JsonFormatter.Default.Format(message));
}
[Test]
public void OneofMerging()
{
var message1 = new OneofMerging { Nested = new Nested { X = 10 } };
var message2 = new OneofMerging { Nested = new Nested { Y = 20 } };
var expected = new OneofMerging { Nested = new Nested { X = 10, Y = 20 } };
var merged = message1.Clone();
merged.MergeFrom(message2);
Assert.AreEqual(expected, merged);
}
}
}
......@@ -466,10 +466,16 @@ namespace Google.Protobuf.WellKnownTypes {
BoolValue = other.BoolValue;
break;
case KindOneofCase.StructValue:
StructValue = other.StructValue;
if (StructValue == null) {
StructValue = new global::Google.Protobuf.WellKnownTypes.Struct();
}
StructValue.MergeFrom(other.StructValue);
break;
case KindOneofCase.ListValue:
ListValue = other.ListValue;
if (ListValue == null) {
ListValue = new global::Google.Protobuf.WellKnownTypes.ListValue();
}
ListValue.MergeFrom(other.ListValue);
break;
}
......
......@@ -89,6 +89,10 @@ EnumOneofFieldGenerator::EnumOneofFieldGenerator(
EnumOneofFieldGenerator::~EnumOneofFieldGenerator() {
}
void EnumOneofFieldGenerator::GenerateMergingCode(io::Printer* printer) {
printer->Print(variables_, "$property_name$ = other.$property_name$;\n");
}
void EnumOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
// TODO(jonskeet): What about if we read the default value?
printer->Print(
......
......@@ -64,6 +64,7 @@ class EnumOneofFieldGenerator : public PrimitiveOneofFieldGenerator {
const Options *options);
~EnumOneofFieldGenerator();
virtual void GenerateMergingCode(io::Printer* printer);
virtual void GenerateParsingCode(io::Printer* printer);
virtual void GenerateSerializationCode(io::Printer* printer);
virtual void GenerateSerializedSizeCode(io::Printer* printer);
......
......@@ -463,9 +463,12 @@ void MessageGenerator::GenerateMergingMethods(io::Printer* printer) {
vars["field_property_name"] = GetPropertyName(field);
printer->Print(
vars,
"case $property_name$OneofCase.$field_property_name$:\n"
" $field_property_name$ = other.$field_property_name$;\n"
" break;\n");
"case $property_name$OneofCase.$field_property_name$:\n");
printer->Indent();
scoped_ptr<FieldGeneratorBase> generator(CreateFieldGeneratorInternal(field));
generator->GenerateMergingCode(printer);
printer->Print("break;\n");
printer->Outdent();
}
printer->Outdent();
printer->Print("}\n\n");
......
......@@ -171,6 +171,14 @@ void MessageOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
"}\n");
}
void MessageOneofFieldGenerator::GenerateMergingCode(io::Printer* printer) {
printer->Print(variables_,
"if ($property_name$ == null) {\n"
" $property_name$ = new $type_name$();\n"
"}\n"
"$property_name$.MergeFrom(other.$property_name$);\n");
}
void MessageOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
// TODO(jonskeet): We may be able to do better than this
printer->Print(
......
......@@ -74,6 +74,7 @@ class MessageOneofFieldGenerator : public MessageFieldGenerator {
virtual void GenerateCloningCode(io::Printer* printer);
virtual void GenerateMembers(io::Printer* printer);
virtual void GenerateMergingCode(io::Printer* printer);
virtual void WriteToString(io::Printer* printer);
virtual void GenerateParsingCode(io::Printer* printer);
......
......@@ -196,6 +196,10 @@ void PrimitiveOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
"}\n");
}
void PrimitiveOneofFieldGenerator::GenerateMergingCode(io::Printer* printer) {
printer->Print(variables_, "$property_name$ = other.$property_name$;\n");
}
void PrimitiveOneofFieldGenerator::WriteToString(io::Printer* printer) {
printer->Print(variables_,
"PrintField(\"$descriptor_name$\", $has_property_check$, $oneof_name$_, writer);\n");
......
......@@ -78,6 +78,7 @@ class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator {
virtual void GenerateCloningCode(io::Printer* printer);
virtual void GenerateMembers(io::Printer* printer);
virtual void GenerateMergingCode(io::Printer* printer);
virtual void WriteToString(io::Printer* printer);
virtual void GenerateParsingCode(io::Printer* printer);
......
......@@ -181,6 +181,10 @@ void WrapperOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
"}\n");
}
void WrapperOneofFieldGenerator::GenerateMergingCode(io::Printer* printer) {
printer->Print(variables_, "$property_name$ = other.$property_name$;\n");
}
void WrapperOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
printer->Print(
variables_,
......
......@@ -75,6 +75,7 @@ class WrapperOneofFieldGenerator : public WrapperFieldGenerator {
~WrapperOneofFieldGenerator();
virtual void GenerateMembers(io::Printer* printer);
virtual void GenerateMergingCode(io::Printer* printer);
virtual void GenerateParsingCode(io::Printer* printer);
virtual void GenerateSerializationCode(io::Printer* printer);
virtual void GenerateSerializedSizeCode(io::Printer* printer);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment