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 { ...@@ -124,3 +124,18 @@ message TestJsonName {
string description = 2 [json_name = "desc"]; string description = 2 [json_name = "desc"];
string guid = 3 [json_name = "exid"]; 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 @@ ...@@ -33,7 +33,7 @@
using Google.Protobuf.Reflection; using Google.Protobuf.Reflection;
using UnitTest.Issues.TestProtos; using UnitTest.Issues.TestProtos;
using NUnit.Framework; using NUnit.Framework;
using static UnitTest.Issues.TestProtos.OneofMerging.Types;
namespace Google.Protobuf namespace Google.Protobuf
{ {
...@@ -78,5 +78,17 @@ namespace Google.Protobuf ...@@ -78,5 +78,17 @@ namespace Google.Protobuf
Assert.AreEqual("{ \"name\": \"test\", \"desc\": \"test2\", \"exid\": \"test3\" }", Assert.AreEqual("{ \"name\": \"test\", \"desc\": \"test2\", \"exid\": \"test3\" }",
JsonFormatter.Default.Format(message)); 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 { ...@@ -466,10 +466,16 @@ namespace Google.Protobuf.WellKnownTypes {
BoolValue = other.BoolValue; BoolValue = other.BoolValue;
break; break;
case KindOneofCase.StructValue: case KindOneofCase.StructValue:
StructValue = other.StructValue; if (StructValue == null) {
StructValue = new global::Google.Protobuf.WellKnownTypes.Struct();
}
StructValue.MergeFrom(other.StructValue);
break; break;
case KindOneofCase.ListValue: case KindOneofCase.ListValue:
ListValue = other.ListValue; if (ListValue == null) {
ListValue = new global::Google.Protobuf.WellKnownTypes.ListValue();
}
ListValue.MergeFrom(other.ListValue);
break; break;
} }
......
...@@ -89,6 +89,10 @@ EnumOneofFieldGenerator::EnumOneofFieldGenerator( ...@@ -89,6 +89,10 @@ EnumOneofFieldGenerator::EnumOneofFieldGenerator(
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) { void EnumOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
// TODO(jonskeet): What about if we read the default value? // TODO(jonskeet): What about if we read the default value?
printer->Print( printer->Print(
......
...@@ -64,6 +64,7 @@ class EnumOneofFieldGenerator : public PrimitiveOneofFieldGenerator { ...@@ -64,6 +64,7 @@ class EnumOneofFieldGenerator : public PrimitiveOneofFieldGenerator {
const Options *options); const Options *options);
~EnumOneofFieldGenerator(); ~EnumOneofFieldGenerator();
virtual void GenerateMergingCode(io::Printer* printer);
virtual void GenerateParsingCode(io::Printer* printer); virtual void GenerateParsingCode(io::Printer* printer);
virtual void GenerateSerializationCode(io::Printer* printer); virtual void GenerateSerializationCode(io::Printer* printer);
virtual void GenerateSerializedSizeCode(io::Printer* printer); virtual void GenerateSerializedSizeCode(io::Printer* printer);
......
...@@ -463,9 +463,12 @@ void MessageGenerator::GenerateMergingMethods(io::Printer* printer) { ...@@ -463,9 +463,12 @@ void MessageGenerator::GenerateMergingMethods(io::Printer* printer) {
vars["field_property_name"] = GetPropertyName(field); vars["field_property_name"] = GetPropertyName(field);
printer->Print( printer->Print(
vars, vars,
"case $property_name$OneofCase.$field_property_name$:\n" "case $property_name$OneofCase.$field_property_name$:\n");
" $field_property_name$ = other.$field_property_name$;\n" printer->Indent();
" break;\n"); scoped_ptr<FieldGeneratorBase> generator(CreateFieldGeneratorInternal(field));
generator->GenerateMergingCode(printer);
printer->Print("break;\n");
printer->Outdent();
} }
printer->Outdent(); printer->Outdent();
printer->Print("}\n\n"); printer->Print("}\n\n");
......
...@@ -171,6 +171,14 @@ void MessageOneofFieldGenerator::GenerateMembers(io::Printer* printer) { ...@@ -171,6 +171,14 @@ void MessageOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
"}\n"); "}\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) { void MessageOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
// TODO(jonskeet): We may be able to do better than this // TODO(jonskeet): We may be able to do better than this
printer->Print( printer->Print(
......
...@@ -74,6 +74,7 @@ class MessageOneofFieldGenerator : public MessageFieldGenerator { ...@@ -74,6 +74,7 @@ class MessageOneofFieldGenerator : public MessageFieldGenerator {
virtual void GenerateCloningCode(io::Printer* printer); virtual void GenerateCloningCode(io::Printer* printer);
virtual void GenerateMembers(io::Printer* printer); virtual void GenerateMembers(io::Printer* printer);
virtual void GenerateMergingCode(io::Printer* printer);
virtual void WriteToString(io::Printer* printer); virtual void WriteToString(io::Printer* printer);
virtual void GenerateParsingCode(io::Printer* printer); virtual void GenerateParsingCode(io::Printer* printer);
......
...@@ -196,6 +196,10 @@ void PrimitiveOneofFieldGenerator::GenerateMembers(io::Printer* printer) { ...@@ -196,6 +196,10 @@ void PrimitiveOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
"}\n"); "}\n");
} }
void PrimitiveOneofFieldGenerator::GenerateMergingCode(io::Printer* printer) {
printer->Print(variables_, "$property_name$ = other.$property_name$;\n");
}
void PrimitiveOneofFieldGenerator::WriteToString(io::Printer* printer) { void PrimitiveOneofFieldGenerator::WriteToString(io::Printer* printer) {
printer->Print(variables_, printer->Print(variables_,
"PrintField(\"$descriptor_name$\", $has_property_check$, $oneof_name$_, writer);\n"); "PrintField(\"$descriptor_name$\", $has_property_check$, $oneof_name$_, writer);\n");
......
...@@ -78,6 +78,7 @@ class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator { ...@@ -78,6 +78,7 @@ class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator {
virtual void GenerateCloningCode(io::Printer* printer); virtual void GenerateCloningCode(io::Printer* printer);
virtual void GenerateMembers(io::Printer* printer); virtual void GenerateMembers(io::Printer* printer);
virtual void GenerateMergingCode(io::Printer* printer);
virtual void WriteToString(io::Printer* printer); virtual void WriteToString(io::Printer* printer);
virtual void GenerateParsingCode(io::Printer* printer); virtual void GenerateParsingCode(io::Printer* printer);
......
...@@ -181,6 +181,10 @@ void WrapperOneofFieldGenerator::GenerateMembers(io::Printer* printer) { ...@@ -181,6 +181,10 @@ void WrapperOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
"}\n"); "}\n");
} }
void WrapperOneofFieldGenerator::GenerateMergingCode(io::Printer* printer) {
printer->Print(variables_, "$property_name$ = other.$property_name$;\n");
}
void WrapperOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) { void WrapperOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
printer->Print( printer->Print(
variables_, variables_,
......
...@@ -75,6 +75,7 @@ class WrapperOneofFieldGenerator : public WrapperFieldGenerator { ...@@ -75,6 +75,7 @@ class WrapperOneofFieldGenerator : public WrapperFieldGenerator {
~WrapperOneofFieldGenerator(); ~WrapperOneofFieldGenerator();
virtual void GenerateMembers(io::Printer* printer); virtual void GenerateMembers(io::Printer* printer);
virtual void GenerateMergingCode(io::Printer* printer);
virtual void GenerateParsingCode(io::Printer* printer); virtual void GenerateParsingCode(io::Printer* printer);
virtual void GenerateSerializationCode(io::Printer* printer); virtual void GenerateSerializationCode(io::Printer* printer);
virtual void GenerateSerializedSizeCode(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